我是靠谱客的博主 任性大白,最近开发中收集的这篇文章主要介绍Linux 串口编程之GPS,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

    之前编写了一个读取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 串口编程之GPS所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部