树莓派RS-232的麻烦 [英] RaspberryPi RS-232 trouble

查看:300
本文介绍了树莓派RS-232的麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是用我的皮的RS-232线路用激光测距仪进行通信。我已经测试使用的Minicom在19200波特率(因为这是LRF的波特率和不能改变),并能正常工作两者之间的通信。虽然写下来到LRF任何命令(其中包括单个字符和pressing'进入')的可能需要尝试多次才能生效,在两个方向通信的伟大工程。

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

 的#include<&stdlib.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&fcntl.h GT;
#包括LT&;&termios.h GT;//设置UART0诠释主(){
    INT uart0_filestream = -1;
    INT回路;
    INT I;
    INT ISERROR = 1,rx_length;
    unsigned char型RX_BUFFER [256];
    useconds_t微= 3000;    uart0_filestream =打开(/开发/ ttyAMA0,O_RDWR | O_NOCTTY | O_NDELAY);    如果(uart0_filestream == -1)
        的printf(错误:无法打开UART \\ n \\ n);
    其他
        的printf(UART开放\\ n \\ n);    结构termios的选择;    tcgetattr(uart0_filestream,&安培;期权);
    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,&安培;期权);    unsigned char型TX_BUFFER [20];
    无符号字符* p_tx_buffer;    p_tx_buffer =安培; TX_BUFFER [0];
    * p_tx_buffer ++ ='O';
    * p_tx_buffer ++ ='\\ n';    / *
    如果(uart0_filestream!= -1){
        对于(i = 0; I< 100;我++){
            诠释计数=写(uart0_filestream,&安培; TX_BUFFER [0],(p_tx_buffer - &安培; TX_BUFFER [0]));
            如果(计数℃,)
                的printf(\\ n \\ n错误:没有写\\ n \\ n字节);
            其他
                的printf(%I字节写:%S \\ n,(p_tx_buffer - &安培; TX_BUFFER [0]),TX_BUFFER);
        }
    }
    * /
    如果(uart0_filestream!= -1){
        对于(I = 0; I&下; 50;){
            rx_length =读(uart0_filestream,(无效*)RX_BUFFER,255);            如果(rx_length大于0){
                的printf(rx_lentgh =%I:\\ t的,rx_length);
                为(循环= 0;环小于30;环++){
                    //检查NULL和新的生产线,方便易读
                    如果(RX_BUFFER [循环] == NULL)
                        RX_BUFFER [循环] ='$';
                    如果(RX_BUFFER [循环] =='\\ n')
                        RX_BUFFER [循环] ='%';
                    的printf(%C,RX_BUFFER [循环]);
                }
                的printf(\\ n);
                我++;
            }
        }
    }    关闭(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:浏览次数:0%$罪状:0000 %% $$$$$结果
  rx_lentgh = 16:142 %% $罪状: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:统计:0TS号码:0142%:0000 %% $$$$$结果
  rx_lentgh = 24:142 %% $ COUNTS号码:0142 %% $ COUN $$$$结果
  rx_lentgh = 8:TS:0000%UNTS号码:0142 %% $ COUN $$$$结果
  rx_lentgh = 16:%$罪状:0000 %% $ 2 %% $ COUN $$$$结果
  rx_lentgh = 8:浏览次数: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 %% $ %%的二氧化碳$ COUN $$$$结果
  rx_lentgh = 8:UNTS:000142 %% $ %%的二氧化碳$ COUN $$$$结果
  rx_lentgh = 24:0 %% $ COUNTS号码:0142 %% $ COUNTS $$$$结果
  rx_lentgh = 16:0000 %% $罪状:0%$ COUNTS $$$$结果
  rx_lentgh = 24:142 %% $ COUNTS号码:0142 %% $ COUN $$$$结果
  rx_lentgh = 8:TS:0000%UNTS号码:0142 %% $ COUN $$$$结果
  rx_lentgh = 16:%$ COUNTS号码:0142 %% $ 2 %% $ COUN $$$$结果


  **以上估计是编辑我的code以提高可读性。空字符被替换为'$'和'\\ n'被替换为%

您可以看到,每次获取数据时,它至少取得了良好的读的一部分,有时整个事情。但是,在那里有很多垃圾。你可以在我的code看到我已筛选出所有读取出错返回。它可能会接管1000读取得到这么多好的读取。我真的认为这与时间的事,但即使是时机,不会我不应该还是会得到[I]一些[/ I]的数据?

写作有同样的问题。单写什么都不做。循环写入code的100倍,最终可能得到code下到LRF,但LRF pretty多不运行code后,在所有的工作,我还没到停电让它Minicom中再工作和查看数据。

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

任何帮助都将大大AP preciated!我一直在这对我的其他类和工作之间几个星期。


解决方案

有您的code的几个问题。


  uart0_filestream =打开(/开发/ ttyAMA0,O_RDWR | O_NOCTTY | O_NDELAY);

您已经安装了端口非阻塞I / O。结果
这可能不是你想要的。添加下面的返回code检查后:

 的fcntl(uart0_filestream,F_SETFL,0);

为了配置阻塞I / O。


 如果(uart0_filestream == -1)
    的printf(错误:无法打开UART \\ n \\ n);

当有一个致命错误的程序应退出,而不是继续上。结果
你还需要检查的错误号的值时,系统调用返回-1。


  tcgetattr(uart0_filestream,&安培;期权);
  ...
tcsetattr(uart0_filestream,TCSANOW,&安培;期权);

从系统调用返回codeS应始终检查。


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

这是的termios 的成员修改不当造成的。结果
只有正确的宏和位运算应执行。
请参阅串行编程的Posix的指南。结果
你必须禁用规范输入处理,这可能不是你想要做什么。结果
你想读的输入是ASCII文本与线路终端,所以用规范的方式为每个行的末尾系统解析。结果
现在,您可以配置为原始模式,其目的是为二进制数据,或者忽略ASCII控制字符的端口。

有关样本code配置规范模式看<一个href=\"http://stackoverflow.com/questions/17675127/reading-from-a-serial-port-after-writing-on-it/17689222#17689222\">this回答。


  rx_length =读(uart0_filestream,(无效*)RX_BUFFER,255);

同样,你需要检查的值的错误号的当系统调用返回-1。结果
阅读()返回-1为您code,的错误号的可能是EAGAIN,表明没有可用数据。


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

I am using the RS-232 lines on my Pi to communicate with a laser range finder. I have tested the communication between the two using minicom at a baud rate of 19200(because that is the baud rate of the LRF and can't be changed), and it works fine. Although writing down to the LRF any commands(which consists of a single character and pressing 'enter') can take several attempts to take affect, communication in both directions works great.

However, when I start programming in C code to read and write with the RS-232, it half works. Here is the code I am using:

#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);
}

When I try to read from the device, it always returns an error. I started looping to see if continually reading gave different results. Of the 100 tries, typically 4-5 return data, all the rest [i]rx_length[/i] comes back -1. The data returned should look like:

COUNTS:0000

where the number depends on the distance the LRF is measuring. But instead, I get output like this:

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 '%'

You can see that every time it gets data, it at least gets part of a good read, and occasionally the whole thing. But there is a lot of junk in there. You can see in my code I have filtered out all reads that returned in an error. It would probably take over 1000 reads to get this many "good" reads. I really think it has to do with timing, but even if it was timing, wouldn't shouldn't I still be getting [i]some[/i] data back?

Writing has the same issue. A single write does nothing. Looping the write code 100 times may end up getting the code down to the LRF, but the LRF pretty much doesn't work at all after running that code and I haven't to cut power to get it to work and view data in minicom again.

The LRF has can send packets at 200Hz or 10Hz, depending on the mode. All data retrieved above was done with the LRF sending packets at 200Hz.

Any help at all would be greatly appreciated! I have been working on this for several weeks between my other classes and work.

解决方案

There are several issues with your code.


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

You have setup the port for non-blocking I/O.
This is probably not what you want. Add the following after the return code checking:

fcntl(uart0_filestream, F_SETFL, 0);

in order to configure blocking I/O.


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

When there is a fatal error the program should exit, rather than continue on.
You also need to examine the value of errno when a syscall returns -1.


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

Return codes from syscalls should always be checked.


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

This is improper modification of termios members.
Only proper macros and bit-wise operations should be performed. Refer to the Posix Guide of Serial Programing.
You have disabled canonical input processing, which is probably not what you want to do.
The input you are trying to read is ASCII text with line termination, so use canonical mode to have the system parse for the end of each line.
You now have the port configured for raw mode, which is intended for binary data or to ignore ASCII control characters.

For sample code to configure canonical mode see this answer.


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

Again, you need to examine the value of errno when a syscall return -1.
When read() returns -1 for your code, errno is probably EAGAIN to indicate that there was no data available.


If blocking I/O is specified and canonical I/O instead of raw I/O, then each read() will return with a complete line of input.

这篇关于树莓派RS-232的麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