树莓派GPIO电平检测脚本无法识别引脚电平变化的问题求助
树莓派GPIO电平检测脚本无法识别引脚电平变化的问题求助
嘿,作为新手能自己把旧脚本适配到Python3已经很厉害了!咱们一步步来拆解你遇到的问题,先从硬件到代码逐一排查:
一、先搞定硬件和GPIO的基础配置问题
你说终端里的电平一直不变化,首先得排除硬件和基础配置的锅:
- 添加GPIO拉电阻配置:你现在只写了
GPIO.setup(7, GPIO.IN),如果外部没接上拉/下拉电阻,引脚会处于"浮空"状态,电平要么飘移要么固定不动。根据你的接线情况调整:- 如果传感器触发时输出高电平、平时接地,就加下拉:
GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) - 如果平时是高电平、触发时接地,就加上拉:
GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- 如果传感器触发时输出高电平、平时接地,就加下拉:
- 再仔细检查接线:哪怕换过线,也再确认下引脚7(BOARD编号)是不是准确连到了传感器输出端?传感器的电源和接地有没有接稳?甚至可以用万用表测一下引脚的实际电压,先确认硬件本身是正常的。
二、代码里藏着的语法和逻辑坑
你的代码有几个明显的错误,这些也会导致脚本运行异常,甚至掩盖电平检测的问题:
函数嵌套搞错了
你把Send_firealarm_email()和Send_cancel_email()缩进在了send_email()函数里面,这会导致外面的while循环根本调用不到这两个函数!把它们的缩进和send_email()对齐,放到外面来。赋值符号写成减号了
好几处用了-代替=,这会直接报错:msg - MIMEMultipart()改成msg = MIMEMultipart()msg['Subject'] - 'Fire Alarm Notification'改成msg['Subject'] = 'Fire Alarm Notification'
同样的错误在Send_cancel_email()里也存在,全部改过来。
没有电平变化的检测逻辑
现在的循环只要检测到高电平就会疯狂发邮件,而且不会识别电平从高变低的变化。得加个变量记录上一次的电平状态,只在电平切换时触发动作:# 初始化上一次的状态 last_yellow_state = GPIO.input(7) while True: Input_yellow = GPIO.input(7) print(Input_yellow) # 检测电平从低变高 if Input_yellow == True and last_yellow_state == False: Send_firealarm_email() # 检测电平从高变低 elif Input_yellow == False and last_yellow_state == True: Send_cancel_email() # 更新上一次的状态 last_yellow_state = Input_yellow sleep(0.1) # 加个小延迟,别让循环占满CPU播放器变量的作用域问题
player是在Send_firealarm_email()里定义的,Send_cancel_email()里直接调用player.stdin.write("q")会报错,因为它访问不到这个变量。可以把player设为全局变量:player = None # 全局变量初始化 def Send_firealarm_email(): global player # ... 其他代码 ... player = subprocess.Popen(["mplayer", "song.mp3", "-ss", "30"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def Send_cancel_email(): global player # ... 其他代码 ... if player is not None: player.stdin.write(b"q") # Python3要传字节串,加个b player.wait()Python3的subprocess输入要传字节串
刚才提到的player.stdin.write("q")要改成player.stdin.write(b"q"),不然会报错。
三、修复后的完整代码参考
把上面的问题都修正后,代码大概是这样的:
#!/usr/bin/python3 # 改成Python3的shebang # Note: you must change lines 25-27 # Import Stuff import subprocess import RPi.GPIO as GPIO from time import sleep import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) # Set up GPIO Inputs with pull-down (根据你的硬件调整) GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) player = None # 全局变量存储播放器进程 # Send email message from Gmail def send_email(msg): # Change these 3 lines to your details. USERNAME = "elislagle2012@gmail.com" PASSWORD = "your Gmail password" # 注意:Gmail现在需要用应用专用密码,普通密码登不上 MAILTO = "elislagle2012@gmail.com" msg['From'] = USERNAME msg['To'] = MAILTO server = smtplib.SMTP('smtp.gmail.com:587') server.ehlo() server.starttls() server.ehlo() server.login(USERNAME, PASSWORD) server.sendmail(USERNAME, MAILTO, msg.as_string()) server.quit() print("Email sent to: " + MAILTO) # Send email when fire alarm activated def Send_firealarm_email(): global player print("Fire Alarm Activated") msg = MIMEMultipart() msg.attach(MIMEText('Fire Alarm on Zone 1')) msg['Subject'] = 'Fire Alarm Notification' send_email(msg) player = subprocess.Popen(["mplayer", "song.mp3", "-ss", "30"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Send email when fire alarm off def Send_cancel_email(): global player print("Fire Alarm Reset") msg = MIMEMultipart() msg.attach(MIMEText('Fire Alarm Canceled')) msg['Subject'] = 'Fire Alarm Canceled' send_email(msg) if player is not None: player.stdin.write(b"q") player.wait() player = None # 重置播放器变量 # Main control loop last_yellow_state = GPIO.input(7) while True: Input_yellow = GPIO.input(7) print(Input_yellow) if Input_yellow == True and last_yellow_state == False: Send_firealarm_email() elif Input_yellow == False and last_yellow_state == True: Send_cancel_email() last_yellow_state = Input_yellow sleep(0.1) # 降低循环频率,减少资源占用
额外提示
- Gmail现在禁用了普通密码登录SMTP,你需要开启两步验证,然后创建应用专用密码来代替代码里的PASSWORD,不然会登录失败。
- 测试的时候可以先把发送邮件的部分注释掉,先确认GPIO电平检测是否正常,再逐步加回邮件功能,这样更容易排查问题。
备注:内容来源于stack exchange,提问作者16BitDoggo
相关产品推荐
相关产品推荐

