树莓派GSM/GPRS/GNSS HAT用Python读GPS报OSError: [Errno 5]错误
问题原因分析
- 串口硬件/系统配置异常:树莓派3默认
/dev/ttyS0是性能较差的mini串口,绑定蓝牙模块,重启后可能因为配置回退导致蓝牙重新占用串口,引发底层IO调用失败;SIM868模块峰值工作电流较高,仅靠树莓派GPIO供电不足时也会触发串口IO错误。 - 代码逻辑缺陷:错误捕获后采用递归调用重新启动函数的逻辑,会导致旧串口句柄无法彻底释放,多次报错后串口资源被占满,触发ioctl调用失败;未设置串口超时、主动查询+自动输出NMEA的AT指令冲突,也可能导致模块串口挂死。
- 模块状态异常:GNSS模块长时间运行后出现固件死锁,重启树莓派时未同步复位扩展板模块,导致模块处于异常工作状态,响应串口请求时报错。
排查解决步骤
1. 硬件与系统配置修复
- 禁用树莓派蓝牙、切换硬件串口:执行
sudo raspi-config,选择「Interface Options」-「Serial」,关闭串口登录shell、开启硬件串口功能;编辑/boot/firmware/config.txt(旧系统为/boot/config.txt),添加两行配置:
执行dtoverlay=disable-bt enable_uart=1sudo systemctl disable hciuart禁用蓝牙服务后重启设备,确认串口映射无误后,将代码中串口路径改为/dev/serial0(硬件串口的统一软链接,稳定性远高于ttyS0)。 - 优化供电:给GSM/GNSS扩展板单独接外部5V 2A供电,不要完全依赖树莓派GPIO引脚供电,避免峰值电流不足导致的模块异常。
2. 代码逻辑修改
- 移除递归重试逻辑:递归调用会导致栈溢出、资源释放不完全,将错误后的重启逻辑改为循环重试,不要递归调用函数本身。
- 优化串口初始化参数:添加超时配置,避免串口读取卡死:
ser = serial.Serial("/dev/serial0", baudrate=115200, timeout=2, inter_byte_timeout=0.1) - 简化AT指令逻辑:移除
AT+CGNSTST=1指令,主动查询CGNSINF的场景下不需要开启自动NMEA输出,两种模式冲突会导致模块串口挂死。 - 优化缓冲区读取逻辑:pyserial 3.x版本推荐用
in_waiting替代旧的inWaiting()方法,添加读取间隔与编码错误忽略,避免乱码报错:time.sleep(0.1) while ser.in_waiting > 0: data += ser.read(ser.in_waiting).decode('utf-8', errors='ignore') time.sleep(0.05) - 错误处理添加模块复位逻辑:捕获到IO错误时,除关闭串口外,可先发送
AT+CGNSPWR=0关闭GNSS模块,延时1秒后再重新初始化,避免模块状态死锁。
3. 底层验证
安装minicom工具执行minicom -b 115200 -D /dev/serial0,手动发送AT指令测试串口稳定性,如果minicom下也出现IO错误,可直接确认是硬件供电或模块本身故障,排查接线或更换扩展板即可。
内容的提问来源于stack exchange,提问作者G33RY
相关产品推荐
相关产品推荐

