树莓派3B+通过GPIO串口与Arduino Nano通信控制继电器逻辑异常
故障可能原因汇总
1. Arduino业务代码逻辑顺序错误
你当前使用的Arduino代码中,turnOn()、turnOff()函数的执行顺序有误:先调用print()打印当前引脚状态,再执行电平切换判断。你观测到的引脚状态日志是切换前的旧状态,并非执行指令后的新状态,会误导问题判断。
同时和你之前USB通信正常的版本对比,新增的状态判断逻辑虽然本身没有语法错误,但结合串口复位问题会出现动作不符合预期的情况。
2. Python侧重复打开串口触发Arduino复位
你的Python代码serialComs函数每次接收网页请求时,都会重新打开/dev/ttyAMA0串口设备。树莓派硬件串口和Arduino Nano连接时,打开串口的动作会默认拉低Arduino的复位引脚,导致Arduino每次处理指令前都会自动重启,继电器引脚电平恢复到初始默认值(LOW),直接打乱你的控制逻辑。
这也是为什么你USB通信时没有问题:USB转串口的默认配置一般不会触发Arduino自动复位,且你当时的代码没有多余的状态判断,每次收到指令直接写电平,不受复位影响。
3. 硬件电平匹配/共地问题
GPIO串口通信对电平一致性要求很高:
- 请确认树莓派和Arduino已经可靠共地,仅连接TX、RX两根线无法保证电平识别准确
- 请确认你的继电器模块触发逻辑:如果是低电平触发的继电器,代码中
HIGH对应关、LOW对应开,和你的预期逻辑完全相反,就会出现点击关按钮反而开继电器的异常
快速修复方案
- 调整Arduino代码执行顺序:先执行电平切换,再打印切换后的状态;建议直接删掉冗余的状态判断逻辑,和之前USB正常的版本保持一致,收到指令直接写引脚电平
- 修改Python代码,将串口初始化逻辑提到全局,不要每次请求都重新打开串口:
import serial from flask import Flask, redirect app = Flask(__name__) # 全局仅初始化一次串口 ser = serial.Serial('/dev/ttyAMA0',9600 , timeout=1) ser.flush() @app.route('/light/on') def lights_on(): line = serialComs(b"on\n") return redirect('/' + str(line)) @app.route("/light/off") def lights_off(): line = serialComs(b"off\n") return redirect('/' + str(line)) @app.route("/<line>") def lights(line): print("The Light Is Now " + line) return str(line) def serialComs(state): ser.write(state) line = ser.readline().decode('utf-8').rstrip() return line if __name__ == '__main__': app.debug = True app.run()
- 检查硬件接线,确认树莓派GND和Arduino GND已经可靠连接,确认继电器触发逻辑和代码电平匹配
内容的提问来源于stack exchange,提问作者Christiaan
相关产品推荐
相关产品推荐

