Ubuntu C Uart通信丢失了第一个字节



我做了一个新的摘要,进行更多测试,并发布herehttps://forums.developer.nvidia.com/t/jetson-nx-uart-communiation-lost-first-byte/234877


我在Jetson Nx(Ubuntu操作系统)上使用c++编写了一个uart软件,用于与PC通信。在PC上有一个uart模拟器,可以在1秒内发送数据,数据为:EB90021112131415161718191A1C1D1E1F202122232425262728292A如下所示:

在此处输入图像描述

当我的软件接收到数据时,有时它会丢失第一个字节";EB";,如图所示:

90021112131415161718191A1B1C1D1E1F202122232425262728292A

而有时它不会丢失第一个字节EB。

此外,我在Jetson Nx上尝试了一个python软件来接收来自uart的数据,它总是可以正常工作

我的c代码如下。

int TestUart(const char * portName, int nSpeed, int nBits, char nEvent, int nStop);
void main(){
TestUart("/dev/ttyTHS0",9600,8,'N',1);
}

int TestUart(const char * portName, int nSpeed, int nBits, char nEvent, int nStop)
{
int Port = open(portName, O_RDWR | O_NOCTTY);
tcflush(Port, TCIFLUSH);
tcflush(Port, TCIOFLUSH);
usleep(500000);
if (Port == -1)
{
printf("UART.cpp : Unable to open port.");
return -1;
}
else
{
printf("UART.cpp : Port opened. Setting Port options...");
}
int fd = Port;
struct termios newtio, oldtio;
if (tcgetattr(fd, &oldtio) != 0)
{
perror("SetupSerial 1");
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch (nBits)
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch (nEvent)
{
case 'O':
case 'o':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
break;
case 'E':
case 'e':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
case 'n':
newtio.c_cflag &= ~PARENB;
break;
}
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
newtio.c_cflag &= ~CRTSCTS;
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
if (nStop == 1)
{
newtio.c_cflag &= ~CSTOPB;
}
else if (nStop == 2)
{
newtio.c_cflag |= CSTOPB;
}
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;

newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
newtio.c_oflag &= ~OPOST;
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
{
perror("com set error");
return -1;
}
tcflush(fd, TCIFLUSH);
int num = 0;
char rx_data[256];
while(1)
{
int m_curPacket_length = read(Port, rx_data,256);
tcflush(Port, TCIFLUSH);
tcflush(Port, TCIOFLUSH);
printf("    Data %d [port = %s,length = %d]: ",++num,portName,m_curPacket_length);
for (int i = 0; i < m_curPacket_length; i++) {
printf("%X ", rx_data[i]);
}
printf("n");
}
printf("set UART port paramster done!n");
return 0;
}

我希望任何人都能帮我找到这个bug。非常感谢

此外,当我设置VTIME=0和VMIN=0的非阻塞模式时,没有字节丢失。



感谢您的建议!

1关于Jetson Nx,正如我在问题中提到的,它确实有一个不同的结果。可能是手工的不同?我在我的主要问题栏上添加了更多的硬件信息。

这个(格式错误的)结果与您声称得到的单行没有任何相似之处。更重要的是;缺少";作为消息的所有29个字节的字节总是被接收和显示,尽管前两个字节存在扩展符号问题。

2真的很喜欢空行,那只是一次尝试。

同样,你对你声称你的代码产生的结果的描述是不准确和误导的。你忽略了提到你的代码会在不停地轮询系统时产生无关的文本:

3更改如下,仍然存在相同的问题。

  • bzero(&newtio,sizeof(newtio))
  • newtio=oldtio;4以下更改仍然没有效果
  • char rx_data[256]
  • 无符号字符rx_data[256];5以下更改内容将打印如下:
  • newtio.c.cc[VTIME]=0
  • newtio.c_cc[VMIN]=1
  • newtio.c.cc[VTIME]=1
  • newtio.c_cc[VMIN]=29;打印结果:
Data 1 [port = /dev/ttyUSB0,length = 57]:90021112131415161718191A1B1C1D1E1F202122232425262728292AEB90021112131415161718191A1B1C1D1E1F202122232425262728292A
Data 2 [port = /dev/ttyUSB0,length = 57]:90021112131415161718191A1B1C1D1E1F202122232425262728292AEB90021112131415161718191A1B1C1D1E1F202122232425262728292A

仍然失去了第一个"EB">

当我的软件接收到数据时,有时会丢失第一个字节"EB";,如图所示:

90021112131415161718191A1B1C1D1E1F202122232425262728292A

而有时它不会丢失第一个字节EB

我的c代码如下
。。。

假设Jetson Nx与9600波特相比并不是非常慢,执行发布的代码(在PC上)会为我产生以下结果:

$ ./a.out
UART.cpp : Port opened. Setting Port options...    Data 1 [port = /dev/ttyUSB0,length = 1]: FFFFFFEB 
Data 2 [port = /dev/ttyUSB0,length = 1]: FFFFFF90 
Data 3 [port = /dev/ttyUSB0,length = 1]: 2 
Data 4 [port = /dev/ttyUSB0,length = 1]: 11 
Data 5 [port = /dev/ttyUSB0,length = 1]: 12 
Data 6 [port = /dev/ttyUSB0,length = 1]: 13 
Data 7 [port = /dev/ttyUSB0,length = 1]: 14 
Data 8 [port = /dev/ttyUSB0,length = 1]: 15 
Data 9 [port = /dev/ttyUSB0,length = 1]: 16 
Data 10 [port = /dev/ttyUSB0,length = 1]: 17 
Data 11 [port = /dev/ttyUSB0,length = 1]: 18 
Data 12 [port = /dev/ttyUSB0,length = 1]: 19 
Data 13 [port = /dev/ttyUSB0,length = 1]: 1A 
Data 14 [port = /dev/ttyUSB0,length = 1]: 1B 
Data 15 [port = /dev/ttyUSB0,length = 1]: 1C 
Data 16 [port = /dev/ttyUSB0,length = 1]: 1D 
Data 17 [port = /dev/ttyUSB0,length = 1]: 1E 
Data 18 [port = /dev/ttyUSB0,length = 1]: 1F 
Data 19 [port = /dev/ttyUSB0,length = 1]: 20 
Data 20 [port = /dev/ttyUSB0,length = 1]: 21 
Data 21 [port = /dev/ttyUSB0,length = 1]: 22 
Data 22 [port = /dev/ttyUSB0,length = 1]: 23 
Data 23 [port = /dev/ttyUSB0,length = 1]: 24 
Data 24 [port = /dev/ttyUSB0,length = 1]: 25 
Data 25 [port = /dev/ttyUSB0,length = 1]: 26 
Data 26 [port = /dev/ttyUSB0,length = 1]: 27 
Data 27 [port = /dev/ttyUSB0,length = 1]: 28 
Data 28 [port = /dev/ttyUSB0,length = 1]: 29 
Data 29 [port = /dev/ttyUSB0,length = 1]: 2A 

这个(格式错误的)结果与您声称得到的单行没有任何相似之处
更重要的是丢失";作为消息的所有29个字节的字节总是被接收和显示,尽管前两个字节存在扩展符号问题。


此外,当我设置VTIME=0和VMIN=0的非阻塞模式时,没有字节丢失。

同样,您对声称代码产生的结果的描述是不准确和误导性的。您忽略了在不断轮询系统时您的代码将产生无关文本:

UART.cpp : Port opened. Setting Port options...    Data 1 [port = /dev/ttyUSB0,length = 0]: 
Data 2 [port = /dev/ttyUSB0,length = 0]: 
Data 3 [port = /dev/ttyUSB0,length = 0]: 
Data 4 [port = /dev/ttyUSB0,length = 0]: 
Data 5 [port = /dev/ttyUSB0,length = 0]: 
Data 6 [port = /dev/ttyUSB0,length = 0]: 
Data 7 [port = /dev/ttyUSB0,length = 0]: 
Data 8 [port = /dev/ttyUSB0,length = 0]: 
Data 9 [port = /dev/ttyUSB0,length = 0]: 
Data 10 [port = /dev/ttyUSB0,length = 0]: 
Data 11 [port = /dev/ttyUSB0,length = 0]: 
Data 12 [port = /dev/ttyUSB0,length = 0]: 
Data 13 [port = /dev/ttyUSB0,length = 0]: 
Data 14 [port = /dev/ttyUSB0,length = 0]: 
Data 15 [port = /dev/ttyUSB0,length = 0]: 
Data 16 [port = /dev/ttyUSB0,length = 0]: 
Data 17 [port = /dev/ttyUSB0,length = 0]: 
Data 18 [port = /dev/ttyUSB0,length = 0]: 
Data 19 [port = /dev/ttyUSB0,length = 0]: 
Data 20 [port = /dev/ttyUSB0,length = 0]: 
Data 21 [port = /dev/ttyUSB0,length = 0]: 
Data 22 [port = /dev/ttyUSB0,length = 0]:
...

如何将指示已接收数据的文本与无输入的垃圾进行排序?



您的初始化有缺陷,因为使用了一个归零的termios结构。请参阅正确设置终端模式。

我已经尝试过不清零termios结构被使用,仍然存在相同的问题。

if (tcgetattr(fd, &newtio) != 0)     {
perror("SetupSerial 1");
return -1;
}
//bzero(&newtio, sizeof(newtio));

你听从我的建议做得很差,因为你显然没有认真研究链接的指南
通过简单地删除bzero()语句,您现在使用的是未初始化的结构,这可能是一个更严重的错误,应该会生成编译器警告
对代码的正确更正是(使用补丁符号):

-    bzero(&newtio, sizeof(newtio));
+    newtio = oldtio;

您的用户空间程序与UART I/O不同步,因此刷新系统缓冲区(丢弃I/O数据)容易意外丢失真实数据。IOW你滥用了刷新指令

并且当没有如下面所示的刷新时,仍然是问题

事实证明,尽管您的代码存在缺陷,但我可以使用您的原始代码在我的电脑上持续接收29字节的消息。尽管这些缺陷目前不会导致任何观察到的不当行为,但必须对其进行纠正,以获得可靠和稳健的代码。

我听不懂你在说什么">丢失字节";。前两个字节的符号扩展表示是问题所在吗
只需使用接收缓冲区的适当类型进行校正:

-    char rx_data[256];
+    unsigned char rx_data[256];

假设您的系统每秒接收29字节的消息,您可以通过尝试获取完整消息来提高每个read()系统调用的效率。尝试更改以下白蚁属性:

-    newtio.c_cc[VTIME] = 0;
-    newtio.c_cc[VMIN] = 1;
+    newtio.c_cc[VTIME] = 1;
+    newtio.c_cc[VMIN] = 29;

然后,程序可以读取每个系统调用的完整消息:

$ ./a.out
UART.cpp : Port opened. Setting Port options...
Data 1 [port = /dev/ttyUSB0,length = 29]: EB 90 2 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 
Data 2 [port = /dev/ttyUSB0,length = 29]: EB 90 2 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 

最新更新