STM32通用定时器输出比较(OC)与PWM模式详解
STM32通用定时器的输出比较(OC)和PWM模式
通用定时器OC & PWM模式详解
1️⃣什么是“输出比较”模式(OC模式)🕰️
想象你有个计时器小朋友,它不停地数数,1、2、3、4、5……
现在你告诉它:“当数到10的时候,给我敲一下桌子!”📢
计时器就会监视自己数的数,一旦到10,就立马敲桌子!这就是“输出比较”模式。
计数器 CNT:一直计数的数字
比较寄存器 CCR:目标数字,敲桌子的时间点
只要 CNT == CCR,就触发“敲桌子”事件,比如切换IO电平,或者发中断。
2️⃣ OC模式有什么作用?🔧
你可以用它做定时开关,比如定时开灯、关灯
还能产生特定波形,比如方波(高低电平交替)
还能产生中断做别的事情
举个例子:当CNT==CCR时,GPIO输出口电平翻转,实现方波!
3️⃣ 什么是PWM?⚡(PWM其实就是OC的升级版)
PWM,全称“脉宽调制”,就是让你的小计时器产生一个“高电平持续时间可调”的波形,为什么?
定时器数到ARR(自动重装载寄存器)周期结束,重新开始
你设置CCR=某个值,代表高电平持续时间
计数器数到CCR时,从高电平切换到低电平
举个简单的图:
|<----- 高电平 Pulse -----|<----- 低电平 ------>|
|<----------- Period ----------->|
占空比 = 高电平时间 / 总周期 = CCR / ARR
你调CCR,就调占空比,灯就能亮得忽明忽暗,这就是呼吸灯的原理!🌬️💡
4️⃣ STM32的PWM模式有哪些?🤔
PWM1模式(TIM_OCMODE_PWM1)
CNT < CCR 输出高电平,CNT >= CCR 输出低电平
PWM2模式(TIM_OCMODE_PWM2)
CNT < CCR 输出低电平,CNT >= CCR 输出高电平
一般用PWM1就行。
5️⃣ 实际配置步骤🏗️
-
设置时钟预分频PSC
-
比如72MHz主频,预分频72,得到1MHz计数频率(1us计数一次)
-
设置计数周期ARR
-
比如设置999,计数从0计数到999,周期1000us=1ms → 频率1kHz
-
设置比较寄存器CCR
-
例如500,占空比50%
-
配置GPIO为复用推挽输出(AF_PP)
-
使能TIM通道对应的GPIO输出PWM波形
-
启动PWM输出
6️⃣ 小结表格✨
| 参数 | 作用 | 举例 |
|---|---|---|
| PSC | 分频主时钟,调节计数频率 | 71预分频 → 1MHz计数频率 |
| ARR | 自动重装载,定时器计数周期(周期) | 999 → 1ms周期 |
| CCR | 比较寄存器,决定高电平时间(占空比) | 500 → 50%占空比 |
| OCMode | 选择PWM模式:PWM1或PWM2 | 一般用PWM1 |
| GPIO配置 | 设为复用推挽输出,保证波形输出 | PB5作为TIM3_CH2输出 |
7️⃣ 代码演示,帮你连起来🚀
用 STM32CubeMX + HAL库 来实现 通用定时器的PWM输出,并且需要配合 Cube自动生成代码 的讲解。👌
用 STM32CubeMX + HAL 实现 TIM3 CH2 PWM 呼吸灯(基于Cube自动生成代码)
1. CubeMX配置步骤(图形界面操作)
打开CubeMX,选择你的芯片 STM32F103ZETx
Clock Configuration:确认时钟配置正常,比如 HSE 8MHz,PLL乘法后 72MHz
Pinout:找到 TIM3_CH2 的引脚,比如 PB5,设置为 TIM3_CH2(复用功能)
Peripherals > TIM3
Mode:PWM Generation CH2
Prescaler:设置为 71 (分频72,得到1MHz计数时钟)
Counter Period (ARR):设置为 999 (周期1ms,即1kHz PWM频率)
NVIC:启用定时器中断(可选,呼吸灯不一定用中断)
Project Manager:选择工具链 Keil MDK-ARM,生成代码
2. Cube生成的代码结构解析
Cube会自动生成 tim.c 和 tim.h
MX_TIM3_Init() 函数中完成了定时器的时钟配置、预分频、周期、PWM通道配置和GPIO初始化
Cube自动帮你写了 HAL_TIM_PWM_MspInit() 和 HAL_TIM_MspPostInit(),配置GPIO口为复用推挽输出(AF_PP)
调用 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); 启动PWM
3. 用户代码部分(main.c)
/* USER CODE BEGIN 0 */
uint16_t pwm_val = 0;
uint8_t dir = 1;
/* USER CODE END 0 */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init();
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); // 启动PWM输出
while (1)
{
if(dir) pwm_val++;
else pwm_val--;
if(pwm_val >= 999) dir = 0;
if(pwm_val == 0) dir = 1;
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, pwm_val); // 动态调节占空比
HAL_Delay(5); // 延时实现呼吸节奏
}
}
4. Cube生成的 MX_TIM3_Init() 关键代码示例
void MX_TIM3_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比0%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim3);
}
5. Cube生成的 HAL_TIM_MspPostInit() 配置GPIO
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM3)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_AFIO_REMAP_TIM3_PARTIAL(); // TIM3部分重映射
}
}
6. 总结
| 关键点 | 说明 |
|---|---|
| CubeMX配置TIM3 PWM | 自动生成预分频、计数周期、通道配置 |
| HAL_TIM_PWM_Init | 初始化定时器PWM功能 |
| HAL_TIM_MspPostInit | 配置对应GPIO口,设置复用推挽输出 |
| HAL_TIM_PWM_Start | 启动PWM输出 |
| __HAL_TIM_SET_COMPARE | 动态改变CCR寄存器,调节占空比(调光、呼吸灯等) |
你要注意的
Cube自动帮你写了GPIO初始化,千万别重复写,否则冲突
HAL_TIM_MspPostInit() 是自动调用的,配置GPIO很重要
启动PWM后动态写CCR才能看到呼吸灯渐变效果
9️⃣ 你应该知道的几个“坑”⚠️
GPIO必须是复用推挽输出(AF_PP),否则PWM波形不会正常输出。
TIM时钟必须使能,定时器才会计数。
HAL_TIM_MspPostInit()负责配置GPIO,是CubeMX自动生成的。
如果你不启动 HAL_TIM_PWM_Start(),PWM不会工作。
PSC和ARR设置必须配合你的时钟频率,频率才对。
输出比较是“计数器到达某值触发事件”,PWM是它的进阶应用
PWM占空比由CCR和ARR决定,调CCR能动态改变占空比
配置定时器必须设置PSC、ARR、CCR,GPIO配置为AF_PP
STM32有PWM1和PWM2两种模式,常用PWM1
动态调节CCR寄存器的值实现呼吸灯或调光效果
作者:不如出家吧