arm-linuxシリアルポート受信エラー
1フレームデータの受信では、1フレームデータは、2回に分けて受信され、以下のように、1回目は一部を受信し、2回目は一部を受信する.
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)を追加した後、すべて1フレームに読まれた.
その後、投稿を参照してループします.一度に16バイトを読むと、シリアルポートから20回読むとエラーが発生します.その後8バイトでテストも理想的ではありません.やはりフレームを2回に分けて受信する場合がある.
では、シリアル関数を実現する際に、どのようにして安定したデータの読み取りを行うことができますか?
その後,シリアルポートの読み出し動作は7層ネットワークモデルにおける物理層動作であり,フレームの完全な受信を実現するにはシリアルポート数値だけでなく容易であるという投稿を見た.シリアルポートはデータを受信するだけなので、完全なフレームデータが到来するか否かを判断するのではなく、データ伝送が終了するか否かに基づいている.データ転送が中止されると、システムが読み出した情報にread()を呼び出してデータを読み出す.しかし、完全なフレームデータは上位層に必要であり、下位層は処理しない.これにより、完全なフレームの受信を制御するために上位層が必要となる.
これにより,上記の作業はシリアルポートデータの数行のコードを読み取るだけではない.受信したデータが完全なデータフレームであるか否かを判断し、もしそうであれば受信に成功し、受信関数を飛び出して他の操作を実行する.受信されたデータが完全なフレームでない場合、受信されたデータが私たちが必要とする完全なデータフレームに合致するまで、シリアルポートデータを受信し続ける必要があります.これは、読み終わった後に一度判断するという煩わしさがあるが、フレームデータの受信精度はずっと高い.
しかし、読み取ったデータが完全なデータフレームではない場合、どうすればいいのかという問題も避けなければなりません.上記のように受信を続けると、シリアル受信で死ぬ可能性が高い.正しいデータフレームがずっとないので、シリアルポートデータの受信を続けます.しかし、読み続けても正しいフレームデータはありません.だからここでは回数判断を加えて、耐えられる回数を超えたら退出します.これにより、プログラムがここに詰まっている可能性が回避されます.
修正したコードを使用した場合、再度テストした場合、上の2フレームは表示されません.最初の受信エラーが発生しても、完全なフレームデータが受信されるまで受信を続けます.受信関数から飛び出すと、必ず完全なデータフレームになります.
修正されたコード:
参考ブログ:
http://justwinit.cn/post/2856/
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)を追加した後、すべて1フレームに読まれた.
その後、投稿を参照してループします.一度に16バイトを読むと、シリアルポートから20回読むとエラーが発生します.その後8バイトでテストも理想的ではありません.やはりフレームを2回に分けて受信する場合がある.
では、シリアル関数を実現する際に、どのようにして安定したデータの読み取りを行うことができますか?
その後,シリアルポートの読み出し動作は7層ネットワークモデルにおける物理層動作であり,フレームの完全な受信を実現するにはシリアルポート数値だけでなく容易であるという投稿を見た.シリアルポートはデータを受信するだけなので、完全なフレームデータが到来するか否かを判断するのではなく、データ伝送が終了するか否かに基づいている.データ転送が中止されると、システムが読み出した情報にread()を呼び出してデータを読み出す.しかし、完全なフレームデータは上位層に必要であり、下位層は処理しない.これにより、完全なフレームの受信を制御するために上位層が必要となる.
これにより,上記の作業はシリアルポートデータの数行のコードを読み取るだけではない.受信したデータが完全なデータフレームであるか否かを判断し、もしそうであれば受信に成功し、受信関数を飛び出して他の操作を実行する.受信されたデータが完全なフレームでない場合、受信されたデータが私たちが必要とする完全なデータフレームに合致するまで、シリアルポートデータを受信し続ける必要があります.これは、読み終わった後に一度判断するという煩わしさがあるが、フレームデータの受信精度はずっと高い.
しかし、読み取ったデータが完全なデータフレームではない場合、どうすればいいのかという問題も避けなければなりません.上記のように受信を続けると、シリアル受信で死ぬ可能性が高い.正しいデータフレームがずっとないので、シリアルポートデータの受信を続けます.しかし、読み続けても正しいフレームデータはありません.だからここでは回数判断を加えて、耐えられる回数を超えたら退出します.これにより、プログラムがここに詰まっている可能性が回避されます.
修正したコードを使用した場合、再度テストした場合、上の2フレームは表示されません.最初の受信エラーが発生しても、完全なフレームデータが受信されるまで受信を続けます.受信関数から飛び出すと、必ず完全なデータフレームになります.
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("
");
printf("recv data downline: ");
for(i=0; i<length; i++)
printf(" 0x%x ",data[i]);
printf("
");
printf("the length of data: %d
",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/