在一帧数据的接收中,一帧数据,会被分两次接收,如下:第一次接收一部分,第二次接收一部分;
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
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/