You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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编号)是不是准确连到了传感器输出端?传感器的电源和接地有没有接稳?甚至可以用万用表测一下引脚的实际电压,先确认硬件本身是正常的。

二、代码里藏着的语法和逻辑坑

你的代码有几个明显的错误,这些也会导致脚本运行异常,甚至掩盖电平检测的问题:

  1. 函数嵌套搞错了
    你把Send_firealarm_email()和Send_cancel_email()缩进在了send_email()函数里面,这会导致外面的while循环根本调用不到这两个函数!把它们的缩进和send_email()对齐,放到外面来。

  2. 赋值符号写成减号了
    好几处用了-代替=,这会直接报错:

    • msg - MIMEMultipart() 改成 msg = MIMEMultipart()
    • msg['Subject'] - 'Fire Alarm Notification' 改成 msg['Subject'] = 'Fire Alarm Notification'
      同样的错误在Send_cancel_email()里也存在,全部改过来。
  3. 没有电平变化的检测逻辑
    现在的循环只要检测到高电平就会疯狂发邮件,而且不会识别电平从高变低的变化。得加个变量记录上一次的电平状态,只在电平切换时触发动作:

    # 初始化上一次的状态
    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
    
  4. 播放器变量的作用域问题
    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()
    
  5. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 16:24:31