【树莓派学习】001 PWM实验

实验名称:树莓派PWM信号生成与示波器分析

实验目标

  1. 通过Python编程,让树莓派生成一个可调占空比的PWM信号。
  2. 用示波器捕捉并测量该PWM信号的频率和占空比,验证软件控制与硬件输出的一致性。

所需设备

  1. 硬件
    • 树莓派 (任何型号,已安装系统)
    • MacBook
    • 数字示波器
    • 面包板、LED灯、220Ω电阻、杜邦线若干
    • USB转TTL串口模块 (可选,用于串口调试)
  2. 软件
    • MacBook上的终端 (用于SSH或串口连接)
    • 树莓派上的Python3及 RPi.GPIO

具体步骤

第一步:硬件连接

  1. 树莓派GPIO连接
    • 将LED的正极(长脚)通过一个220Ω的限流电阻,连接到树莓派的 GPIO 18 (物理引脚12)。这是因为GPIO 18支持硬件PWM。
    • 将LED的负极(短脚)连接到树莓派的 GND (物理引脚6)。
  2. 示波器连接
    • 将示波器探头的尖端钩在 GPIO 18 引脚上。
    • 将示波器探头的接地夹夹在树莓派的 GND 引脚上。
  3. MacBook连接树莓派
    • 方法A (推荐,使用SSH):确保MacBook和树莓派在同一个Wi-Fi下,在Mac终端输入:ssh pi@<你的树莓派IP地址>,然后输入密码。
    • 方法B (使用串口):通过USB转TTL模块连接树莓派的UART引脚,在Mac上用 screen 命令连接。

连接示意图:

1
2
3
树莓派 GPIO 18 ---[220Ω电阻]--- LED(+) --- LED(-) --- GND
|
+--- (连接至示波器探头)

1. 命令行工具:pinout

这是最直接、最推荐的方法。

在你的树莓派终端中,直接输入:

1
pinout
这个命令会返回一个清晰的ASCII艺术图,明确标出了: - 物理引脚编号 (1, 2, 3...) - BCM GPIO编号 (GPIO 2, GPIO 3...),这是 RPi.GPIO 库默认使用的编号。 - 电源引脚 (3.3V, 5V, GND) - 特殊功能引脚 (例如,我们实验要用到的GPIO 18)

示例输出(部分):

1
2
3
4
5
6
7
8
9
10
11
12
13
   3V3  (1) ◉◉ (2)  5V
GPIO2 (3) ◉◉ (4) 5V
GPIO3 (5) ◉◉ (6) GND
GPIO4 (7) ◉◉ (8) GPIO14
GND (9) ◉◉ (10) GPIO15
GPIO17 (11) ◉◉ (12) GPIO18 <-- 我们要用的引脚!
GPIO27 (13) ◉◉ (14) GND
GPIO22 (15) ◉◉ (16) GPIO23
3V3 (17) ◉◉ (18) GPIO24
GPIO10 (19) ◉◉ (20) GND
GPIO9 (21) ◉◉ (22) GPIO25
GPIO11 (23) ◉◉ (24) GPIO8
GND (25) ◉◉ (26) GPIO7

从图中可以看到,物理引脚12 对应的就是 BCM GPIO 18

2. GPIO库的Python命令

如果你已经在Python环境中,可以这样验证:

  1. 在树莓派终端输入 python3 进入Python交互环境。
  2. 依次输入以下命令:
    1
    2
    3
    4
    5
    import RPi.GPIO as GPIO
    GPIO.setmode(GPIO.BCM) # 设置为BCM编号模式
    # 将GPIO 18设置为输出模式,这会初始化该引脚
    GPIO.setup(18, GPIO.OUT)
    print("GPIO 18 设置成功!")
    如果没有报错,说明GPIO 18是可用的。

第二步:创建并运行Python脚本

  1. 在树莓派上,创建一个Python文件,例如 pwm_test.py

    1
    vi pwm_test.py

  2. 将以下代码复制进去:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #!/usr/bin/env python3
    import RPi.GPIO as GPIO
    import time
    import atexit

    PWM_FREQUENCY = 1000 # 频率
    PWM_DUTY_CYCLE = 50 # 占空比
    # 全局变量跟踪PWM状态
    pwm_active = False
    pwm_instance = None

    def cleanup_resources():
    """在程序退出时清理资源"""
    global pwm_active, pwm_instance
    if pwm_active and pwm_instance:
    try:
    pwm_instance.stop()
    pwm_active = False
    pwm_instance = None
    except:
    pass
    try:
    GPIO.cleanup()
    except:
    pass

    # 注册退出处理函数
    atexit.register(cleanup_resources)

    try:
    # 设置GPIO
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(18, GPIO.OUT)

    # 创建并启动PWM
    pwm_instance = GPIO.PWM(18, PWM_FREQUENCY)
    pwm_instance.start(PWM_DUTY_CYCLE)
    pwm_active = True

    print(f"PWM已启动,频率{PWM_FREQUENCY}Hz,占空比{PWM_DUTY_CYCLE}%。按 Ctrl+C 停止程序。")

    # 主循环
    while True:
    time.sleep(1)

    except KeyboardInterrupt:
    print("\n程序被用户中断")

    finally:
    cleanup_resources()
    print("资源清理完成")

  3. 保存并退出 (在nano中按 Ctrl+X, 然后按 Y, 最后按 Enter)。

  4. 运行脚本 (需要sudo权限来访问GPIO):

    1
    sudo python3 pwm_test.py
    ### 硬件PWM

