RaspberryPi RS-232麻烦

我在Pi上使用RS-232线与激光测距仪进行通信。 我已经使用minicom以19200的波特率测试了两者之间的通信(因为这是LRF的波特率并且无法更改),并且它工作正常。 虽然写下LRF任何命令(由单个字符组成并按’enter’)可能需要多次尝试才能生效,但双向通信效果很好。

但是,当我开始使用C代码编程以使用RS-232进行读写时,它的一半工作。 这是我正在使用的代码:

#include  #include  #include  #include  //SETUP UART0 int main(){ int uart0_filestream = -1; int loop; int i; int isError=1, rx_length; unsigned char rx_buffer[256]; useconds_t micro=3000; uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); if(uart0_filestream == -1) printf("ERROR: Unable to open UART\n\n"); else printf("UART open\n\n"); struct termios options; tcgetattr(uart0_filestream, &options); options.c_cflag = B19200 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR | ICRNL; options.c_oflag = 0; options.c_lflag = 0; tcflush(uart0_filestream, TCIFLUSH); tcsetattr(uart0_filestream, TCSANOW, &options); unsigned char tx_buffer[20]; unsigned char *p_tx_buffer; p_tx_buffer = &tx_buffer[0]; *p_tx_buffer++ = 'o'; *p_tx_buffer++ = '\n'; /* if(uart0_filestream != -1){ for(i = 0; i<100; i++){ int count = write(uart0_filestream, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0])); if(count < 0) printf("\n\nERROR: No bytes written\n\n"); else printf("%i bytes written: %s\n", (p_tx_buffer - &tx_buffer[0]), tx_buffer); } } */ if(uart0_filestream != -1){ for(i=0; i 0){ printf("rx_lentgh = %i:\t ", rx_length); for(loop=0; loop<30; loop++){ //check for NULL and new line for easier readability if(rx_buffer[loop] == NULL) rx_buffer[loop] = '$'; if(rx_buffer[loop] == '\n') rx_buffer[loop] = '%'; printf("%c", rx_buffer[loop]); } printf("\n"); i++; } } } close(uart0_filestream); } 

当我尝试从设备读取时,它总是返回错误。 我开始循环,看看是否持续阅读给出了不同的结果。 在100次尝试中,通常4-5次返回数据,所有其余的[i] rx_length [/ i]返回-1。 返回的数据应如下所示:

计数:0000

数量取决于LRF测量的距离。 但相反,我得到这样的输出:

rx_lentgh = 16:jRþ$ COUNTS:0000%$$$$$$$$$$$$
rx_lentgh = 8:%$ COUNTSTS:0000%$$$$$$$$$$$$
rx_lentgh = 16 :: 0142 %% $ COUNTS:0 $$$$$$$$$$$$
rx_lentgh = 8:000 %% $ COCOUNTS:0 $$$$$$$$$$$$
rx_lentgh = 16:UNTS:0142 %% $ COUN $$$$$$$$$$$$
rx_lentgh = 24:TS:0142 %% $ COUNTS:0000 %% $$$$$
rx_lentgh = 8:COUNTS:0%$ COUNTS:0000 %% $$$$$
rx_lentgh = 16:142 %% $ COUNTS:000:0000 %% $$$$$
rx_lentgh = 16:0 %% $ COUNTS:0142%:0000 %% $$$$$
rx_lentgh = 8:%$ COUNTSTS:0142%:0000 %% $$$$$
rx_lentgh = 8 :: 0000 %% $ TS:0142%:0000 %% $$$$$
rx_lentgh = 8:COUNTS:0TS:0142%:0000 %% $$$$$
rx_lentgh = 24:142 %% $ COUNTS:0142 %% $ COUN $$$$
rx_lentgh = 8:TS:0000%UNTS:0142 %% $ COUN $$$$
rx_lentgh = 16:%$ COUNTS:0000 %% $ 2 %% $ COUN $$$$
rx_lentgh = 8:COUNTS:0:0000 %% $ 2 %% $ COUN $$$$
rx_lentgh = 16:142 %% $ COUNTS:0002 %% $ COUN $$$$
rx_lentgh = 8:0 %% $ COUNUNTS:0002 %% $ COUN $$$$
rx_lentgh = 16:TS:0142 %% $ COUNTS2 %% $ COUN $$$$
rx_lentgh = 8 :: 0000 %% $%$ COUNTS2 %% $ COUN $$$$
rx_lentgh = 16:COUNTS:0142 %% $ CO2 %% $ COUN $$$$
rx_lentgh = 8:UNTS:000142 %% $ CO2 %% $ COUN $$$$
rx_lentgh = 24:0 %% $ COUNTS:0142 %% $ COUNTS $$$$
rx_lentgh = 16 :: 0000 %% $ COUNTS:0%$ COUNTS $$$$
rx_lentgh = 24:142 %% $ COUNTS:0142 %% $ COUN $$$$
rx_lentgh = 8:TS:0000%UNTS:0142 %% $ COUN $$$$
rx_lentgh = 16:%$ COUNTS:0142 %% $ 2 %% $ COUN $$$$

 **The above is edited in my code for readability. A NULL character is replaced with '$' and a '\n' is replaced with '%' 

