树莓派3 LED交通灯与客户端通信代码故障排查求助
解决树莓派交通灯循环与Socket信号响应的冲突问题
嘿,我瞅了你的代码,核心问题其实很明显:socket.accept()是阻塞调用,它会一直卡在那儿等客户端连进来,导致你的红黄绿循环代码根本没机会执行!另外代码里还有几个小坑:比如判断c==0完全不对(accept()返回的c是客户端套接字对象,永远不可能是0),还有重复导入GPIO、重复初始化引脚的问题,这些都得改。
给你整个靠谱的解决方案——用多线程把交通灯循环和Socket监听分开,这样俩任务能同时跑,再用个标志位来触发紧急绿灯模式,完美解决阻塞问题。
修复后的完整代码
import socket import RPi.GPIO as GPIO import time import threading # GPIO只初始化一次!别重复搞 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) # 定义引脚,方便后续维护 RED_PIN = 18 YELLOW_PIN = 23 GREEN_PIN = 24 GPIO.setup(RED_PIN, GPIO.OUT) GPIO.setup(YELLOW_PIN, GPIO.OUT) GPIO.setup(GREEN_PIN, GPIO.OUT) # 全局标志位:标记是否要触发紧急绿灯 emergency_mode = False def traffic_light_loop(): """负责红黄绿循环的线程函数""" global emergency_mode while True: if emergency_mode: # 紧急模式:立刻亮绿灯,关掉其他灯 GPIO.output(RED_PIN, GPIO.LOW) GPIO.output(YELLOW_PIN, GPIO.LOW) GPIO.output(GREEN_PIN, GPIO.HIGH) time.sleep(0.5) # 加个短延迟,避免频繁切换 continue # 红灯阶段(原来的2秒拆成20个0.1秒,方便响应紧急信号) GPIO.output(RED_PIN, GPIO.HIGH) GPIO.output(YELLOW_PIN, GPIO.LOW) GPIO.output(GREEN_PIN, GPIO.LOW) for _ in range(20): if emergency_mode: break time.sleep(0.1) if emergency_mode: continue # 黄灯阶段(1秒拆成10个0.1秒) GPIO.output(RED_PIN, GPIO.LOW) GPIO.output(YELLOW_PIN, GPIO.HIGH) GPIO.output(GREEN_PIN, GPIO.LOW) for _ in range(10): if emergency_mode: break time.sleep(0.1) if emergency_mode: continue # 绿灯阶段(2秒拆成20个0.1秒) GPIO.output(RED_PIN, GPIO.LOW) GPIO.output(YELLOW_PIN, GPIO.LOW) GPIO.output(GREEN_PIN, GPIO.HIGH) for _ in range(20): if emergency_mode: break time.sleep(0.1) def socket_listener(): """负责监听Socket连接的线程函数""" global emergency_mode s = socket.socket() host = '' port = 12345 s.bind((host, port)) s.listen(5) print("等着电脑端发信号呢...") while True: c, addr = s.accept() print(f'收到来自 {addr} 的连接啦!') # 触发紧急模式 emergency_mode = True # 给电脑端回个消息 c.send('救护车已检测到,绿灯已点亮!'.encode('utf-8')) c.close() # 保持绿灯3秒(你可以根据需求调整这个时间) time.sleep(3) # 恢复正常循环 emergency_mode = False if __name__ == "__main__": try: # 启动两个线程 light_thread = threading.Thread(target=traffic_light_loop) socket_thread = threading.Thread(target=socket_listener) # 设置为守护线程,主程序退出时自动结束 light_thread.daemon = True socket_thread.daemon = True light_thread.start() socket_thread.start() # 主线程保持运行,不然程序会直接退出 while True: time.sleep(1) except KeyboardInterrupt: # 按Ctrl+C时清理GPIO,避免引脚状态异常 GPIO.cleanup() print("程序已终止~")
关键改动说明
- 多线程分离任务:把交通灯循环和Socket监听拆成两个独立线程,再也不会因为
accept()阻塞导致循环跑不起来了。 - 紧急标志位控制:用
emergency_mode这个全局变量来切换模式,交通灯线程会不断检查这个标志,一旦为True就立刻切到绿灯。 - 拆分长延迟:把原来的
time.sleep(2)拆成多个0.1秒的小延迟,这样就算在红灯/黄灯期间,也能在0.1秒内响应紧急信号,不会出现半天没反应的情况。 - GPIO初始化只做一次:原来的代码在每个分支都重复导入GPIO、初始化引脚,现在只在开头做一次,既高效又避免潜在问题。
- 优雅退出:捕获Ctrl+C信号,清理GPIO资源,防止树莓派引脚一直处于通电状态。
电脑端测试代码
你可以在电脑上跑这个代码来测试:
import socket s = socket.socket() # 把这里改成你的树莓派IP raspberry_pi_ip = "192.168.x.x" port = 12345 s.connect((raspberry_pi_ip, port)) print(s.recv(1024).decode('utf-8')) s.close()
内容的提问来源于stack exchange,提问作者Rahul




