定时器PWM
一、STM32 定时器 PWM 基础理论
1. 什么是 PWM
PWM 全称:脉冲宽度调制 简单说:周期固定,高电平时间可调的方波信号 不靠改变电压大小,靠高电平占整个周期的比例,实现调压、调速、舵机角度控制。
2. 三个核心参数
- 周期 T:一个高低电平完整循环的时间
- 频率 f:f = 1 / T,每秒循环多少次
- 占空比:高电平时间 ÷ 整个周期时间
举例:周期 20ms,高电平 0.5ms → 占空比很小周期 20ms,高电平 2.5ms → 占空比很大
二、STM32 定时器怎么产生 PWM
1. 定时器内部三大关键寄存器
- 预分频器 PSC:把 72MHz 系统时钟降频
- 自动重装载寄存器 ARR :决定 PWM周期
- 捕获比较寄存器 CCR :决定 PWM高电平宽度
2. PWM 周期计算公式
\(T_{PWM} = \frac{(PSC+1)\times(ARR+1)}{f_{TIM}}\)
- \(f_{TIM}\) 定时器时钟(F103 一般 72MHz)
- PSC:预分频值
- ARR:自动重装载值
3. 高电平时间由 CCR 决定
计数器从 0 往上数:
- 数到 CCR → 电平翻转
- 数到 ARR → 计数器清零,重新开始
所以:改 ARR → 改 PWM 频率 / 周期 改 CCR → 改占空比、改高电平时间
三、STM32 PWM 两种工作模式
模式 1(最常用,舵机必用)
向上计数
- 计数器 0 → ARR
- 当计数器 < CCR:输出高电平
- 当计数器 > CCR:输出低电平
模式 2
- 刚好相反:小于 CCR 低电平,大于 CCR 高电平
控制 SG90 一律用:PWM 模式 1
SG90舵机
一、SG90 9g 舵机纯理论原理
1. 内部结构
- 直流小电机
- 减速齿轮组(减速增扭)
- 电位器(角度位置反馈)
- 控制电路板
2. 工作逻辑
- 外部给 固定周期 PWM 信号
- 舵机内部检测高电平持续时间
- 对比内部电位器当前角度
- 自动正转 / 反转,直到角度匹配 PWM 设定值
- 到达角度后自锁,保持位置不动
3. 供电与接线
- 红线:5V 供电
- 棕线:GND
- 橙 / 黄线:PWM 信号控制线
二、SG90 标准控制时序
1. 固定周期
SG90 要求 PWM 周期必须严格 20ms对应频率:\(f = 1/20ms = 50Hz\)
2. 高电平时间对应角度(标准 180° 舵机)
| 高电平时间 | 对应角度 |
|---|---|
| 0.5ms | 0° |
| 1.5ms | 90° |
| 2.5ms | 180° |
规律:
- 高电平越长 → 角度越大
- 高电平越短 → 角度越小
三、PWM 参数配置理论(适配 SG90)
目标:生成 50Hz 周期 20ms 的 PWMSTM32F103 主频 72MHz
配置思路:
- 定时器时钟 72MHz
- 分频 + ARR 算出 20ms 周期
- 调节 CCR 值,改变高电平 0.5~2.5ms
计算公式对应关系
- ARR、PSC 固定死 → 保证周期 20ms
- 只改 CCR → 控制 0°~180° 角度
四、角度与 CCR 值线性关系理论
180° 对应高电平区间:0.5ms ~ 2.5ms差值:\(2.5 - 0.5 = 2ms\)
每 1° 对应时间:\(2ms / 180° \approx 0.0111ms/°\)
可以写出公式:\(高电平时间(ms) = 0.5 + \frac{角度}{180} \times 2.0\)再把时间换算成 CCR 数值,就能直接用代码赋值控制角度。
TIM3 PWM 控制 SG90 舵机
一、工程功能
使用 STM32F103 的 TIM3 通道 2(PB5) 输出 50Hz PWM 信号,控制 SG90 舵机在 0°、90° 之间来回旋转。
二、硬件接线
- SG90 信号线 → PB5
- VCC → 5V
- GND → GND
三、main.c
#include "stm32f10x.h"
#include "main.h"
#include "stdio.h"
#include "sg90.h"
// 软件毫秒延时(粗略)
void delay(uint16_t time)
{
uint16_t i = 0;
while(time--)
{
i = 12000;
while(i--);
}
}
int main()
{
// 中断分组(整个系统只配置一次)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 初始化 PWM + GPIO + 定时器
SG90_Init();
while(1)
{
// 舵机转到 90°,延时1秒
SG90_Angle(90);
delay(1000);
// 舵机转到 0°,延时1秒
SG90_Angle(0);
delay(1000);
}
}
主函数逻辑
- 配置中断分组
- 初始化舵机 PWM 输出
- 死循环:
- 90° → 等待 1 秒
- 0° → 等待 1 秒
- 循环往复
四、sg90.c
#include "stm32f10x.h"
#include "sg90.h"
void SG90_Init(void)
{
// 1. 定义结构体
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_OCInitTypeDef TIMOC_InitStruct;
// 2. 开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 复用功能时钟
// 3. 开启 TIM3 部分重映射 → CH2 从 PA7 → PB5
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
// 4. 配置 PB5 为复用推挽输出(PWM 输出引脚)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// ==========================
// 5. 定时器配置:50Hz / 20ms
// ==========================
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
// 自动重装载值
TIM_InitStruct.TIM_Period = 200-1;
// 预分频
TIM_InitStruct.TIM_Prescaler = 7200-1;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
// ==========================
// 6. PWM 模式配置
// ==========================
TIMOC_InitStruct.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIMOC_InitStruct.TIM_OCPolarity = TIM_OCPolarity_Low; // 低电平有效
TIMOC_InitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC2Init(TIM3, &TIMOC_InitStruct); // 通道2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能预装载
// 7. 启动定时器
TIM_Cmd(TIM3, ENABLE);
}
// ==========================
// 角度设置函数
// ==========================
void SG90_Angle(uint16_t angle)
{
switch(angle)
{
case 180: TIM_SetCompare2(TIM3, 175); break;
case 135: TIM_SetCompare2(TIM3, 180); break;
case 90 : TIM_SetCompare2(TIM3, 185); break;
case 45 : TIM_SetCompare2(TIM3, 190); break;
case 0 : TIM_SetCompare2(TIM3, 195); break;
}
}
五、核心知识点
1. 定时器 PWM 周期计算(20ms / 50Hz)
你的配置:
- 预分频:7200-1
- 重装载:200-1
计算公式:
周期 = (7200 × 200) / 72M = 0.02s = 20ms
刚好满足 SG90 舵机要求!
2. PWM 模式 1 作用
- 计数器从 0 往上数
- 小于 CCR:低电平
- 大于 CCR:高电平
- 配置了 低极性有效 ,所以:CCR 值越小 → 高电平时间越长 → 角度越大
3. 角度与 CCR 对应关系
代码里的实测值:
- 0° → CCR = 195
- 90° → CCR = 185
- 180° → CCR = 175
规律:CCR 越小 → 角度越大
4. 为什么用 PB5?
因为开启了:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
TIM3_CH2 从 PA7 重映射到 PB5。
六、sg90.h 代码
#ifndef SG90_H_
#define SG90_H_
#include "stm32f10x.h"
void SG90_Init(void);
void SG90_Angle(uint16_t angle);
#endif
七、程序整体运行流程
- 初始化 GPIO、TIM3、PWM
- 定时器开始输出 20ms 周期的 PWM
- 主循环不断设置 0° / 90°
- 舵机根据 PWM 信号旋转角度