一 本章简介
本章以天空星板载 LED(PB2)和筑基学习板 LED(PB8)为例,介绍 MicroPython 中控制 LED 的各种方式,从最简单的点亮/熄灭,到定时器驱动的 PWM 呼吸灯效果。LED 控制是嵌入式开发的经典入门实验,也是验证开发环境是否正常工作的最直接方式。
1.1 学习目标
| 序号 | 学习目标 | 重要程度 |
|---|---|---|
| 1 | 掌握使用 pyb.LED 控制核心板 LED(PB2)的方法 | ⭐⭐⭐⭐⭐ |
| 2 | 掌握使用 Pin 控制筑基学习板 LED(PB8,低电平点亮)的方法 | ⭐⭐⭐⭐⭐ |
| 3 | 能够实现 LED 的定时闪烁效果 | ⭐⭐⭐⭐ |
| 4 | 能够使用 PB8(TIM10_CH1)实现 PWM 呼吸灯效果 | ⭐⭐⭐⭐ |
| 5 | 理解高电平点亮与低电平点亮两种接法的区别 | ⭐⭐⭐⭐⭐ |
1.2 重点提示
- 天空星核心板 LED 连接在 PB2,高电平点亮,低电平熄灭;筑基学习板 LED 连接在 PB8,低电平点亮,高电平熄灭。两者逻辑相反,写代码时务必注意。
pyb.LED(1)中的参数1是 LED 的编号,天空星只有一颗板载 LED,编号为 1,对应 PB2。- 使用
pyb.delay()实现延时时,CPU 处于忙等待状态,无法做其他事情。如果需要在延时期间处理其他任务,应使用定时器中断。 - PB8 支持 PWM 输出(TIM10_CH1),可以直接对筑基学习板上的 LED 做呼吸灯效果,无需外接额外硬件。
1.3 硬件说明
1.3.1 单片机控制 LED 的两种接法
TIP
看本小节之前,先回顾上一章的 3.2.4 输出控制(P-MOS管和N-MOS管) ,理解一下GPIO中推挽模式里上下MOS管的配合,这里会更好理解。
在电路原理图中,我们一般会看到两种接法:
- 灌电流(Sink Current)—— 低电平点亮
- 接法:LED 正极接电源(VCC),负极串联电阻后接单片机引脚(GPIO)。
- 原理:当 GPIO 输出低电平(0)时,电流从 VCC -> LED -> GPIO -> GND,形成回路,灯亮。
- 优点:单片机引脚(GPIO)的吸入电流能力通常比输出电流能力强。

- 拉电流(Source Current)—— 高电平点亮
- 接法:LED 正极串联电阻接 GPIO,负极接 GND。
- 原理:当 GPIO 输出高电平(1)时,电流从 GPIO -> 电阻 -> LED -> GND,形成回路,灯亮。
- 现状:现代单片机(如 STM32、GD32 等)推挽输出能力很强,这种接法也完全没问题,且逻辑上更符合直觉(1就是亮,0就是灭)。

TIP
在看原理图时,一定要先确认是低电平亮还是高电平亮,否则你的代码逻辑可能是反的!对于天空星核心板上的 PB2,它是拉电流(Source Current)的方式点亮的,也就是高电平点亮;而筑基学习板上的大部分 LED 灯,基本都是采用灌电流(Sink Current)的方式驱动的,也就是低电平点亮。
1.3.2 天空星核心板上的 LED 灯
原理图:

可以看到天空星核心板上我们可以控制的灯的引脚为 PB2。这个引脚输出高电平才能点亮该 LED 灯。
实物图中 LED 的位置:

就在 TYPE-C 旁边,还做了绿色 LED 灯的彩印标识。
1.3.3 天空星筑基学习板上的 LED 灯
原理图:

可以看到筑基学习板上我们可以控制的灯的引脚为 PB8。这个引脚输出低电平才能点亮该 LED 灯。
实物图位置:

