Python之树莓派GPIO篇:从零开始掌控硬件(完整版)
树莓派(Raspberry Pi)之所以如此受欢迎,很大程度上归功于它那排标志性的GPIO(通用输入输出)引脚。通过Python,你可以轻松地控制这些引脚,让树莓派与传感器、LED、电机、显示屏等物理世界交互。本文将系统性地带你从零开始,深入掌握使用Python控制树莓派GPIO的全部核心技能。
第一部分:GPIO基础认知
1.1 什么是GPIO?
GPIO是“通用输入/输出”(General Purpose Input/Output)的缩写,是树莓派与外部世界沟通的桥梁。通过编程,你可以:
- **设置某个引脚为高电平(3.3V)或低电平(0V)**来控制外部设备(如点亮LED、驱动电机)
- 读取某个引脚的电平状态来感知外部世界(如检测按钮是否被按下、读取传感器数据)
树莓派上的GPIO引脚本质上是芯片(Broadcom SoC)直接引出的接口,可以通过软件控制其行为。
1.2 GPIO引脚布局详解
树莓派主板上的40个引脚(部分早期型号为26脚)有着各自不同的功能。以最新型号为例,引脚按功能可分为以下几类:
电源引脚(POWER):
- 提供稳定的3.3V或5V电压,用于为外部电路供电
- 3.3V引脚:1号、17号(最大电流约50mA)
- 5V引脚:2号、4号(最大电流取决于USB电源适配器)
接地引脚(GND):
- 用于闭合电路,是任何电子项目的“负极”
- 6号、9号、14号、20号、25号、30号、34号、39号
GPIO控制引脚:
- 这才是我们可以编程控制的引脚,数量有26个
- 它们可以被灵活地设置为输入或输出模式
- 部分引脚还具备特殊功能(如I2C、SPI、UART、PWM)
特殊功能引脚:
| 功能 | 引脚(BCM编号) | 用途 |
|---|---|---|
| I2C | BCM 2(SDA), BCM 3(SCL) | 连接I2C传感器 |
| SPI | BCM 7-11 | 连接SPI设备(显示屏等) |
| UART | BCM 14(TX), BCM 15(RX) | 串口通信 |
| PWM | BCM 12, 13, 18, 19 | 硬件PWM输出 |
💡 快速查询引脚功能
在树莓派终端输入pinout命令,系统会以清晰的图表显示你当前所用树莓派型号的完整GPIO引脚布局。或参考官方GPIO引脚图:
+-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 0 | IN | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | IN | 0 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | IN | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | IN | 0 | 23 || 24 | 1 | IN | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
1.3 GPIO的两种主流编码方式
使用Python的RPi.GPIO库时,首先要决定如何“指代”一个引脚,这需要在代码开头用 GPIO.setmode() 声明。
| 编码方式 | 说明 | 使用场景 |
|---|---|---|
| BOARD | 使用引脚在物理排针上的位置编号(1至40) | 推荐新手,最直观,和GPIO图一一对应 |
| BCM | 使用Broadcom SoC的通道编号 | 官方习惯,但需对照引脚图查找 |
示例:
import RPi.GPIO as GPIO
# 方式一:使用物理引脚编号(推荐)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT) # 将物理引脚11(对应BCM17)设置为输出
# 方式二:使用BCM编号
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT) # 将BCM17设置为输出
⚠️ 注意
一旦选择了一种编码方式,整个程序中必须保持一致,混用会导致引脚混淆。
第二部分:RPi.GPIO核心库详解
RPi.GPIO是Python控制GPIO的核心库,在官方Raspberry Pi OS中已预装。如需手动安装:
sudo apt update
sudo apt install python3-rpi.gpio
2.1 基础用法四步走
第一步:导入库并设置编码
这是所有GPIO程序的标准开头。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD) # 选择你习惯的编码方式
GPIO.setwarnings(False) # 可选:关闭警告信息
第二步:初始化引脚模式
使用 GPIO.setup(pin, mode) 来设置引脚是输入还是输出。
GPIO.setup(12, GPIO.OUT) # 将物理引脚12设置为输出模式
GPIO.setup(16, GPIO.IN) # 将物理引脚16设置为输入模式
# 设置输出引脚的初始状态
GPIO.setup(12, GPIO.OUT, initial=GPIO.HIGH) # 初始为高电平
# 设置输入引脚的上拉/下拉电阻
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP) # 上拉电阻
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # 下拉电阻
第三步:读/写引脚数据
- 写入:用
GPIO.output(pin, state)让输出引脚输出高或低电平。
GPIO.output(12, GPIO.HIGH) # 引脚12输出高电平(3.3V)
GPIO.output(12, GPIO.LOW) # 引脚12输出低电平(0V)
- 读取:用
GPIO.input(pin)读取输入引脚的电平状态,返回GPIO.HIGH(1)或GPIO.LOW(0)。
state = GPIO.input(16) # 读取引脚16的状态
if state == GPIO.HIGH:
print("引脚16检测到高电平")
else:
print("引脚16检测到低电平")
第四步:清理引脚
程序结束时,务必调用 GPIO.cleanup() 来释放资源,将所有引脚恢复到默认状态,避免后续程序出问题。
GPIO.cleanup() # 清理所有引脚
GPIO.cleanup(12) # 仅清理指定引脚
2.2 完整代码模板
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
# 定义引脚
LED_PIN = 33
BUTTON_PIN = 31
# 初始化
GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
print("程序启动,按Ctrl+C退出")
try:
while True:
if GPIO.input(BUTTON_PIN) == GPIO.LOW:
GPIO.output(LED_PIN, GPIO.HIGH)
else:
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(0.01)
except KeyboardInterrupt:
print("程序被手动终止")
finally:
GPIO.cleanup()
print("GPIO清理完成")
第三部分:动手实验
3.1 实验一:点亮LED
通过一个最简单的“点亮LED”实验,快速理解GPIO的输出功能。
硬件连接(以物理引脚为例):
- LED的正极(长脚)通过一个限流电阻(约220Ω)连接到树莓派的 GPIO输出引脚(例如物理引脚33)
- LED的负极(短脚)连接到树莓派的 GND引脚(例如物理引脚34)
⚠️ 安全提示
树莓派GPIO引脚只能提供约3.3V电压和很低的电流(最大约16mA),必须串联限流电阻(220Ω-1kΩ),否则可能会烧坏LED或GPIO引脚。
树莓派 (物理引脚33) --- 220Ω电阻 --- [LED+ (长脚)] --- [LED- (短脚)] --- GND (物理引脚34)
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
LED_PIN = 33
GPIO.setup(LED_PIN, GPIO.OUT)
print("开始闪烁LED")
try:
while True:
GPIO.output(LED_PIN, GPIO.HIGH)
print("LED点亮")
time.sleep(1)
GPIO.output(LED_PIN, GPIO.LOW)
print("LED熄灭")
time.sleep(1)
except KeyboardInterrupt:
print("程序被手动终止")
finally:
GPIO.cleanup()
运行:
sudo python led_blink.py
3.2 实验二:读取按钮输入
使用按键检测GPIO的输入功能。
硬件连接:
- 按钮一端连接到树莓派的 GPIO输入引脚(如物理引脚31)
- 按钮另一端连接到 GND
- 在GPIO引脚和3.3V之间连接一个上拉电阻(10kΩ),或使用GPIO内置上拉
两种接法对比:
| 接法 | GPIO初始状态 | 按钮按下时 | 优点 | 缺点 |
|---|---|---|---|---|
| 上拉电阻 | HIGH | LOW | 信号稳定,抗干扰强 | 需要外部电阻 |
| 下拉电阻 | LOW | HIGH | 信号稳定,抗干扰强 | 需要外部电阻 |
| 浮空输入 | 不确定 | - | 无需电阻 | 信号不稳定,不推荐 |
推荐方案:使用GPIO内置上拉电阻,无需外部电阻:
树莓派 (物理引脚31) --- 按钮 --- GND (物理引脚34)
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
BUTTON_PIN = 31
# 启用内置上拉电阻
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
print("等待按钮按下...")
try:
while True:
if GPIO.input(BUTTON_PIN) == GPIO.LOW:
print("按钮被按下!")
time.sleep(0.3) # 简单消抖
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
3.3 实验三:按钮控制LED
结合输入和输出,制作一个按钮开关灯。
硬件连接:
- 按钮:物理引脚31到GND(使用上拉电阻)
- LED:物理引脚33经220Ω电阻到GND
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
LED_PIN = 33
BUTTON_PIN = 31
GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
print("按钮按下时LED点亮,松开熄灭")
try:
while True:
if GPIO.input(BUTTON_PIN) == GPIO.LOW:
GPIO.output(LED_PIN, GPIO.HIGH)
else:
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(0.01)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
3.4 实验四:按钮切换LED(自锁开关)
每次按下按钮切换LED的状态。
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
LED_PIN = 33
BUTTON_PIN = 31
GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
led_state = False
last_button_state = GPIO.HIGH
print("每次按下按钮切换LED状态")
try:
while True:
button_state = GPIO.input(BUTTON_PIN)
# 检测下降沿(从HIGH到LOW)
if last_button_state == GPIO.HIGH and button_state == GPIO.LOW:
led_state = not led_state
GPIO.output(LED_PIN, GPIO.HIGH if led_state else GPIO.LOW)
print("LED", "点亮" if led_state else "熄灭")
time.sleep(0.2) # 消抖
last_button_state = button_state
time.sleep(0.01)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
第四部分:PWM与呼吸灯
PWM(脉冲宽度调制)技术可以让数字信号模拟出模拟信号的效果,最经典的例子就是控制LED的亮度和电机转速。
4.1 PWM原理详解
PWM通过在一个固定周期内快速切换高电平和低电平,并调整高电平所占的时间比例(即占空比) 来实现“看起来”的不同亮度。占空比越大,LED就越亮。
| 占空比 | 效果 |
|---|---|
| 0% | LED完全熄灭 |
| 25% | LED亮度约25% |
| 50% | LED亮度为50% |
| 75% | LED亮度约75% |
| 100% | LED完全点亮 |
树莓派提供两种PWM方式:
- 软件PWM:由CPU模拟,精度较低,占用CPU资源
- 硬件PWM:由专用硬件产生,精度高,不占用CPU(支持BCM 12, 13, 18, 19)
4.2 RPi.GPIO实现呼吸灯
使用RPi.GPIO库的PWM功能,实现让LED像呼吸一样柔和变化。
硬件连接:同实验一(LED接物理引脚33)
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
LED_PIN = 33
GPIO.setup(LED_PIN, GPIO.OUT)
# 创建PWM实例:频率100Hz
p = GPIO.PWM(LED_PIN, 100)
p.start(0) # 以0%占空比启动(LED熄灭)
print("呼吸灯效果,按Ctrl+C退出")
try:
while True:
# 渐亮:从0%到100%
for dc in range(0, 101, 2):
p.ChangeDutyCycle(dc)
time.sleep(0.02)
# 渐暗:从100%到0%
for dc in range(100, -1, -2):
p.ChangeDutyCycle(dc)
time.sleep(0.02)
except KeyboardInterrupt:
print("程序终止")
finally:
p.stop()
GPIO.cleanup()
参数调优:
frequency(频率):50-200Hz适合LED,20-50kHz适合电机sleep(步进延时):值越小变化越平滑,值越大变化越快step(步长):值越小变化越细腻
4.3 使用硬件PWM
如果希望更精确的PWM控制,可以使用硬件PWM引脚(BCM 12, 13, 18, 19)。以BCM 18(物理引脚12)为例:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM) # 使用BCM编号
PWM_PIN = 18 # BCM 18对应硬件PWM
GPIO.setup(PWM_PIN, GPIO.OUT)
p = GPIO.PWM(PWM_PIN, 1000) # 1kHz频率
p.start(0)
try:
while True:
for duty in range(0, 101, 1):
p.ChangeDutyCycle(duty)
time.sleep(0.01)
for duty in range(100, -1, -1):
p.ChangeDutyCycle(duty)
time.sleep(0.01)
except KeyboardInterrupt:
pass
finally:
p.stop()
GPIO.cleanup()
第五部分:传感器实战
5.1 温度传感器DHT11
DHT11是最常用的温湿度传感器之一,单总线通信。
硬件连接:
- VCC → 3.3V(物理引脚1)
- GND → GND
- DATA → GPIO引脚(如物理引脚29,BCM 5)
安装依赖库:
sudo pip3 install Adafruit-DHT
Python代码:
#!/usr/bin/python
# coding:utf-8
import Adafruit_DHT
import time
DHT_SENSOR = Adafruit_DHT.DHT11
DHT_PIN = 5 # BCM编号
print("读取DHT11温湿度数据")
try:
while True:
humidity, temperature = Adafruit_DHT.read(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
print(f"温度: {temperature:.1f}°C 湿度: {humidity:.1f}%")
else:
print("读取失败,重试...")
time.sleep(2)
except KeyboardInterrupt:
print("程序终止")
5.2 超声波测距模块HC-SR04
通过发出超声波并接收回波来测量距离。
硬件连接:
- VCC → 5V(物理引脚2或4)
- GND → GND
- TRIG → GPIO引脚(如物理引脚31)
- ECHO → GPIO引脚(需注意3.3V电平兼容)
⚠️ 注意:HC-SR04的ECHO引脚输出5V信号,需要用电阻分压或电平转换模块,否则会损坏树莓派。
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
TRIG = 31
ECHO = 33
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
def get_distance():
GPIO.output(TRIG, GPIO.LOW)
time.sleep(0.000002)
GPIO.output(TRIG, GPIO.HIGH)
time.sleep(0.000010)
GPIO.output(TRIG, GPIO.LOW)
# 等待ECHO变高
while GPIO.input(ECHO) == GPIO.LOW:
pulse_start = time.time()
# 等待ECHO变低
while GPIO.input(ECHO) == GPIO.HIGH:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * 17150 # 声速343m/s,往返除以2
return distance
print("超声波测距开始")
try:
while True:
dist = get_distance()
print(f"距离: {dist:.1f} cm")
time.sleep(0.5)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
5.3 光敏传感器
使用光敏电阻和ADC(模数转换器)读取光照强度。如果需要读取模拟信号,可使用MCP3008等ADC芯片。
硬件连接(使用MCP3008,通过SPI通信):
- MCP3008 VDD → 3.3V
- MCP3008 VREF → 3.3V
- MCP3008 AGND → GND
- MCP3008 CLK → GPIO 11(SPI CLK)
- MCP3008 DOUT → GPIO 9(SPI MISO)
- MCP3008 DIN → GPIO 10(SPI MOSI)
- MCP3008 CS → GPIO 8(SPI CE0)
安装依赖:
sudo pip3 install spidev
Python代码:
#!/usr/bin/python
# coding:utf-8
import spidev
import time
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
# 发送读取命令
r = spi.xfer2([1, (8 + channel) << 4, 0])
adc_value = ((r[1] & 3) << 8) + r[2]
return adc_value
try:
while True:
light_value = read_adc(0)
print(f"光照值: {light_value}")
time.sleep(0.5)
except KeyboardInterrupt:
print("程序终止")
finally:
spi.close()
第六部分:中断与事件检测
使用 GPIO.add_event_detect() 可以在引脚状态变化时触发回调函数,无需循环轮询,效率更高。
6.1 事件检测基础
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
BUTTON_PIN = 31
LED_PIN = 33
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)
def button_callback(channel):
print("按钮按下!")
GPIO.output(LED_PIN, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(LED_PIN, GPIO.LOW)
# 检测下降沿触发
GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING,
callback=button_callback,
bouncetime=200) # 消抖时间200ms
print("等待按钮事件...")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
6.2 多种边沿触发方式
| 触发方式 | 说明 |
|---|---|
GPIO.RISING | 检测上升沿(低电平→高电平) |
GPIO.FALLING | 检测下降沿(高电平→低电平) |
GPIO.BOTH | 检测上升沿和下降沿 |
6.3 同时检测多个引脚
GPIO.add_event_detect(31, GPIO.FALLING, callback=func1, bouncetime=200)
GPIO.add_event_detect(33, GPIO.RISING, callback=func2, bouncetime=200)
第七部分:扩展库与替代方案
7.1 常用GPIO库对比
| 库名 | 特点 | 适用场景 |
|---|---|---|
| RPi.GPIO | 最基础,预装,简单易用 | 新手入门,简单项目 |
| gpiozero | 更高级的封装,对象化接口 | 推荐新手,更Pythonic |
| pigpio | 硬件PWM,精确时序,支持网络控制 | 需要高精度PWM或远程控制 |
| WiringPi | 源自Arduino风格,C/Python支持 | Arduino用户迁移 |
| periphery | 跨平台,支持多种接口 | 需要跨平台兼容 |
7.2 gpiozero示例(更简洁)
gpiozero是官方推荐的高级库,接口更加友好。
安装:
sudo apt install python3-gpiozero
点亮LED:
from gpiozero import LED
from time import sleep
led = LED(17) # BCM编号
while True:
led.on()
sleep(1)
led.off()
sleep(1)
按钮控制LED:
from gpiozero import LED, Button
from signal import pause
led = LED(17)
button = Button(2)
button.when_pressed = led.on
button.when_released = led.off
pause()
PWM呼吸灯:
from gpiozero import PWMLED
from time import sleep
led = PWMLED(17)
while True:
led.value = 0.0
sleep(1)
for i in range(0, 101, 1):
led.value = i / 100
sleep(0.02)
for i in range(100, -1, -1):
led.value = i / 100
sleep(0.02)
7.3 pigpio高级应用
适用于需要精确PWM或远程网络控制的场景。
启动pigpiod服务:
sudo systemctl enable pigpiod
sudo systemctl start pigpiod
Python示例:
import pigpio
import time
pi = pigpio.pi()
pi.set_mode(17, pigpio.OUTPUT)
# 硬件PWM输出
pi.hardware_PWM(12, 1000, 500000) # 1kHz, 50%占空比
# 读取GPIO
state = pi.read(17)
pi.stop()
第八部分:安全与最佳实践
8.1 电气安全
| 原则 | 说明 |
|---|---|
| 3.3V逻辑电平 | 树莓派GPIO是3.3V逻辑电平,连接5V设备会导致永久损坏 |
| 限流电阻 | 所有LED必须串联220Ω-1kΩ的限流电阻 |
| 电流限制 | 每个GPIO引脚最大输出电流约16mA,所有引脚总和不超过50mA |
| 电源设计 | 驱动电机等大功率设备必须使用外接电源和驱动电路 |
| 电平转换 | 连接5V传感器时使用电平转换模块(如TXS0108E) |
8.2 软件最佳实践
- 使用
try...except...finally:确保GPIO.cleanup()始终被执行 - 设置
GPIO.setwarnings(False):避免重复引脚设置警告 - 合理使用上拉/下拉电阻:避免引脚浮空导致信号不稳定
- 消抖处理:机械开关/按钮必须做消抖(软件延时或硬件电容)
- 避免阻塞循环:使用事件检测替代轮询,提高响应效率
8.3 常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| LED不亮 | 引脚接错或电阻太大 | 检查接线,减少电阻 |
| 引脚没有权限 | 未使用sudo运行 | sudo python script.py |
| 信号不稳定 | 引脚浮空 | 启用上拉/下拉电阻 |
| 按钮误触发 | 机械抖动 | 增加消抖时间 bouncetime=200 |
| GPIO已占用 | 上次未清理 | 运行 GPIO.cleanup() 或重启 |
第九部分:项目实战
9.1 智能交通灯系统
使用3个LED模拟交通灯逻辑。
硬件连接:
- 红灯 → 物理引脚33
- 黄灯 → 物理引脚31
- 绿灯 → 物理引脚29
- 按钮(行人过街)→ 物理引脚27
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
RED = 33
YELLOW = 31
GREEN = 29
BUTTON = 27
GPIO.setup(RED, GPIO.OUT)
GPIO.setup(YELLOW, GPIO.OUT)
GPIO.setup(GREEN, GPIO.OUT)
GPIO.setup(BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def traffic_light_state(state):
GPIO.output(RED, GPIO.LOW)
GPIO.output(YELLOW, GPIO.LOW)
GPIO.output(GREEN, GPIO.LOW)
if state == "red":
GPIO.output(RED, GPIO.HIGH)
elif state == "yellow":
GPIO.output(YELLOW, GPIO.HIGH)
elif state == "green":
GPIO.output(GREEN, GPIO.HIGH)
def pedestrian_crossing():
print("行人过街请求")
# 黄灯闪烁
for i in range(3):
traffic_light_state("yellow")
time.sleep(0.5)
traffic_light_state("off")
time.sleep(0.5)
# 红灯
traffic_light_state("red")
time.sleep(3)
# 恢复绿灯
traffic_light_state("green")
print("交通灯系统启动")
traffic_light_state("green")
try:
while True:
# 检测按钮
if GPIO.input(BUTTON) == GPIO.LOW:
pedestrian_crossing()
time.sleep(1)
time.sleep(0.1)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
9.2 家庭安全报警系统
使用PIR人体红外传感器和蜂鸣器。
硬件连接:
- PIR传感器 VCC → 5V(物理引脚2)
- PIR传感器 GND → GND
- PIR传感器 OUT → GPIO(如物理引脚29)
- 蜂鸣器 → GPIO(如物理引脚31)
Python代码:
#!/usr/bin/python
# coding:utf-8
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
PIR_PIN = 29
BUZZER_PIN = 31
GPIO.setup(PIR_PIN, GPIO.IN)
GPIO.setup(BUZZER_PIN, GPIO.OUT, initial=GPIO.LOW)
def alarm():
for i in range(3):
GPIO.output(BUZZER_PIN, GPIO.HIGH)
time.sleep(0.2)
GPIO.output(BUZZER_PIN, GPIO.LOW)
time.sleep(0.1)
print("安防系统启动,检测到移动将报警")
try:
while True:
if GPIO.input(PIR_PIN) == GPIO.HIGH:
print("检测到移动!")
alarm()
time.sleep(2)
time.sleep(0.1)
except KeyboardInterrupt:
print("程序终止")
finally:
GPIO.cleanup()
掌握了这些核心概念、工具和实践案例,你就为更复杂的树莓派硬件项目(如机器人控制、智能家居、物联网设备等)打下了坚实的基础。现在,拿出你的树莓派和传感器,开始你的硬件编程之旅吧!
&spm=1001.2101.3001.5002&articleId=163419340&d=1&t=3&u=cdb55e92bfd545e5bc3f78500ef8cf06)
492

被折叠的 条评论
为什么被折叠?



