串口终端读取出现\r伪影的原因排查及无外部命令解决方案
串口读取时\r伪影与自动换行问题的排查与解决
问题复现
我用你提供的Python代码复现了问题——向嵌入式Linux设备的UART端口发送一段长字符串后,读取到的内容里在80字符位置附近出现了多余的\r:
import serial ser = serial.Serial( port='/dev/ttyUSB0', baudrate=115200, timeout=5) ser.reset_input_buffer() ser.reset_output_buffer() b_NEW_LINE_WRITTEN = b'\n' b_alphabet = b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z' ser.write(b_alphabet + b_NEW_LINE_WRITTEN) raw_line = ser.readline() print(raw_line) # 输出:b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q\rq R r S s T t U u V v W w X x Y y Z z\r\n'
同时发现,用终端模拟器连接/dev/ttyUSB0时,行在80字符后自动换行,这和读取到的\r伪影直接相关。
成因排查
我针对你列出的几个可能成因逐一测试:
- 主机
/dev/ttyUSB0驱动设置:在Python占用设备时,单独修改主机串口的列数和模式,确认设置生效后,Python读取仍有\r伪影,排除主机驱动问题。stty -F /dev/ttyUSB0 cols 100 stty -F /dev/ttyUSB0 raw stty -F /dev/ttyUSB0 -a # 输出确认cols已设为100,但问题依旧 - 目标设备
/dev/S0驱动设置:通过Python发送命令修改目标设备的串口列数并确认已设为200,但发送长字符串后仍有\r伪影,排除目标设备tty驱动问题。stty_cmd_set = b'stty cols 200' ser.write(stty_cmd_set + b_NEW_LINE_WRITTEN) ser.reset_input_buffer() ser.reset_output_buffer() stty_cmd_confirm = b'stty -a' ser.write(stty_cmd_confirm + b_NEW_LINE_WRITTEN) print(ser.readline()) # 输出:b'speed 115200 baud; rows 56; columns 200; line = 0;\r\n' - 目标设备Shell设置:用picocom连接时,执行
shopt -s checkwinsize和resize命令后问题消失,这说明问题根源是目标设备的Shell(如bash)缓存了默认的80列窗口大小——当串口连接没有传递窗口尺寸信息时,Shell会在80字符处自动换行并插入\r,而修改stty cols只是改变了终端驱动设置,并没有更新Shell的窗口大小缓存。
无需外部命令的解决方法
要在Python脚本中直接解决,不需要手动执行终端命令,可以尝试以下两种方案:
方案1:强制刷新目标设备的Shell窗口大小
在发送测试字符串前,先向目标设备发送resize命令(这个命令会让Shell重新读取终端的cols/rows设置并更新缓存):
# 发送resize命令刷新Shell窗口大小 ser.write(b'resize\n') # 读取resize命令的输出(避免干扰后续读取) while ser.in_waiting > 0: ser.readline() ser.reset_input_buffer() ser.reset_output_buffer() # 再发送测试字符串 ser.write(b_alphabet + b_NEW_LINE_WRITTEN) raw_line = ser.readline() print(raw_line) # 此时输出应该不再有多余的\r
方案2:永久开启Shell的窗口大小自动检查
如果需要长期解决,可以向目标设备发送命令,让bash在每次执行命令前自动检查窗口大小:
# 永久开启checkwinsize(写入~/.bashrc) ser.write(b'echo "shopt -s checkwinsize" >> ~/.bashrc\n') # 立即生效当前Shell ser.write(b'shopt -s checkwinsize\n') ser.reset_input_buffer() ser.reset_output_buffer()
这样后续连接时,Shell会自动同步终端的cols设置,不会再出现自动换行插入\r的问题。
内容的提问来源于stack exchange,提问作者TheMeaningfulEngineer
相关产品推荐
相关产品推荐

