arm-linux串口接收出错

在一帧数据的接收中,一帧数据,会被分两次接收,如下:第一次接收一部分,第二次接收一部分;
recv  data   from downline:   0x66   0x17   0x0   0xc1   0x0   0x1   0x0   0x0   0x0   0x0   0x11   0x1   0x0   0x0   0x1   0x41   0x33   0x0   0x1   0x0 
the length of data  : 20
16:43:6
16:48:53

recv data  downline:      0xff   0x4d   0x16 
the length of data :3
难道是我在模块发完之后就进入接收状态,以至于从设备速度跟不上造成了发送数据慢,接收快数据发了一半就被读了出来。造成数据被分成了两半?但是后来给加了个sleep(1)之后,都被读到一帧上了。
后来参照一个帖子循环读。当一次读16个字节时,从串口读20次时还是有一次出错的。后来用8个字节,测试也不理想。还是出现了分两次接收帧的情况。
那么在实现串口函数时,怎样才能做到稳定的读取数据呢?

后来看到一个帖子说串口的读取操作是七层网络模型中的物理层操作,在其之上如果要实现对于帧的完整接收就不仅仅是读取串口数值那么容易。因为串口只是接收数据,不会判断一个完整的帧数据是否到来,而是根据数据传输是否终止。如果数据传输中止,则给系统读的信息,调用read()读取数据。但是完整的帧数据是上层需要的,底层不会处理。这样就需要上层来控制完整帧的接收。


如此一来,上边的工作就不仅仅是读串口数据的几行代码。而是要判断接收到的数据是否是一个完整的数据帧,如果是则接收成功,跳出接收函数去执行其他操作。如果接收到的数据不是一个完整帧,则需要继续接收串口数据,直到接收到的数据符合我们需要的完整数据帧。尽管这样有些繁琐,即在读完之后判断一次,但是这样接收帧数据的准确性要高好多。

但是也要避免一些问题,即如果读到的数据一直不是一个完整的数据帧,怎么办呢?如果像上边说的,继续接收则很可能在串口接收这里死掉。因为一直没有正确的数据帧,所以还要继续接收串口数据;但是继续读还是没有正确的帧数据。所以在这里还要加上次数判断,如果超过可承受的次数,就退出。这样避免了程序在此卡住的可能。

使用修改过的代码时,再次测试时,没有再出现上边两帧的情况。即使第一次接受出错了,也会继续接收,直到收到一个完整的帧数据。跳出接收函数时,一定是一个完整的数据帧。
int Read_Com3(unsigned char * Data)
{
#define TTY_READ_SIZE       8

    short int length=0;
    unsigned char route;
    unsigned char data[256];
    unsigned char *p_data = data;
    unsigned char start;
    struct timeval tv = {8, 0};
    fd_set serialfd;
    unsigned int u32Ret = FALSE;
    unsigned char u8ReadSize;
    FD_ZERO(&serialfd);
    FD_SET(fd3,&serialfd);
do{
	u32Ret = select(fd3 + 1,&serialfd,NULL,NULL,&tv))
        if(u32Ret < 1)
        {   
            break;
        }
        
        u32Ret = FD_ISSET(fd3, &serialfd) ;
        if(u32Ret < 1)
        {
            break;
        }
        
        bzero(data, 256);
        
        #if 0
        length = read(fd3, data, 256);
        #else
        while(1)
        {
            u8ReadSize = read(fd3, p_data, TTY_READ_SIZE);
            if(TTY_READ_SIZE != u8ReadSize)
            {
                length += u8ReadSize;
                break;
            }
            p_data += TTY_READ_SIZE;
            length += TTY_READ_SIZE;
        }
        #endif
        
#ifdef DEBUG
        printf("\n");
        printf("recv  data downline:  ");
        for(i=0; i<length; i++)
        printf(" 0x%x  ",data[i]);  
        printf("\n");  

        printf("the length of data: %d\n",length);	 
#endif
	 
        if(length > 0)
        {
            u32Ret = length;
        }
        else
        {
           u32Ret = FALSE; //error handle
        }
}while(0);

    tcflush(fd3,TCIOFLUSH);  //clear the rest of the data  in the fd3
    return u32Ret;
}


修改过的代码:
int Read_Com3(unsigned char * Data)
{
#define READ_DATA_SIZE   256

    unsigned char u8CycleTime = 0;
    short int length=0;
    unsigned char route;
    unsigned char data[256];
    unsigned char *p_data = data;
    unsigned char start;
    unsigned char u8ReadSize;
    unsigned char u8Ret = FALSE;

    struct timeval tv = {.tv_sec = 10,
                        .tv_usec = 0};

do{
        if(FALSE == is_ready_read(fd3, &tv))
            break;
        bzero(data, 256);
        
        while(1)
        {
            u8ReadSize = read(fd3, p_data, READ_DATA_SIZE);
            
            if(READ_DATA_SIZE != u8ReadSize)
            {
                length += u8ReadSize;
                p_data += u8ReadSize;
                
                tcflush(fd3,TCIOFLUSH);  //clear the rest of the data  in the fd3

                if(TRUE == judge(&start, data, length))
                {
                    //store the number
                    length = length - start;
                    /*===Copy the data after A===*/
                    memcpy(Data, &data[start],length);
                    u8Ret = length;
                    break;
                }
                
                u8CycleTime++;
                if(u8CycleTime & 0x11)
                {
                    break;
                }
                
                tv.tv_sec = 1;
                tv.tv_usec = 0;
                if(FALSE == is_ready_read(fd3, &tv))
                {
                    
                    break;
                }
                else
                {
                    printf_str_int("####/***read continue*****/####", TRUE);
                    continue;
                }
            }
            else
            {
                p_data += READ_DATA_SIZE;
                length += READ_DATA_SIZE;
            }
        }
        
        printf_str_int("judeg_end", NULL);
    }   while(0);
     //tcflush(fd3,TCIOFLUSH);  //clear the rest of the data  in the fd3
     
    return u8Ret;
}

参考的博客:

http://justwinit.cn/post/2856/



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值