4、GPIO基础与传感器驱动:树莓派GPIO引脚图、PIR传感器工作原理、使用RPi.GPIO读取传感器状态、中断触发模式
好,咱们正式开始动手了。这一章,我会带你从树莓派的“神经末梢”——GPIO引脚讲起,然后接入一个最常用的传感器:PIR人体红外传感器。说白了,就是让树莓派学会“看”到有人经过。
我个人习惯,每次做嵌入式项目,第一步永远是先搞清楚引脚定义。别小看这个,我在项目里见过太多人因为接错线烧了板子。嗯,咱们先把这个基础打牢。
树莓派GPIO引脚图:别接错了,会烧板子
树莓派的GPIO(通用输入输出)引脚,是它和外部世界沟通的桥梁。以树莓派4B为例,它有一个40针的排针。但注意,不是所有针脚都能当GPIO用,有些是电源、有些是地线。
我建议你手边常备一张引脚图。你想想看,如果VCC(3.3V或5V)和GND接反了,或者把3.3V的设备接到了5V上,芯片瞬间就冒烟了。我曾经在调试一个红外传感器时,就因为看错了引脚编号,把信号线接到了5V上,结果传感器直接报废。从那以后,我每次接线前都会用万用表再确认一遍。
这里给你一个常用的引脚功能速查表(以BCM编号为准,这是代码里用的编号):
| 物理引脚 | BCM编号 | 功能 |
|---|---|---|
| 1 | - | 3.3V电源 |
| 2 | - | 5V电源 |
| 3 | 2 (SDA) | I2C数据线 |
| 5 | 3 (SCL) | I2C时钟线 |
| 6 | - | GND |
| 7 | 4 | GPIO 4 |
| 11 | 17 | GPIO 17 |
| 12 | 18 | GPIO 18 |
| 13 | 27 | GPIO 27 |
| 14 | - | GND |
PIR传感器工作原理:它怎么知道有人来了?
PIR(Passive Infrared,被动红外)传感器,说白了就是检测人体发出的红外线。人体温度大约37度,会持续向外辐射红外线。PIR传感器内部有两个热释电元件,当人移动时,两个元件接收到的红外线强度发生变化,传感器就会输出一个高电平信号。
这里有个坑:PIR传感器检测的是“移动”,不是“静止”。如果你站在它面前一动不动,它过几秒就会认为你消失了。我在做智能家居项目时,客户投诉说“人在厕所里灯却灭了”,其实就是这个原因。后来我加了一个延时逻辑,检测到人后保持10分钟输出,才解决了问题。
常见的PIR模块(比如HC-SR501)有三个引脚:
- VCC:接5V(注意,这里是5V,不是3.3V)
- GND:接地
- OUT:信号输出,接树莓派的GPIO
模块背面通常有两个可调电位器:一个调灵敏度(检测距离),一个调延时(输出保持时间)。我建议你先把灵敏度调到中等,延时调到最短,方便调试。
使用RPi.GPIO读取传感器状态:让树莓派“看见”
好,现在开始写代码。Python的RPi.GPIO库是操作GPIO的标准工具。先安装一下:
sudo apt-get update
sudo apt-get install python3-rpi.gpio
然后,咱们写一个最简单的程序,读取PIR传感器的状态:
import RPi.GPIO as GPIO
import time
# 设置引脚编号模式为BCM
GPIO.setmode(GPIO.BCM)
# 定义PIR传感器连接的GPIO引脚
PIR_PIN = 17
# 设置引脚为输入模式
GPIO.setup(PIR_PIN, GPIO.IN)
print("PIR传感器测试开始...")
try:
while True:
# 读取传感器状态
sensor_state = GPIO.input(PIR_PIN)
if sensor_state == GPIO.HIGH:
print("检测到移动!")
else:
print("一切安静...")
# 每0.5秒读取一次
time.sleep(0.5)
except KeyboardInterrupt:
print("程序退出")
GPIO.cleanup()
这段代码的逻辑很简单:循环读取引脚电平,高电平表示有人,低电平表示没人。但这里有个问题——你想想看,如果一直用while True轮询,CPU占用率会很高,而且响应不及时。这就是为什么我们需要中断。
中断触发模式:让CPU别傻等
中断,说白了就是让传感器主动“喊”CPU,而不是CPU一直去“问”。树莓派的GPIO支持三种中断触发模式:
- 上升沿触发:从低电平变高电平时触发(比如有人进入检测区域)
- 下降沿触发:从高电平变低电平时触发(比如人离开检测区域)
- 双边沿触发:两种变化都触发
我个人习惯用上升沿触发来检测“有人进入”,用下降沿触发来检测“人离开”。这样代码更高效,CPU也不用一直空转。
来看一个使用中断的示例:
import RPi.GPIO as GPIO
import time
PIR_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR_PIN, GPIO.IN)
# 定义回调函数
def motion_detected(channel):
print(f"引脚 {channel} 检测到移动!")
def motion_ended(channel):
print(f"引脚 {channel} 移动结束!")
# 添加中断检测
# 上升沿触发:检测到人
GPIO.add_event_detect(PIR_PIN, GPIO.RISING,
callback=motion_detected,
bouncetime=300)
# 下降沿触发:人离开
GPIO.add_event_detect(PIR_PIN, GPIO.FALLING,
callback=motion_ended,
bouncetime=300)
print("中断模式已启动,等待事件...")
try:
# 主程序可以干别的事
while True:
time.sleep(1)
print("主程序正在运行其他任务...")
except KeyboardInterrupt:
print("程序退出")
GPIO.cleanup()
bouncetime=300 这个参数很重要。PIR传感器在输出高电平时,可能会因为信号抖动而产生多次触发。设置300毫秒的防抖时间,可以避免误触发。我曾经没加这个参数,结果传感器每触发一次,回调函数被调用了七八次,日志刷得飞起。
GPIO.BOTH 模式,然后在回调函数里通过 GPIO.input(PIR_PIN) 判断当前电平,就知道是进入还是离开了。
嗯,到这里,你已经掌握了GPIO的基础操作和PIR传感器的驱动方法。下一章,咱们会把这些知识整合起来,做一个完整的报警系统。到时候,你会看到中断模式在实战中的真正威力。