方法1:从源码编译安装pigpio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装编译依赖
sudo apt update
sudo apt install python3-pigpio

# 下载并编译pigpio
cd ~
wget https://github.com/joan2937/pigpio/archive/refs/heads/master.zip
unzip master.zip
cd pigpio-master
make -j
sudo make install

# 启动守护进程
sudo pigpiod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python3
import pigpio
import time
import signal
import sys

# 硬件PWM引脚(仅GPIO12, GPIO13, GPIO18, GPIO19支持硬件PWM)
PWM_PIN = 18
FREQUENCY = 1000000 # 1MHz
DUTY_CYCLE = 500000 # 50% (范围: 0-1000000)

pi = pigpio.pi()

def cleanup(signum=None, frame=None):
"""清理资源"""
pi.set_mode(PWM_PIN, pigpio.INPUT)
pi.stop()
print("\n资源清理完成")
sys.exit(0)

# 注册信号处理
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)

try:
# 设置硬件PWM
pi.set_mode(PWM_PIN, pigpio.OUTPUT)
pi.hardware_PWM(PWM_PIN, FREQUENCY, DUTY_CYCLE)

print(f"硬件PWM已启动: GPIO{PWM_PIN}, {FREQUENCY}Hz, 50%占空比")
print("按 Ctrl+C 停止")

while True:
time.sleep(1)

except Exception as e:
print(f"错误: {e}")
cleanup()

**方法2:gpiozero

1
2
# 安装gpiozero(通常已预装)
sudo apt install python3-gpiozero
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
from gpiozero import PWMOutputDevice
import time
import signal
import sys

# 使用GPIO18(硬件PWM引脚)
pwm = PWMOutputDevice(18, frequency=1000)

def cleanup(signum, frame):
pwm.close()
print("\n资源清理完成")
sys.exit(0)

signal.signal(signal.SIGINT, cleanup)

try:
pwm.value = 0.5 # 50%占空比
print("硬件PWM已启动: 1kHz, 50%占空比")
print("按 Ctrl+C 停止")

while True:
time.sleep(1)

except Exception as e:
print(f"错误: {e}")
cleanup()
1
pwm_hw_test.py

第三步:使用示波器测量

  1. 打开示波器。
  2. 将探头连接到 物理引脚12 (GPIO 18)GND
  3. 在示波器上执行 自动设置 或手动调整:
    • 时基:调到 500μs/div 左右,以清晰看到1kHz的周期。
    • 电压刻度:调到 1V/div2V/div
    • 触发:设置为边沿触发,源选择你连接的通道,电平调到约1.6V (3.3V的一半)。
  4. 你应该能立即在屏幕上看到一个稳定的 方波
  5. 进行测量:
    • 频率:使用示波器的测量功能,选择“频率”,读数应接近 1.000 kHz
    • 占空比:选择“占空比”测量,读数应接近 50.0%
    • 电压:高电平应在 3.3V 左右,低电平在 0V

软件PWM

rpi-001-expriment

硬件PWM 10MHz

rpi-001-10M-expriment

树莓派PWM频率对比

软件PWM (RPi.GPIO)

  • 最高频率:约 1-10kHz (实际使用建议 ≤1kHz)
  • 限制因素:Python解释器性能、系统负载
  • 特点:所有GPIO都可用,但精度差、抖动明显

硬件PWM (pigpio/gpiozero)

  • 最高频率:理论上可达 125MHz (树莓派4)
  • 实际可用频率:通常 1kHz - 30MHz
  • 支持引脚:仅 GPIO12, GPIO13, GPIO18, GPIO19

具体频率对比表

方法 最高频率 推荐频率 精度 稳定性
RPi.GPIO软件PWM ~10kHz ≤1kHz
pigpio硬件PWM 125MHz 1kHz-30MHz 极高 优秀
gpiozero硬件PWM 125MHz 1kHz-30MHz 极高 优秀
Linux PWM子系统 125MHz 1kHz-30MHz 极高 优秀

第四步:实验扩展

修改代码中的 pwm.start(50),将 50 改为 10 (10%占空比) 或 90 (90%占空比),重新运行程序。再次用示波器测量,你会看到波形的“高电平”部分明显变短或变长,但频率保持不变。

恭喜你! 你已经成功地用软件生成一个精确的硬件信号,并用示波器完成了验证。这是嵌入式系统调试中最基础的技能之一。