定时器与脉冲宽度调制(PWM)
1. 定时器概述
- 定时器是 STM32F103 微控制器中的重要外设,用于实现 计时、计数、事件产生 等功能。
- STM32F103 提供了多个通用定时器(如 TIM2、TIM3、TIM4 等),每个定时器都有多达 4 个通道,可用于捕获/比较、PWM 输出等。
- 定时器可配置为多种工作模式:
- 输入捕获模式:用于测量输入信号的周期、频率或脉宽。
- 输出比较模式:当计数器的值与预设的比较值匹配时,产生事件或输出信号。
- PWM 模式:通过调节脉冲的 占空比,实现对负载的精确控制。
2. PWM 原理
- PWM(Pulse Width Modulation,脉冲宽度调制)是一种通过改变脉冲信号 占空比 来控制平均输出功率的技术。
- 占空比 是指脉冲高电平持续时间与周期的比值。通过调整占空比,可以控制负载所获得的能量。
- PWM 应用领域:
- 电机控制:调节电机的转速和转矩。
- LED 调光:控制 LED 的亮度,实现从全暗到全亮的平滑过渡。
- 音频信号:用于数字音频的合成与放大。
3. PWM 配置步骤
要在 STM32F103 上配置 PWM 输出,需要按照以下步骤进行:
-
使能时钟:开启对应的定时器和 GPIO 时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能 TIM3 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
-
配置 GPIO 引脚为复用功能输出:将用于 PWM 输出的 GPIO 引脚设置为复用推挽输出模式。
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // 选择 PA6 引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO 速度 GPIO_Init(GPIOA, &GPIO_InitStructure);
-
初始化定时器:设置计数模式、周期(ARR)、预分频器(PSC)等参数。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值(决定 PWM 周期) TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器(决定计数器时钟) TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
计算说明:
- 定时器频率 = 主频 / (预分频器 + 1)
- PWM 频率 = 定时器频率 / (自动重装载值 + 1)
- 以主频 72MHz 为例,预分频器为 71,则定时器频率为 1MHz。自动重装载值为 999,则 PWM 频率为 1kHz。
-
配置 PWM 模式:设置输出比较模式、输出极性和占空比(比较值)。
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 499; // 比较值(占空比 50%) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高有效 TIM_OC1Init(TIM3, &TIM_OCInitStructure); // 配置 TIM3 通道 1
占空比计算:
- 占空比(%) = (比较值 / (自动重装载值 + 1)) × 100%
- 例如,比较值为 499,占空比约为 50%。
-
启动定时器:使能定时器计数和 PWM 输出。
TIM_Cmd(TIM3, ENABLE); // 使能 TIM3 // 对于高级定时器(如 TIM1、TIM8),需要使能 PWM 输出:TIM_CtrlPWMOutputs(TIM3, ENABLE);
4. 示例:使用 TIM3 产生 PWM 信号
以下是完整的代码示例,演示如何使用 TIM3 通道 1 (PA6) 产生占空比为 50% 的 PWM 信号。
#include "stm32f10x.h"
void PWM_Init(void) {
// 1. 使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能 TIM3 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
// 2. 配置 GPIOA Pin6 为复用推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // PA6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度 50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 初始化定时器
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值(ARR)
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器(PSC)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 4. 配置 PWM 模式
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_Pulse = 499; // 比较值(占空比 50%)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效
TIM_OC1Init(TIM3, &TIM_OCInitStructure); // 配置 TIM3 通道 1
// 5. 启动定时器
TIM_Cmd(TIM3, ENABLE); // 使能定时器
}
int main(void) {
PWM_Init(); // 初始化 PWM
while (1) {
// 主循环,可在此调整占空比等参数
}
}
调整占空比
在实际应用中,可能需要动态调整 PWM 的占空比。例如,通过改变比较值 TIM_OCInitStructure.TIM_Pulse
,可以调整输出信号的占空比。
示例:
void Set_PWM_DutyCycle(uint16_t duty) {
if (duty <= 999) {
TIM_SetCompare1(TIM3, duty); // 设置 TIM3 通道 1 的比较值
}
}
// 在主循环中调用
int main(void) {
PWM_Init(); // 初始化 PWM
while (1) {
for (uint16_t i = 0; i <= 999; i++) {
Set_PWM_DutyCycle(i); // 增加占空比
Delay(1); // 自定义延时函数
}
for (uint16_t i = 999; i > 0; i--) {
Set_PWM_DutyCycle(i); // 减小占空比
Delay(1);
}
}
}
注意: Delay()
为自定义的延时函数,需要根据具体情况实现。
5. 注意事项
- GPIO 引脚选择:确保所选的 GPIO 引脚支持定时器的 PWM 功能,不同的定时器通道对应的 GPIO 详见 STM32F103 的数据手册。
- 定时器时钟源:定时器的时钟频率受 APB 总线的预分频影响,需要确认定时器实际工作频率。
- 高级定时器:对于高级定时器(如 TIM1、TIM8),在使能定时器后还需要使能 PWM 输出:
TIM_CtrlPWMOutputs(TIM1, ENABLE);
- 占空比范围:占空比的比较值应在
0
到TIM_Period
范围内。
Comments NOTHING