之前编写了一个读取GPS内容的代码,现将之贴出来。此代码中涉及到串口初始化、串口操作的打开、关闭、读写,还涉及到GPS相关协议的解析,如接收到的GPS数据如何处理,如何发送数据到GPS模块等。协议采用的是SIM68VB NMEA协议。
1、 串口初始化代码如下:
此函数为设置串口 属性如波特率、数据位、校验位、停止位,此函数将串口设置为非阻塞,在读串口时可采用I/O多路复用的机制。
例:configs ="115200,8,1,N" 115200代表波特率,8数据位,1停止位,N无校验
int SetNolockComCfg(int fd, char *configs)
{
int uBaudRate, databits, stopbits;
char parity;
char temp[32];
char *p1 = NULL, *p2 = NULL;
int n = 0;
unsigned int flag = 0;
unsigned short Speed;
int stats;
struct termios options;
/* clear struct for new port settings */
bzero(&options, sizeof (struct termios));
//波特率
p1 = configs;
p2 = strchr(p1, ',');
n = p2 - p1;
if (n) {
strncpy(temp, p1, n);
temp[n] = '';
uBaudRate = atoi(temp);
}
else
uBaudRate = COM_BAUDDEF;
//数据位
p1 = strchr(p2 + 1, ',');
n = p1 - (p2 + 1);
if (n) {
strncpy(temp, p2 + 1, n);
temp[n] = '';
databits = atoi(temp);
}
else
databits = COM_DABITSDEF;
// 停止位
p2 = strchr(p1 + 1, ',');
n = p2 - (p1 + 1);
if (n) {
strncpy(temp, p1 + 1, n);
temp[n] = '';
stopbits = atoi(temp);
}
else
stopbits = COM_STBITSDEF;
//校验位
if (p2 + 1 != NULL) {
strcpy(temp, p2 + 1);
parity = temp[0];
}
else {
parity = COM_PARITYDEF;
}
//设置波特率
switch (uBaudRate) {
case 110:
Speed = B110;
break;
case 300:
Speed = B300;
break;
case 600:
Speed = B600;
break;
case 1200:
Speed = B1200;
break;
case 2400:
Speed = B2400;
break;
case 4800:
Speed = B4800;
break;
case 9600:
Speed = B9600;
break;
case 19200:
Speed = B19200;
break;
case 38400:
Speed = B38400;
break;
case 57600:
Speed = B57600;
break;
case 115200:
Speed = B115200;
break;
case 230400:
Speed = B230400;
break;
case 460800:
Speed = B460800;
break;
case 921600:
Speed = B921600;
break;
default:
fprintf(stderr, "Unsupported data sizen");
return -1;
}
flag |= Speed;
//设置数据位
switch (databits) {
case 5:
flag |= CS5;
break;
case 6:
flag |= CS6;
break;
case 7:
flag |= CS7;
break;
case 8:
flag |= CS8;
break;
default:
fprintf(stderr, "Unsupported data sizen");
return -1;
}
//设置停止位
switch (stopbits) {
case 1:
break;
case 2:
flag |= CSTOPB;
break;
default:
fprintf(stderr, "Unsupported stop bitsn");
return -1;
}
//设置奇偶校验位
switch (parity) {
case 'n':
case 'N':
options.c_iflag = IGNPAR;
break;
case 'e':
case 'E':
flag |= PARENB;
options.c_iflag = 0;
break;
case 'o':
case 'O':
flag |= PARENB | PARODD;
options.c_iflag = 0;
break;
case 's':
case 'S':
flag |= PARENB | CMSPAR;
options.c_iflag = 0;
break;
case 'm':
case 'M':
flag |= PARENB | PARODD | CMSPAR;
options.c_iflag = 0;
break;
default:
fprintf(stderr, "Unsupported parityn");
return -1;
}
options.c_cflag = flag | CREAD | CLOCAL;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_cc[VINTR] = 0;
options.c_cc[VQUIT] = 0;
options.c_cc[VERASE] = 0;
options.c_cc[VKILL] = 0;
options.c_cc[VEOF] = 4;
// 100MS 串口等待接收(2S)
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
options.c_cc[VSWTC] = 0;
options.c_cc[VSTART] = 0;
options.c_cc[VSTOP] = 0;
options.c_cc[VSUSP] = 0;
options.c_cc[VEOL] = 0;
options.c_cc[VREPRINT] = 0;
options.c_cc[VDISCARD] = 0;
options.c_cc[VWERASE] = 0;
options.c_cc[VLNEXT] = 0;
options.c_cc[VEOL2] = 0;
//刷新输入输出缓冲
tcflush(fd, TCIOFLUSH);
//把设置真正写到串口中去
stats = tcsetattr(fd, TCSANOW, &options);
if (stats != 0) {
perror("tcsetattr fd1");
return -1;
}
return 0;
}
2、GPS相关的数据定义在一个结构体中,如下
struct stGPS {
//位置信息有效性
char loca_state;
//东西经
char we;
//经度位置
unsigned int Longitude;
//南北纬
char ns;
//纬度位置
unsigned int Latitude;
//海拔高度
unsigned int Altitude;
//距1970-1-1 0:0:0 的秒数
unsigned int Time;
};
3、获取GPS信息的函数如下
相关宏:
#define GPGGA "$GPGGA" //GPS定位系统输出字符串的头部
#define GPRMC "$GPRMC"
#define BDGGA "$BDGGA" //北斗定位系统输出字符串的头部
#define BDRMC "$BDRMC"
int GetBDGPSData(int bdgps_fd, struct stGPS *bdgps, int mode)
{
int ret;
char read_buf[512] = {0};
char *pGGA = NULL, *pRMC = NULL;
char gpstime[64] = {0};
char altitude[64] = {0};
char ns; //纬度标识
char we; //经度标识
char state; //状态标识
char ns_data[16] = {0}; //纬度
char we_data[16] = {0}; //经度
char date[16] = {0};
struct tm utc_time = {0};
int year;
int daytime;
int err_num;
int flag = 0;
char str1[10] = {0};
char str2[10] = {0};
switch (mode){
case BD_MODE:
memcpy(str1, BDGGA, sizeof(BDGGA));
memcpy(str2, BDRMC, sizeof(BDRMC));
break;
case GPS_MODE:
default:
memcpy(str1, GPGGA, sizeof(GPGGA));
memcpy(str2, GPRMC, sizeof(GPRMC));
break;
}
for(err_num=0; err_num<MAX_ERROR; err_num++){
delay(0, 100);
ret = read(bdgps_fd, read_buf, sizeof(read_buf));
pGGA = strstr(read_buf,str1); //在字符串中查找字符串
pRMC = strstr(read_buf,str2);
if((ret>150) && pGGA && pRMC){
flag = 1;
break;
}
}
if(!flag)
return -1;
printf("read num = %d nread_buf: %s n", ret, read_buf);
//根据需求我们需要采集到两次信息
sscanf(pGGA, "%[^r]", pGGA); //解析字符串
sscanf(pRMC, "%[^r]", pRMC);
//根据协议解析字符串
sscanf(pGGA, "%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%*[^,],%[^,]",altitude);
// 时间 状态 纬度 ns 经度 we
sscanf(pRMC, "%*[^,],%[^,],%c, %[^,],%c,%[^,],%c,%*[^,],%*[^,],%[^,]",
gpstime, &state , ns_data, &ns, we_data, &we, date);
year = atoi(date);
daytime = atoi(gpstime);
utc_time.tm_sec = daytime%100;
utc_time.tm_min = daytime%10000/100 ;
utc_time.tm_hour = daytime/10000;
utc_time.tm_mday = year/10000;
utc_time.tm_mon = year%10000/100;
utc_time.tm_year = year%100 + 2000;
bdgps->Longitude = atof(we_data) * 10000;
bdgps->Latitude = atof(ns_data) * 10000;
bdgps->loca_state = state;
bdgps->Altitude = atof(altitude) * 10000;
bdgps->ns = ns;
bdgps->we = we;
bdgps->Time = mktime(&utc_time);
return 0;
}
4、 main函数,采用select机制读取GPS串口的数据
int main()
{
int ret = 0;
fd_set readfs;
int bdgps_fd, maxfd;
int err_num = 0;
struct stGPS bdgps = {0};
struct timeval timeout={1, 0};
bdgps_fd = open("/dev/ttyS1", O_RDWR);
if(bdgps_fd < 0){
perror("open ttyS1");
return -1;
}
//设置为非阻塞
ret = SetNolockComCfg(bdgps_fd, CONFIG);
if(ret)
return -1;
while(1){
FD_ZERO(&readfs);
FD_SET(bdgps_fd, &readfs);
maxfd = bdgps_fd + 1;
ret = select(maxfd, &readfs, NULL, NULL, &timeout);
if(ret < 0){
perror("select"); //允许出错三次
err_num++;
if(err_num < MAX_ERROR)
continue;
else
break;
}
err_num = 0;
if(FD_ISSET(bdgps_fd, &readfs)){
ret = GetBDGPSData(bdgps_fd, &bdgps, GPS_MODE);
if(ret)
continue;
printf("bdgps->state: %c n",bdgps.loca_state);
printf("bdgps->we: %c n",bdgps.we);
printf("bdgps->Longitude:%d n",bdgps.Longitude);
printf("bdgps->ns: %c n",bdgps.ns);
printf("bdgps->Latitude: %d n",bdgps.Latitude);
printf("bdgps->Altitude: %d n",bdgps.Altitude);
printf("bdgps->Time: %d n",bdgps.Time);
}
usleep(50*1000);
}
close(bdgps_fd);
return 0;
}
至此,一个完整的GPS读取数据的程序已经完成,已经能够读取到相关的位置信息。
最后
以上就是任性大白最近收集整理的关于Linux 串口编程之GPS的全部内容,更多相关Linux内容请搜索靠谱客的其他文章。
发表评论 取消回复