一、前期准备
- 硬件:STM32F103C8T6开发板
- 调试工具:DAPLink(本次使用)或USB-TTL
- 开发环境:STM32CubeMX、Keil、Vscode(可选)
- LED:使用PA0(TIM2_CH1)输出PWM,LED的阴极接GND
二、使用定时器中断产生PWM
STM32F103C8T6在72MHz的计数时钟下,可实现最大59.65s的定时。
- STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
- 时基单元:16位预分频器 + 16位计数器 + 16位自动重装载寄存器
计数模式:
1. 向上计数模式(常用):从0开始累加,到自动重装值触发中断。
2. 向下计数模式:从自动重装值递减,到0触发中断
3. 中央对齐计数模式:从0开始累加,到自动重装载值触发中断,然后递减,到0再次触发中断。常用于电机控制的SVPWM算法中。
TIM输出比较原理:
- OC(Output Compare):输出比较,输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。每个高级定时器和通用定时器都拥有4个输出比较通道OC1~4。
- CCR(Capture Compare):捕获比较寄存器
PWM(Pulse Width Modulation)脉冲宽度调制
- 频率 = 1 / TS,一般在 几kHz~几十kHz。
- 占空比 = TON / TS
- 分辨率 = 占空比变化步距,也就是占空比变化的精细程度。一般1%足够使用。
注:定时中断的频率就是PWM波的频率,只不过占空比的变化范围由自动重装载值ARR决定。
输出比较模式:常用PWM模式1
2.1 PWM参数计算
- PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
- PWM占空比: Duty = CCR / (ARR + 1),CCR值可以设置PWM的占空比,因此ARR常设为100-1
- PWM分辨率: Reso = 1 / (ARR + 1),即PWM的步长
参数说明:
- CK_PSC:时钟源频率,72MHz
- PSC:预分频器寄存器的值
- ARR:自动重装寄存器的值
- CCR:捕获比较寄存器的值
案例1:假如驱动SG90舵机:PWM频率为50Hz,即周期20ms
- PSC = 72-1
- ARR = 20K-1
案例2:输出频率为10K的PWM
- 先确定ARR的值:ARR = 100-1
- 再设置PSC的值:PSC = 72-1
2.2 STM32F103C8T6通用定时器输出通道
- 因为涉及到GPIO的复用功能,所以要使用定时器输出PWM时,GPIO的工作模式需要设置为复用推挽输出模式
序号 | 主功能 | 默认复用功能 |
1 | PA0 | TIM2_CH1 |
2 | PA1 | TIM2_CH2 |
3 | PA2 | TIM2_CH3 |
4 | PA3 | TIM2_CH4 |
5 | PA6 | TIM3_CH1 |
6 | PA7 | TIM3_CH2 |
7 | PB0 | TIM3_CH3 |
8 | PB1 | TIM3_CH4 |
9 | PB6 | TIM4_CH1 |
10 | PB7 | TIM4_CH2 |
11 | PB8 | TIM4_CH3 |
12 | PB9 | TIM4_CH4 |
三、STM32CubeMX配置
1.设置RCC:使用外部高速时钟HSE
2.SYS配置:配置成 SWD协议下载和调试
3. 定时器配置
使用TIM2,输出PWM频率10K
- 设置ARR = 100-1
- 设置PSC = 72-1
TIM2时钟源配置、通道输出配置: GPIO的工作模式会自动被设置为复用推挽输出模式
工作参数设置:PWM模式1
- ARR:决定PWM的分辨率
- CCR:PWM的占空比
4.时钟树配置:72MHz
5.导出代码:之后步骤参考之前的就可以了
四、程序编写
// 在TIMX_CH1通道上输出占空比为CompareValue的PWM
__STATIC_INLINE void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue)
{
WRITE_REG(TIMx->CCR1, CompareValue);
}
/* USER CODE BEGIN WHILE */
LL_TIM_EnableAllOutputs(TIM2);
LL_TIM_EnableCounter(TIM2); // 使能计数
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); // 使能输出比较通道
while (1)
{
for (uint16_t i = 0; i <= 100; i++)
{
LL_TIM_OC_SetCompareCH1(TIM2, i); // PA0(TIM2_CH1)输出占空比为i的PWM
LL_mDelay(10);
}
for (uint16_t i = 0; i <= 100; i++)
{
LL_TIM_OC_SetCompareCH1(TIM2, 100 - i);
LL_mDelay(10);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */