解析串口-接收完整数据帧

在linux下编写串口通讯程序,采用select监听串口的可读事件,一旦可读,调用read。但是我们会发现,read一次得到的数据通常不是完整的一个数据帧。
比如完整数据帧为

这里写图片描述

但是实际上需要read多次才能完全读到。

程序实际运行情况:

两次读完:

这里写图片描述

四次读完:

这里写图片描述

为了解决不能接收完整数据帧的问题,借鉴了网友的例子,并进行了一些改动:

现在的效果:

这里写图片描述

下面是程序代码:

#include "smartlight.h"

int portfd = -1;
void print_frame(const char *desc,uint8_t *buf,int size);
void getCompleteFrame(uint8_t *inBuf,int inCnt,uint8_t *outBuf,int *destCnt,int *readStatus);
void *monitor_serial_readable(void *arg);

int main(int argc,char *argv[])
{
    int nret;
    pthread_t wtid;
    /* open serial port */
    portfd = open_port();
    /* set serial port */
    set_opt(portfd,57600);

    nret = pthread_create(&wtid,NULL,monitor_serial_readable,NULL);
    if(nret != 0)
    {
        DEBUG_ERR(create thread failed);
        exit(-1);
    }
    nret = pthread_join(wtid,NULL);
    if(nret != 0)
    {
        DEBUG_ERR(join thread failed);
        exit(-1);
    }
    close(portfd);

    return 0;
}

void getCompleteFrame(uint8_t *inBuf,int inCnt,uint8_t *outBuf,int *destCnt,int *readStatus)
{
    int i;
    for(i=0; i<inCnt; i++)
    {
        if(inBuf[i] == 0x11 && inBuf[i+2] == 0x00 && inBuf[i+3] == 0x00)//header
        {
            outBuf[(*destCnt)++] = inBuf[i];
            *readStatus = 1;
            //print_frame("header",dest,dest_cnt);
            continue;
        }
        if(*readStatus == 1)//body
        {
            outBuf[(*destCnt)++] = inBuf[i];    
            //print_frame("body",dest,dest_cnt);
        }
        if(*destCnt == outBuf[1])//tail
        {
            print_frame("tail",outBuf,*destCnt);
            *readStatus = 0;
            *destCnt = 0;
            memset(outBuf,-1,sizeof(outBuf));
            memset(inBuf,0,sizeof(inBuf));
            continue;
        }
    }
}

void *monitor_serial_readable(void *arg)
{
    int rc,i,nread=0;
    fd_set rset;
    struct timeval tv;
    uint8_t buf[1024] = {0};
    uint8_t dest[1024]={0};
    int read_status = 0;
    int dest_cnt = 0;

    while(1)
    {
        FD_ZERO(&rset);
        FD_SET(portfd,&rset);

        tv.tv_sec = 5;
        tv.tv_usec = 0;

        rc = select(portfd+1,&rset,NULL,NULL,&tv);
        if(rc == -1)
        {
            DEBUG_ERR(select error in thread);
            continue;
        }
        if(rc == 0)
        {
            DEBUG_INFO(select timeout in thread);
            continue;
        }
        else
        {
            nread = read(portfd,buf,sizeof(buf));   
            if(nread == -1)
            {
                perror("read");
                usleep(100*1000);
                continue;
            }
            if(nread == 0)
            {
                printf("nread==0\n");
                usleep(100*1000);
                continue;
            }
            printf("nread = %d\n",nread);
            getCompleteFrame(buf,nread,dest,&dest_cnt,&read_status);
        }
    }//END_while
}

void print_frame(const char *desc,uint8_t *buf,int size)
{
    int i;

    printf(RED"[%s] [LEN=%d]"COLOR_END,desc,size);
    for(i=0; i<size; i++)
    {
        printf(BLUE"[%.2x]"COLOR_END,buf[i]);
    }
    printf("\n");
}
  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值