核心目标:掌握 STM32 定时器的核心用法 —— 用定时器中断实现 “非阻塞精确延时”(替代HAL_Delay)、用 PWM 输出控制 LED 亮度 / 电机转速,理解定时器在嵌入式中的核心价值(精准计时、外设驱动)。
一、定时器原理:嵌入式的 “精准时钟”(30 分钟)
STM32 的定时器是片上外设,本质是 “可编程计数器”,通过计数时钟脉冲实现精准计时,比HAL_Delay(阻塞式)更灵活、精准,核心用途:
- 精确延时(非阻塞,不占用 CPU);
- 生成 PWM 波(控制 LED 亮度、电机转速、舵机角度);
- 频率测量、脉冲计数(如检测传感器脉冲)。
1. 定时器分类(STM32F103 为例,新手先掌握这 2 种)
- 通用定时器(TIM2-TIM5):最常用,支持定时中断、PWM 输出,16 位计数器(计数范围 0-65535);
- 高级定时器(TIM1、TIM8):功能更多(如死区控制),适合电机控制,新手先聚焦通用定时器。
2. 定时中断核心逻辑(记牢!)
- 配置定时器时钟(STM32F103 默认 APB1 时钟为 72MHz);
- 设置预分频器(PSC):将时钟分频,降低计数频率(如 72MHz÷7200=10kHz,即每 100us 计数一次);
- 设置自动重载值(ARR):计数器计数到 ARR 后,自动清零并触发中断(如 ARR=100,即 100×100us=10ms 触发一次中断);
- 使能中断并编写中断服务函数(ISR):中断触发时执行自定义逻辑(如翻转 LED)。
3. PWM 核心概念
- PWM(脉冲宽度调制):通过周期性高低电平的占空比(高电平时间 / 周期)控制输出量;
- 占空比:高电平占一个周期的百分比(0%= 全低,50%= 高低各半,100%= 全高);
- 嵌入式场景:占空比 50%→LED 半亮,占空比 100%→LED 全亮,占空比 0%→LED 熄灭。
二、实操 1:定时器中断实现非阻塞 1sLED 闪烁(50 分钟)
目标:用 TIM3 定时器中断实现 1s 翻转一次 LED,替代HAL_Delay(非阻塞,CPU 可同时做其他事)。
步骤 1:CubeIDE 配置定时器
- 新建工程 “Timer_Interrupt”,选择 STM32F103C8T6;
- 配置 GPIO:PC13 设为 GPIO_Output(LED);
- 配置定时器(左侧 “Timers→TIM3”):
- Mode:选择 “Internal Clock”(内部时钟驱动);
- 预分频器(Prescaler):填 7199(72MHz÷(7199+1)=10kHz,计数周期 100us);
- 自动重载值(Counter Period):填 9999(100us×(9999+1)=1000000us=1s,即 1s 触发一次中断);
- 使能中断:点击 “NVIC Settings”,勾选 “TIM3 global interrupt”,优先级默认;
- 生成初始化代码(Project→Generate Code)。
步骤 2:编写中断逻辑
- 打开
main.c,定义全局变量(记录中断次数):c
/* USER CODE BEGIN 2 */ uint32_t timer_count = 0; // 定时器中断计数 /* USER CODE END 2 */ - 在
main函数中启动定时器:c
/* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim3); // 启动TIM3定时器中断 /* USER CODE END 2 */ - 重写定时器中断回调函数(在
main.c的 “USER CODE BEGIN 4” 区域):c
/* 定时器中断回调函数:TIM3触发中断时执行 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM3) // 确认是TIM3触发的中断 { timer_count++; // 每次中断计数+1 if (timer_count >= 1) // 计数1次(即1s) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转LED timer_count = 0; // 重置计数 } } } - 主循环中添加其他逻辑(验证非阻塞):
c
while (1) { /* 主循环可同时执行其他任务,不受延时影响 */ printf("主循环运行中...\n"); // 模拟其他任务(需配置串口,后续可补充) HAL_Delay(200); // 这里的延时不影响LED的1s闪烁 /* USER CODE END WHILE */ }
步骤 3:下载测试
程序下载后,LED 每 1s 闪烁一次,同时主循环持续打印信息 —— 证明定时器中断是 “非阻塞” 的,CPU 可并行处理多个任务。
三、实操 2:定时器 PWM 输出控制 LED 亮度(50 分钟)
目标:用 TIM4 定时器生成 PWM 波,通过调节占空比,实现 LED 从暗到亮、从亮到暗的渐变。
步骤 1:CubeIDE 配置 PWM
- 新建工程 “Timer_PWM”,选择 STM32F103C8T6;
- 配置 GPIO:选择一个支持 PWM 的引脚(如 PB6,对应 TIM4_CH1),设置为 “PWM Generation CH1”;
- 配置定时器(左侧 “Timers→TIM4”):
- Mode:Internal Clock;
- 预分频器(Prescaler):填 7199(72MHz÷7200=10kHz,计数周期 100us);
- 自动重载值(Counter Period):填 99(100us×100=10ms,PWM 周期 10ms,频率 100Hz,适合 LED);
- PWM 模式:点击 “Configuration→PWM Generation CH1”,Mode 选 “PWM Generation CH1”,Pulse(初始占空比)填 0(初始 LED 熄灭);
- 生成初始化代码。
步骤 2:编写 PWM 占空比调节逻辑
- 在
main.c中定义占空比变量:c
/* USER CODE BEGIN 2 */ uint16_t duty_cycle = 0; // 占空比(0-99,对应0%-100%) int8_t step = 1; // 占空比调节步长(1=递增,-1=递减) /* USER CODE END 2 */ - 启动 PWM 输出(
main函数中):c
/* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // 启动TIM4通道1的PWM输出 /* USER CODE END 2 */ - 主循环中调节占空比:
c
while (1) { /* 调节占空比:0→99递增(LED变亮),99→0递减(LED变暗) */ duty_cycle += step; if (duty_cycle >= 99) step = -1; // 达到最大占空比,开始递减 if (duty_cycle <= 0) step = 1; // 达到最小占空比,开始递增 /* 设置PWM占空比:__HAL_TIM_SET_COMPARE(定时器句柄, 通道, 占空比) */ __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, duty_cycle); HAL_Delay(50); // 控制渐变速度(50ms调节一次,肉眼可见渐变) /* USER CODE END WHILE */ }
步骤 3:下载测试
将 LED 正极接 PB6 引脚,负极接 GND(或直接使用板载 LED 对应的 PWM 引脚),下载后能看到 LED 从暗逐渐变亮,再从亮逐渐变暗,实现平滑渐变。
四、第六天必掌握的 3 个关键知识点(10 分钟自测)
- 定时器中断核心参数:预分频器(PSC)和自动重载值(ARR),定时时间 =(PSC+1)×(ARR+1)÷ 时钟频率;
- 非阻塞延时的优势:CPU 可同时执行其他任务,比
HAL_Delay更高效; - PWM 占空比调节:通过
__HAL_TIM_SET_COMPARE函数修改,范围是 0 到 ARR 值(对应 0%-100%)。
总结
今天掌握了嵌入式 “精准计时” 和 “模拟量控制” 的核心工具!定时器中断解决了HAL_Delay的阻塞问题,PWM 是控制 LED 亮度、电机转速的基础(后续舵机、直流电机控制都依赖 PWM)。


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



