一 本章简介
本章是「定时器与 PWM基础」系列教程的总览和基础知识介绍。STM32F407 内部拥有多达 14 个硬件定时器,它们不仅能做简单的延时计时,更是 PWM 输出、电机控制、编码器解码等功能的核心硬件基础。掌握定时器和 PWM 的使用,是从 点灯 迈向 控制 的关键一步。
1.1 学习目标
| 序号 | 学习目标 | 重要程度 |
|---|---|---|
| 1 | 理解定时器的基本工作原理(预分频、自动重装载、计数) | ⭐⭐⭐⭐⭐ |
| 2 | 理解 PWM 的核心概念(频率、占空比、脉宽) | ⭐⭐⭐⭐⭐ |
| 3 | 掌握 MicroPython 中 pyb.Timer 的基本用法 | ⭐⭐⭐⭐⭐ |
| 4 | 了解 STM32F407 定时器资源分布和时钟来源 | ⭐⭐⭐⭐ |
| 5 | 了解定时器的编码器模式 | ⭐⭐⭐⭐ |
1.2 重点提示
- STM32F407 的 14 个定时器分为高级定时器(TIM1/TIM8)、通用定时器(TIM2,TIM5,TIM9~TIM14)和基本定时器(TIM6/TIM7),功能和性能各有不同。
- APB1 总线上的定时器(TIM2,TIM7,TIM12~TIM14)时钟为 84MHz;APB2 总线上的定时器(TIM1、TIM8~TIM11)时钟为 168MHz。MicroPython 的
Timer类会自动处理时钟源选择,不需要像在C语言里面我们再手动计算了。 - 同一个定时器的多个通道共享频率(由 PSC 和 ARR 决定),但每个通道可以独立设置占空比。
- 部分定时器通道与筑基学习板的外设存在引脚复用冲突,使用前请确认拨码开关状态。
1.3 基础概念与术语
- 定时器(Timer):单片机内部的硬件计数器,以固定频率递增或递减计数,到达设定值时产生事件(中断、PWM 翻转等)。
- 预分频器(Prescaler,PSC):将输入时钟分频后再送给计数器。例如 84MHz 时钟经过 PSC=83 分频后,计数器时钟为 1MHz(每微秒计数一次)。
- 自动重装载值(Auto-Reload Register,ARR):计数器的上限值。计数器从 0 计到 ARR 后归零,产生一个溢出事件。定时器频率 = 时钟 / (PSC+1) / (ARR+1)。
- PWM(Pulse Width Modulation,脉冲宽度调制):定时器的一种输出模式,在每个计数周期内,根据比较值(CCR)自动翻转引脚电平,产生占空比可调的方波。
- 占空比(Duty Cycle):PWM 信号中高电平时间占整个周期的百分比。
- 编码器模式(Encoder Mode):定时器的一种特殊输入模式,利用两个通道接收 A/B 相正交信号,硬件自动完成方向判断和脉冲计数。
二 STM32F407 定时器资源概览
2.1 定时器分类
| 类型 | 定时器 | 位数 | 通道数 | 总线 | 时钟 | 特殊功能 |
|---|---|---|---|---|---|---|
| 高级 | TIM1、TIM8 | 16 位 | 4 | APB2 | 168MHz | 互补输出、死区、刹车 |
| 通用(32位) | TIM2、TIM5 | 32 位 | 4 | APB1 | 84MHz | 编码器模式 |
| 通用(16位) | TIM3、TIM4 | 16 位 | 4 | APB1 | 84MHz | 编码器模式 |
| 通用(16位) | TIM9~TIM14 | 16 位 | 1~2 | APB1/APB2 | 84/168MHz | 简单 PWM |
| 基本 | TIM6、TIM7 | 16 位 | 0 | APB1 | 84MHz | 仅计时,触发 DAC |
2.2 本系列教程使用的定时器
| 定时器 | 用途 | 引脚 | 涉及资源 |
|---|---|---|---|
| TIM10_CH1 | LED 呼吸灯 PWM | PB8 | LED 呼吸灯 |
| TIM13_CH1 | 无源蜂鸣器 PWM | PA6 | 无源蜂鸣器 |
| TIM12_CH1/CH2 | 舵机 PWM / 电机 2 PWM | PB14/PB15 | 舵机 / 直流电机 |
| TIM9_CH1/CH2 | 电机 1 PWM | PE5/PE6 | 直流电机 |
| TIM4(编码器模式) | EC11 / 电机编码器 2 | PD12/PD13 | EC11 / 编码器测速 |
| TIM3(编码器模式) | 电机编码器 1 | PB4/PC7 | 编码器测速 |
NOTE
LED 呼吸灯使用 TIM10_CH1(而非 TIM4_CH3)驱动 PB8,这是因为 TIM4 在编码器章节中会被用于编码器模式(EC11 / 电机编码器 2),两者不能同时使用。选择 TIM10 可以避免定时器资源冲突。
三 MicroPython 定时器基础用法
3.1 创建定时器
python
import pyb
# 方式一:指定频率(推荐,最简单)
tim = pyb.Timer(2, freq=1000) # TIM2,频率 1kHz
# 查看定时器参数
print("预分频:", tim.prescaler())
print("周期:", tim.period())
print("频率:", tim.freq())
# 方式二:手动指定预分频和周期(精确控制)
tim = pyb.Timer(4, prescaler=83, period=999)
# APB1 Timer = 84MHz
# 频率 = 84MHz / (83+1) / (999+1) = 1000Hz = 1kHz
# 查看定时器参数
print("预分频:", tim.prescaler())
print("周期:", tim.period())
print("频率:", tim.freq())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.2 定时器回调(周期中断)
python
import pyb
led = pyb.LED(1)
# 创建定时器,频率 2Hz(每秒触发 2 次)
tim = pyb.Timer(2, freq=2)
tim.callback(lambda t: led.toggle())
# LED 在后台自动闪烁,REPL 仍然可用
# 停止:tim.callback(None); tim.deinit()1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
WARNING
定时器回调函数在中断上下文中执行,有严格限制:
- 禁止:
print()、time.sleep()、内存分配(创建列表/字典/字符串)、浮点运算 - 允许:修改全局变量、置标志位、直接操作引脚
违反这些规则可能导致系统崩溃或行为异常。
3.3 PWM 输出
python
from pyb import Pin, Timer
# 配置引脚为定时器复用功能
pin = Pin('PB8', Pin.AF_PP, af=3) # AF3 = TIM10
# 创建定时器,设置 PWM 频率
tim = Timer(10, freq=1000) # 1kHz
# 创建 PWM 通道
ch = tim.channel(1, Timer.PWM, pin=pin)
# 设置占空比(0~100%)
ch.pulse_width_percent(50) # 50% 占空比
# 也可以直接设置脉宽值(0 ~ period)
# ch.pulse_width(500) # 如果 period=999,则占空比约 50%1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.4 编码器模式
python
from pyb import Pin, Timer
# 配置 A/B 相引脚
Pin('PD12', mode=Pin.AF_PP, alt=Pin.AF2_TIM4)
Pin('PD13', mode=Pin.AF_PP, alt=Pin.AF2_TIM4)
# 定时器初始化为编码器模式
tim = Timer(4, prescaler=0, period=0xFFFF)
tim.channel(1, Timer.ENC_AB)
while True:
# 读取计数器(顺时针递增,逆时针递减)
print(tim.counter())
time.sleep(0.1)1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
运行上述代码后,确认筑基学习板的拨码开关的BIT6处于OFF状态(默认状态),此处转动天空星核心板右边的EC11旋转编码器就会在REPL终端打印出当前的编码器计数了。
3.5 精确延时与时间测量
python
import pyb
# 微秒级延时
pyb.udelay(100) # 延时 100 微秒
# 毫秒级延时
pyb.delay(500) # 延时 500 毫秒
# 测量代码执行时间
start = pyb.micros()
# ... 你的代码 ...
elapsed = pyb.elapsed_micros(start)
print("耗时: {}us".format(elapsed))1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
四 拨码开关与定时器资源冲突速查
本章节系列教程涉及多个拨码开关设置,这里先提前汇总方便查阅:
| 拨码位 | OFF(默认) | ON | 影响的外设 |
|---|---|---|---|
| BIT4 | 有源蜂鸣器(PA6) | 无源蜂鸣器(PA6 PWM) | 无源蜂鸣器 |
| BIT5 | 舵机接口(PB14/PB15) | 直流电机 2(PB14/PB15) | 舵机 / 直流电机 |
| BIT6 | EC11 编码器(PD12/PD13) | 电机编码器 2(PD12/PD13) | EC11 / 编码器测速 |
IMPORTANT
每次切换实验内容时,请务必检查拨码开关状态。拨码设置错误是最常见的 硬件不工作 原因。
简单记忆:
- 做蜂鸣器实验 → 看 BIT4
- 做舵机或电机 2 实验 → 看 BIT5
- 做 EC11 或电机编码器 2 实验 → 看 BIT6
五 本节参考文档
- MicroPython pyb.Timer 文档:
- MicroPython pyb.Pin 文档:
- STM32F4 参考手册 RM0090(定时器章节):
- 天空星硬件资料(原理图):