二 硬件资源
2.1 LED 资源汇总
| 资源 | 核心板 LED | 筑基学习板 LED |
|---|---|---|
| 引脚 | PB2 | PB8 |
| 点亮电平 | 高电平(3.3V) | 低电平(0V) |
| 熄灭电平 | 低电平(0V) | 高电平(3.3V) |
| pyb.LED 编号 | LED1 | 不支持(需用 Pin) |
| PWM 支持 | 不支持 | 支持(TIM10_CH1) |
| 限流电阻 | 已板载 | 已板载 |
三 软件设计
3.1 基础部分
3.1.1 控制核心板 LED(PB2,高电平点亮)
pyb.LED 是 MicroPython 为 STM32 平台提供的 LED 专用类,使用最为简便:
import pyb
led = pyb.LED(1) # LED1 对应 PB2
# 点亮
led.on()
# 熄灭
led.off()
# 翻转状态(亮变灭,灭变亮)
led.toggle()
# 查询当前状态(1=亮,0=灭)
print(led.intensity())2
3
4
5
6
7
8
9
10
11
12
13
14
15
也可以直接用 Pin 操作:
from pyb import Pin, delay
# 配置 PB2 为推挽输出,高电平点亮
led_pin = Pin('PB2', Pin.OUT_PP)
while True:
led_pin.high() # 点亮
delay(500)
led_pin.low() # 熄灭
delay(500)2
3
4
5
6
7
8
9
10
3.1.2 控制筑基学习板 LED(PB8,低电平点亮)
PB8 是低电平点亮,逻辑与 PB2 相反,pyb.LED 不支持该引脚,需要直接用 Pin 操作:
from pyb import Pin, delay
# 配置 PB8 为推挽输出,低电平点亮
led_pb8 = Pin('PB8', Pin.OUT_PP)
# 点亮:输出低电平
led_pb8.low()
delay(500)
# 熄灭:输出高电平
led_pb8.high()
delay(500)2
3
4
5
6
7
8
9
10
11
12
WARNING
PB8 是低电平点亮,low() 是亮,high() 是灭,与 PB2 逻辑完全相反。初学者容易在这里搞混,写代码时一定要注意。
3.1.3 同时控制两颗 LED 闪烁
# 两颗 LED 交替闪烁
# 编写者: LCKFB-YZH
from pyb import Pin, delay
led_pb2 = Pin('PB2', Pin.OUT_PP) # 核心板 LED,高电平亮
led_pb8 = Pin('PB8', Pin.OUT_PP) # 筑基学习板 LED,低电平亮
# 初始状态:全部熄灭
led_pb2.low()
led_pb8.high()
while True:
# PB2 亮,PB8 灭
led_pb2.high()
led_pb8.high()
delay(500)
# PB2 灭,PB8 亮
led_pb2.low()
led_pb8.low()
delay(500)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
3.2 进阶部分
3.2.1 SOS 求救信号(核心板 PB2)
摩尔斯电码中,SOS 是国际通用的求救信号(···---···):
# SOS 求救信号
import pyb
led = pyb.LED(1) # PB2,高电平点亮
DOT = 150 # 短信号时长(ms)
DASH = 450 # 长信号时长(ms)
GAP = 150 # 信号间隔(ms)
LETTER_GAP = 450 # 字母间隔(ms)
WORD_GAP = 2000 # 单词间隔(ms)
def blink(duration):
led.on()
pyb.delay(duration)
led.off()
pyb.delay(GAP)
while True:
for _ in range(3): blink(DOT) # S: · · ·
pyb.delay(LETTER_GAP)
for _ in range(3): blink(DASH) # O: — — —
pyb.delay(LETTER_GAP)
for _ in range(3): blink(DOT) # S: · · ·
pyb.delay(WORD_GAP)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3.2.2 定时器驱动闪烁(非阻塞)
使用定时器中断实现非阻塞的 LED 闪烁,主循环可以同时处理其他任务:
# 定时器驱动 LED 闪烁(非阻塞)
import pyb
led = pyb.LED(1) # PB2
# 创建定时器 2,频率 2Hz(每秒触发 2 次)
tim = pyb.Timer(2, freq=2)
tim.callback(lambda t: led.toggle())
# 主循环可以做其他事情,LED 在后台自动闪烁
print("LED 在后台闪烁,主循环继续运行...")
counter = 0
while True:
counter += 1
print("主循环计数:", counter)
pyb.delay(1000)
# 停止定时器:
# tim.callback(None)
# tim.deinit()2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.2.3 PWM 呼吸灯(筑基学习板 PB8)
PB8 支持 TIM10_CH1 的 PWM 输出,可以直接对筑基学习板上的 LED 做呼吸灯效果。
NOTE
PB8 是低电平点亮,所以 PWM 占空比越低,LED 越亮;占空比越高,LED 越暗。这与高电平点亮的 LED 逻辑相反,代码中需要做取反处理。
# PWM 呼吸灯 —— 筑基学习板 PB8(TIM10_CH1,低电平点亮)
from pyb import Pin, Timer
import time
# 配置 PB8 为 TIM10_CH1 的 PWM 输出
# AF3 = TIM10,CH1 对应 PB8
pin = Pin('PB8', Pin.AF_PP, af=3)
tim = Timer(10, freq=1000) # PWM 频率 1kHz
ch = tim.channel(1, Timer.PWM, pin=pin)
print("呼吸灯启动(PB8,低电平点亮)")
try:
while True:
# 亮度从暗到亮:占空比从 100% 降到 0%(低电平点亮,占空比越低越亮)
for duty in range(100, -1, -2):
ch.pulse_width_percent(duty)
time.sleep_ms(20)
# 亮度从亮到暗:占空比从 0% 升到 100%
for duty in range(0, 101, 2):
ch.pulse_width_percent(duty)
time.sleep_ms(20)
except KeyboardInterrupt:
ch.pulse_width_percent(100) # 停止时熄灭(高电平=灭)
tim.deinit()
print("已停止")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
TIP
PWM 频率设置为 1kHz 时,人眼感知不到闪烁,只会看到亮度平滑变化。如果 PWM 频率太低(如 10Hz),会看到明显的闪烁感。
四 常见问题
Q: 代码运行了,但 LED 没有任何反应?
先确认你控制的是哪颗 LED:
- 核心板 PB2:
pyb.LED(1).on()或Pin('PB2', Pin.OUT_PP).high() - 筑基学习板 PB8:
Pin('PB8', Pin.OUT_PP).low()(注意是low())
Q: 筑基学习板的 LED 逻辑感觉反了,high() 反而灭了?
这是正常的。PB8 是低电平点亮(灌电流接法),low() = 亮,high() = 灭。参考 1.3.1 节的两种接法说明。
Q: PWM 呼吸灯运行后,亮度变化方向感觉反了?
PB8 低电平点亮,占空比越低 LED 越亮。如果感觉方向反了,把 pulse_width_percent(duty) 改为 pulse_width_percent(100 - duty) 即可。
Q: 使用定时器后 REPL 没有响应?
定时器回调函数中如果有耗时操作或错误,可能导致系统异常。检查回调函数是否足够简短,只做翻转操作,不要在回调里调用 print()。
五 本节参考文档
- MicroPython pyb.LED 文档:
- MicroPython pyb.Timer 文档:
- 天空星硬件资料(原理图):