树莓派RS-232麻烦(RaspberryPi RS-232 trouble)

2019-10-18 16:35发布

我使用我的裨的RS-232线用激光测距仪通信。 我已经测试使用小型机在19200波特率(因为这是LRF的波特率,不能更改),并能正常工作两者之间的通信。 虽然写下来到LRF任何命令(其中包括一个单独的字符,然后按“Enter”键)可以需要尝试多次才能生效,在两个方向通信的伟大工程。

然而,当我开始用C代码编程阅读和与RS-232写了一半的作品。 这里是我使用的代码:

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

//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<50; ){
            rx_length = read(uart0_filestream, (void*)rx_buffer, 255);

            if(rx_length > 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þ$罪状:0000%$$$$$$$$$$$$
rx_lentgh = 8:%$ COUNTSTS:0000%$$$$$$$$$$$$
rx_lentgh = 16:号码:0142 %% $计数:0 $$$$$$$$$$$$
rx_lentgh = 8:000 %% $ COCOUNTS:0 $$$$$$$$$$$$
rx_lentgh = 16:UNTS号码:0142 %% $ COUN $$$$$$$$$$$$
rx_lentgh = 24:TS号码:0142 %% $罪状: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:统计号码: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几乎不运行的代码后,在所有的工作,我也没有削减权力得到它的工作和查看数据在小型机再次。

该LRF已经可以在200Hz的10Hz的或发送数据包,根据不同的模式。 上述检索到的所有数据与LRF在200Hz的发送数据包来完成。

任何帮助都将不胜感激! 我一直在为我的其他类和工作之间的几个星期。

Answer 1:

有你的代码的几个问题。


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");

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


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的值。
read()返回-1为您的代码, 错误号可能是EAGAIN,表明没有可用数据。


如果阻塞I / O被指定和典型的I / O而不是原始I / O,则每个read()将与输入的完整线返回。



Answer 2:

建议OP是错误解释数据 - 它看起来相当不错。

建议重新写内环

// for(loop=0; loop<30; loop++)
for(loop=0; loop<rx_length; 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” 与 “rx_lentgh”。

  3. rx_buffer[loop] == NULL是不好的形式。 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]);
}


文章来源: RaspberryPi RS-232 trouble