我写了一个与串口通信的程序,使用termios,这个程序将读取非阻塞模式的串口,一旦读取数据就向串口写入响应。 如果没有数据从串口读取,程序会做其他的事情,下一个循环,程序再次读取串口。
现在的问题是,有时候,也许几分钟,或者几个小时后,串口不再响应我的程序了。 即使我执行echo 'HBn' > /dev/ttyUSB0 (然后串口应该响应'HACK'),它不会再响应。
我甚至不知道什么时候串口“死”,我没有任何线索。它“死”不吝。
这里是我的configuration:
在Windows上Pyserial的非阻塞/繁忙等待使用:如何实时监控多个串行端口?
在c ++的windows上的串行端口上设置low_latency标志
奇怪的未经处理的exception
从串口读取失败
.Net中的高容量,高速文本框
/// set local mode options //tminfo.c_lflag |= ICANON; tminfo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /// set control mode options tminfo.c_cflag |= (CLOCAL | CREAD); tminfo.c_cflag |= HUPCL; // set hardware flow control tminfo.c_cflag &= ~CRTSCTS; // set how many bits in a character tminfo.c_cflag &= ~CSIZE; tminfo.c_cflag |= CS8; // set parity mode (default to odd validation),this option (PARENB) will both enable input and output parity checking tminfo.c_cflag &= ~PARENB; // we don't need prity checking Now /// set input mode options // set input parity checking tminfo.c_iflag &= ~INPCK; tminfo.c_cflag &= ~CSTOPB; /// set output mode options tminfo.c_oflag &= ~OPOST; tminfo.c_cc[VMIN] = 1; tminfo.c_cc[VTIME] = 1; /// set line speed,defaults to 38400bps,both for input and output // this call will set both input and output speed cfsetspeed(&tminfo,B38400);
在这种情况下很难debugging串行。 我真的不知道是什么原因导致串口在地球上“死亡”。 我快疯了
可能的原因是什么? 任何帮助将不胜感激!
更新:
当串口“死”的时候,其configuration是:
speed 38400 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 1; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
更新2
的/ proc / TTY /驱动器/ ar933x-UART
我注意到,即使我手动写入我的序列,在我的程序运行期间,这个tx和rx字段的值不会改变。
serinfo:1.0 driver revision: 0: uart:AR933X UART mmio:0x18020000 irq:11 tx:169 rx:0 RTS|DTR|CD
的/ proc / TTY /驱动器/串行
serinfo:1.0 driver revision: 0: uart:unkNown port:00000000 irq:0 1: uart:unkNown port:00000000 irq:0 2: uart:unkNown port:00000000 irq:0 3: uart:unkNown port:00000000 irq:0 4: uart:unkNown port:00000000 irq:0 5: uart:unkNown port:00000000 irq:0 6: uart:unkNown port:00000000 irq:0 7: uart:unkNown port:00000000 irq:0 8: uart:unkNown port:00000000 irq:0 9: uart:unkNown port:00000000 irq:0 10: uart:unkNown port:00000000 irq:0 11: uart:unkNown port:00000000 irq:0 12: uart:unkNown port:00000000 irq:0 13: uart:unkNown port:00000000 irq:0 14: uart:unkNown port:00000000 irq:0 15: uart:unkNown port:00000000 irq:0
的/ proc / TTY /驱动器/ usbserial
usbserinfo:1.0 driver:2.0 0: module:pl2303 name:"pl2303" vendor:067b product:2303 num_ports:1 port:1 path:usb-ehci-platform-1
下面是更详细的代码…
int Serial::openup(const char *devfile) { if(-1 == (devfds = open(devfile,O_RDWR | O_NOCTTY ))) { perror(strerror(errno)); return -1; } // set device file io mode to nonblock //int oldflags = fcntl(devfds,F_GETFL); //fcntl(devfds,F_SETFL,oldflags | O_NONBLOCK); // get terminal's attributes tcgetattr(devfds,&tminfo); memset(&tminfo,sizeof(struct termios)); /// set local mode options /// //tminfo.c_lflag |= ICANON; tminfo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN); /// set control mode options /// tminfo.c_cflag |= (CLOCAL | CREAD); // disable hardware flow control tminfo.c_cflag &= ~CRTSCTS; // set how many bits in a character tminfo.c_cflag &= ~CSIZE; tminfo.c_cflag |= CS8; // we don't need prity checking tminfo.c_cflag &= ~PARENB; tminfo.c_cflag &= ~CSTOPB; /// set input mode options /// // disable input parity checking,this tminfo.c_iflag &= ~(INPCK | PARMRK | IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | ICRNL | IXON); /// set output mode options /// //tminfo.c_oflag |= (OPOST | ONLCR); tminfo.c_oflag &= ~OPOST; // *** tminfo.c_cc[VMIN] = 0; // *** tminfo.c_cc[VTIME] = 1; // *** /// set line speed,both for input and output /// // this call will set both input and output speed cfsetspeed(&tminfo,B38400); if(-1 == tcsetattr(devfds,TCSANow,&tminfo)) { perror(strerror(errno)); return -1; } return 0; } int Serial::serve() { char buffer[256] = {0}; /* struct timeval timeo; timeo.tv_sec = 0; timeo.tv_usec = 2 * 1000; select(0,NULL,&timeo); */ //print_trace("ready to read data from serial port.n"); int read_count = 0; if((read_count = read_line(devfds,buffer,256))) { print_trace("read line: %d bytes,%sn",read_count,buffer); if(0 == strncmp(buffer,"S",1)) { // do some operation } else if(0 == strncmp(buffer,"N",1)) { // do some operation } } else { //print_trace("read no data.n"); } // Todo: test only,for find out the reason of serial port 'dead' problem tcflush(devfds,TCIFLUSH); }
其他模块写串口还有另外一个function
int Serial::write_to_zigbee_co(const char *msg) { int write_count = 0; int len = strlen(msg); struct timeval timeo; timeo.tv_sec = 0; timeo.tv_usec = 20 * 1000; select(0,&timeo); tcflush(devfds,TCOFLUSH); if(len == (write_count = write(devfds,msg,len))) { } else { tcflush(devfds,TCOFLUSH); } return write_count; }
linux串口读取()错误的数据
无法让C写入和读取串行端口
如何在Windows上的python中创buildCOM端口
Android上USB设备的Linux文件权限
串口不会突然“死掉”。
突然“死”或无响应的串行链路的典型原因是不必要的流量控制。 您似乎禁用了HW流量控制,但是软件流量控制尚未禁用, 原始模式未正确配置。
您的初始化需求
tminfo.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF);
还要清除c_lflag的IEXTEN ,
并清除c_cflag的PARENB 。
考虑使用cfmakeraw()函数来简化原始模式的初始化。
Raw mode cfmakeraw() sets the terminal to something like the "raw" mode of the old Version 7 terminal driver: input is available character by character,echoing is disabled,and all special processing of terminal input and output characters is disabled. The terminal attributes are set as follows: termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios_p->c_cflag &= ~(CSIZE | PARENB); termios_p->c_cflag |= CS8;
附录
您修改的termios设置看起来没问题。
我想尝试的下一步将是确定串行链路的哪一侧出现故障。 一端没有收到还是一端不能发送?
您可以尝试使用由串口驱动程序维护的指标。 如果双方都在运行Linux,那么你应该检查/ proc / tty / drivers中的文件。 串口潜水员将报告每个端口的接收和发送字节数。 比较测试之前和之后的Rx和Tx计数。
如果你无法从CC2530获得任何数据,那么可能需要串行链路监视器。 除了专用的测试仪器之外,您还可以使用带有两个串行端口的PC进行设置。 将端口A连接到主机,将端口B连接到CC2530,这样这台PC就是一个“中间人”。 然后,您必须编写一个程序,将端口A的接收数据重新传输到端口B,将端口B的RxD重新传输到端口A的TxD。
重传的数据(两个通道)也必须显示或记录。 目的是确定串行链路的哪一侧出现故障。 一旦建立,那么你必须弄清楚它是一个接收还是传输问题。
要么
你可以发布更多的代码(完整的open() ,初始化例程和读写逻辑),供大家检查。
附录2
你发布的代码有一些问题。
初始化代码
// get terminal's attributes tcgetattr(devfds,sizeof(struct termios));
您需要删除memset()语句。
阅读代码
if((read_count = read_line(devfds,256))) {
串口已经初始化为非规范(aka raw)模式,但是这是一个read_line() ,它是一个规范的输入操作。
当你设置原始模式并尝试读取行时,我不知道会发生什么情况,但是如果读取操作挂起,我不会感到惊讶。
您需要评估将通过此串行链路在这两个设备之间交换的数据的类型。
每条消息是由ASCII文本组成的,每一行由一个换行符结尾?
如果“是”,那么你可以使用规范模式和read_line() 。
否则,您应该使用非规范模式和read()系统调用,并编写代码来解析接收到的数据。
if((read_count = read_line(devfds,256))) { ... } else { //print_trace("read no data.n"); }
当read_line()返回一个错误(-1)时,这段代码将把它视为一个好的返回,并尝试在接收缓冲区中处理陈旧或垃圾数据。 如果有任何读取错误,他们一直未被发现,从未报告。
tcflush(devfds,TCIFLUSH);
国际海事组织你滥用tcflush() 。 可能有一些罕见的情况,但是通常你不应该丢弃任何数据,直到你真正解析了它,并且知道它是垃圾数据。 你应该删除这个tcflush()语句。
编写代码
select(0,&timeo);
在写入之前执行时间延迟在用户空间中是有问题的操作。 在调度和抢占的多任务环境中会破坏实际的执行时间,用户空间程序很少需要为每个write()系统调用添加这样一个固定的延迟。
tcflush(devfds,TCOFLUSH);
这应该被删除。
if(len == (write_count = write(devfds,TCOFLUSH); }
另一个可疑/不正确的使用tcflush() 。
这应该被更好的恢复代码所取代。 写短文是不太可能的。 最有可能返回的是完整写入计数或错误返回(-1)。 你需要检查一个错误返回(-1)和errno变量。 (您也需要为其他系统调用执行此操作,例如tcgetattr() 。您需要阅读每个系统调用的手册页 ,以了解可以返回的内容。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。