我尝试在荔枝派中读取gps的信息,我用的gps模块是NEO-6M。

以下是我的程序

#include <stdio.h>
#include <stdlib.h>
#include <common.h>

char GPS_Data_Temp[256]= {0}; //送去解析的GPS数据
gps_process_data gps;//gps数据结构体
#pragma pack (4)
unsigned char outbuf[50];//用于规范打印的buf
#pragma pack ()
int s,bufflen,uartfd=-1;
int gpsbuflen=0;//避免线程间错误



static sem_t semA;//设置信号量

void GPS_Show()
{
//                float tp;
//                tp=gps.longitude;
//                sprintf((char *)outbuf,"Longitude:%.5f %1c \r\n",tp/=100000,gps.ewhemi);    //得到经度字符串
//
//                tp=gps.latitude;
//                sprintf((char *)outbuf,"Latitude:%.5f %1c \r\n",tp/=100000,gps.nshemi);        //得到纬度字符串
//
//                sprintf((char *)outbuf,"Valid satellite:%02d\r\n",gps.posslnum);             //用于定位的卫星数
//
//                sprintf((char *)outbuf,"Visible satellite:%02d\r\n",gps.svnum%100);             //可见卫星数
}

static void *threadRead(void *arg)//串口读取线程
{
    int i,Bufcnt=0;//设置一个计数器
    char RecvBuff[33];//接受数据缓存,因为一次最多只能读到32个字节
    char Storebuf[256]={0};//数据暂存,用于分割线程之间的联系
    while(1)
    {
        bufflen=UART_Recv(uartfd,RecvBuff,33);
        if(bufflen>0)
        {
            if((Bufcnt+bufflen)<255)
            {
                for(i=0; i<bufflen; i++)
                {
                    Storebuf[i+Bufcnt]=RecvBuff[i];//赋值
                }
                Bufcnt+=bufflen;//用于确定下一次赋值的偏移量

            }
            else //发出条件信号
            {
                memcpy(GPS_Data_Temp,Storebuf,Bufcnt);//数据拷贝,再清零
                memset(Storebuf,0,256);
                gpsbuflen=Bufcnt;
                Bufcnt=0;
                for(i=0; i<bufflen; i++)
                {
                    Storebuf[i+Bufcnt]=RecvBuff[i];//把剩下的数据重新赋值到buf
                }
                Bufcnt+=bufflen;//用于确定下一次赋值的偏移量
                sem_post(&semA);
            }
        }

    }
    return NULL;
}

static void *threadSend(void *arg)
{
    int i;
    while(1)
    {
        sem_wait(&semA);//等待信号量
        for(i=0;i<gpsbuflen;i++)
        {
            printf("%c",GPS_Data_Temp[i]);//输出数据,并将计数器清零
        }
        memset(GPS_Data_Temp,0,256);
        gpsbuflen=0;
    }

    return NULL;
}


int main()
{

    pthread_t Rec,Snd;
    uartfd=UART_Open(uartfd,UART_PORT2);//打开串口1
    if(uartfd==0)
        errExit("open");
    if(UART_Init(uartfd,9600,0,8,1,'N')==0)//串口初始化
        errExit("set uart");

    sem_init(&semA,0,0); //信号量初始化

    s=pthread_create(&Rec,NULL,threadRead,"read");//线程初始化
    if(s!=0)
        errExitEN(s,"pthread_create");

    s=pthread_create(&Snd,NULL,threadSend,"Send");//线程初始化
    if(s!=0)
        errExitEN(s,"pthread_create");

    //死循环
    while(1)
    {

    }

    s=pthread_join(Rec,NULL);
    if(s!=0)
        errExitEN(s,"pthread_join");


    s=pthread_join(Snd,NULL);
    if(s!=0)
        errExitEN(s,"pthread_join");

    sem_destroy(&semA);

    exit(EXIT_SUCCESS);
}

我现在就是开了两个线程,一个线程用于读取串口数据,一个线程用于解析gps数据,当然我目前只是把数据printf出来。

遇到几个问题,线程之间的数据的传递,是一个很难解决的问题,主要在于我没有找到合适的方法。

如果都使用全局变量,那么两个线程,姑且称读取线程为生产者,解析线程为消费者。在生产和消费的过程中,就需要两个线程进行同步。

线程同步,我想到两个方法,一个用互斥锁+条件变量,一个是用信号量。

开始我用第一个方法,但是写的时候又发现有个问题,我一次性只能读取32字节的数据,我需要多读几个字节才可以送去解析。这个时候,就需要分情况考虑,

那么互斥锁加条件变量的方法就显得非常麻烦。

目前我用第二个方法,当数据读满的时候,发出信号量来提醒消费者进行消费。但是这个时候问题又来了,现在我没有互斥锁,无法避免消费者去使用全局变量的时候产生错误。所以我就讲生产者中的局部变量赋值到全局变量中,让消费者独自使用。

总的来说这两个方法都很不爽,我在想有没有可以直接在线程中等待,并且传递数据的方法。类似freeRTOS中的信号量+消息队列。

我测试的数据如下

v3s Linux中读取GPS数据。

接收到的如下

v3s Linux中读取GPS数据。