您可以看到,每次获取数据时,它至少会获得良好的读取,有时甚至是整个事情。 但那里有很多垃圾。 您可以在我的代码中看到我已经过滤掉了错误中返回的所有读取。 它可能需要超过1000次读取才能获得这么多“好”的读取。 我真的认为它与时间有关,但即使是时间,我不应该仍然得到[i]一些[/ i]数据吗?

写作有同样的问题。 一次写入什么都不做。 将编写代码循环100次可能最终将代码下载到LRF,但是在运行该代码之后LRF几乎完全不起作用而且我没有削减function以使其工作并在minicom中查看数据再次。

LRF可以发送200Hz或10Hz的数据包,具体取决于模式。 上面检索的所有数据都是使用LRF以200Hz发送数据包完成的。

任何帮助都将非常感谢! 我在其他课程和工作之间已经工作了几个星期。

您的代码有几个问题。


 uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); 

您已为非阻塞I / O设置端口。
这可能不是你想要的。 返回代码检查后添加以下内容:

 fcntl(uart0_filestream, F_SETFL, 0); 

为了配置阻塞I / O.


 if(uart0_filestream == -1) printf("ERROR: Unable to open UART\n\n"); 

当出现致命错误时,程序应该退出,而不是继续。
当系统调用返回-1时,您还需要检查errno的值。


 tcgetattr(uart0_filestream, &options); ... tcsetattr(uart0_filestream, TCSANOW, &options); 

应始终检查系统调用的返回码。


 options.c_cflag = B19200 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR | ICRNL; options.c_oflag = 0; options.c_lflag = 0; 

这是对termios成员的不正确修改。
只应执行适当的宏和逐位操作。 请参阅串行编程的Posix指南 。
您已禁用规范输入处理,这可能不是您想要做的。
您尝试读取的输入是带有行终止的ASCII文本,因此请使用规范模式让系统解析每行的结尾。
您现在已将端口配置为原始模式,该模式用于二进制数据或忽略ASCII控制字符。

有关配置规范模式的示例代码,请参阅此答案 。


  rx_length = read(uart0_filestream, (void*)rx_buffer, 255); 

同样,当系统调用返回-1时,您需要检查errno的值。
read()为您的代码返回-1时, errno可能是EAGAIN,表示没有可用的数据。


如果指定了阻塞I / O和规范I / O而不是原始I / O,那么每个read()将返回一个完整的输入行。

建议OP错误地解释数据 – 看起来相当不错。

建议重写内循环

 // for(loop=0; loop<30; loop++) for(loop=0; loop 

这样做之后,结果应该会好得多。 诀窍是read()示例与到达数据异步发生,因此只读取部分消息。 read()不知道数据包何时结束。 它在完整,错误或当时没有可用数据时返回read()和数据包结束的到达之间没有同步。 需要重新整合消息。

同步伪代码

 i = 0; length = 0; forever() { do { i += length; length = read(&buffer[i]) if (length means bad read) handle error; search buffer from i to (i+length) for End-of-packet } while (end-of-packet not found and buffer not too full) Use buffer from start to end-of-packet. length = i+length-end-of-packet-index memmove(&buffer[0], &buffer[end-of-packet-index+1], length); i = 0; } 

您可以检查其他类似read()的函数,这些函数会在超时之前读取。 (也许是一个不同的open()选项呢?

其他小问题

  1. options.c_cflag更多注释来解释选项。

  2. “rx_length”vs“rx_lentgh”。

  3. rx_buffer[loop] == NULL是不好的forms。 rx_buffer[loop]是一个charNULL是一个指针。 使用rx_buffer[loop] == '\0'

  4. 出于调试目的,请考虑

 // printf("%c", rx_buffer[loop]); if (isprint(rx_buffer[loop])) { printf("%c", rx_buffer[loop]); } else { printf("(%02hhX)", rx_buffer[loop]); }