串口通信相关小结

本文探讨了在Ubuntu上进行串口通信时遇到的常见问题,包括打开串口失败、串口丢包、段错误等问题的定位与解决方法。详细分析了串口通信的注意事项,如正确关闭串口、调整通信协议、优化数据接收与解析流程,以及在多线程环境中避免死锁的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. open /dev/ttyUSB0 failed 问题定位

     基于虚拟机,在ubuntu上进行adaptive_hand控制调试时,发现:程序关闭,再重新运行时,有时会出现open /dev/ttyUSB0 failed;必须将串口设备重新插拔,才可以再次成功打开串口。

- 通信类的析构函数中,未使用close()显示关闭串口,加上之后,打开失败现象少很多,但偶尔也会出现,此时多尝试打开几次,或重新插拔串口;

 

2.串口丢包问题

参考:串口丢包受什么影响_总结一下曾经在串口方面犯的错误    https://blog.youkuaiyun.com/weixin_39772652/article/details/111262718

串口通讯丢包原因分析:

- 因为串口数据并不是一定能读到对方发的完整数据,这个和驱动性能、波特率、线长、电磁干扰等很多东西都有关

通信速率设的太高了,高的话容易丢数据

- CPU本身性能限制 或者 总线的限制 导致中断响应不过来

高速  大数据通信时会出现。CPU本身限制 中断响应不过来,这时候一般可以选择更低的波特率、或者更小的封包,或者发包时加一些延时来解决,不过 这些都是应用层的解决方案,在驱动层能做的工作,微乎其微。

由于应用程序效率不高,导致CPU loading 过大,持续100%,可能会有中断丢失的现象,也会导致丢包。这时候优化程序显的格外重要,减少不必要的printf,printf 是非常耗时的。

 

调试、问题定位

- 实际抓取一下,看一下丢包的现象是不是重复,必须排除通信线路的问题;

- 用串口调试助手测试一下硬件和驱动的性能。

- 串口BUF改大点,速度放慢点试试看

 

问题解决

- 串口丢包是不可避免的,因此应该从通讯协议和交互方式上着手改进,使得在偶尔数据丢包的情况下,能尽可能使双方发送的数据仍能被对方接收;

- 通讯协议不要采用一收一发的形式,最好开两个线程,一个用来接收解析数据,另外一个用来定时循环发送数据;

 

3.串口通讯,数据接收、解析时出现“stack smashing detected”错误,即段错误,导致上位机程序崩溃

- 上位机数据接收时,在check sum 错误的情况下,未对变量m_rcv_len清零,使得m_rcv_len越来越大,超过RCV_BUFFER[buffer_size] 的size,就会出现段错误;

tips::段错误往往难以通过gdb调试准确定位具体位置,一定要对各种情况的逻辑进行充分的梳理,根据异常打印信息逐步排查;

 

4. uart解析实例

参考:串口通信协议制定https://mp.youkuaiyun.com/console/editor/html/108194381代码

uart是全双工通信,可开两个线程,一个用来接收解析数据,另外一个用来定时循环发送数据;

read()和write()函数操作的是读缓存区和写缓存区,不需要进行mutex.lock();

 

FD_ISSET(m_fd, &rd)检查串口描述符是否准备好,以便进行接下来的处理操作;如果未准备好,会直接返回-1;

因此,串口通讯,最好有个循环一直调用recv_mcu_data()接收函数,直到接收成功.

经测试,调用一次recv_mcu_data()很多时候是接收失败的,因为串口资源未准备好(被MCU send占用);一般要2-6次调用recv_mcu_data(),才会接收成功一次。

循环可以写在recv_mcu_data()内,变成阻塞直到接收成功为止;也可在外部反复调用recv_mcu_data(),直到接收成功(一定次数内)。

 

5. 和多线程互斥锁mutex同用时,造成的死锁问题

      一般情况下两个线程对同一个mutex进行lock,并不会造成死锁,后lock的线程会进入等待状态,直到前一个进行unlock。

但如果,在lock代码块中有串口通信(文件读写)recv_mcu_data()时,两个线程也会导致程序卡死,无法发送和接收数据(在欠驱手串口通信读、写线程中测试到,如果将串口通信recv_mcu_data()函数放在lock代码块之外,则不会造成死锁)。 因为串口通信、文件读写等输入输出操作,本身就是线程互斥的。

 

6.打开串口后,清除缓存


fd = open("devpath", O_RDWR|O_NOCTTY);
usleep(200000);
tcflush(fd, TCIFLUSH);    //清空输入缓存
tcflush(fd, TCOFLUSH);    //清空输出缓存

7.linux 串口编程详解

https://blog.youkuaiyun.com/jiesunliu3215/article/details/109674157

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值