第28章 通用定时器-4路PWM输出
第二十八章 通用定时器-4路PWM输出
1. 硬件设计
无硬件设计
2. 软件设计
- TIM3相关参数和四个通道宏定义
// 通用定时器参数宏定义-TIM3
#define GENERAL_TIM TIM3 // 选择使用的通用定时器-TIM3
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd // 选择要挂载的时钟-APB1
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 // 选择时钟源-APB1时钟_TIM3
#define GENERAL_TIM_Period 9 // 定时器周期-9
#define GENERAL_TIM_Prescaler 71 // 定时器分频系数-71
// TIM3 输出比较通道1
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_6
// TIM3 输出比较通道2(PA7)
#define GENERAL_TIM_CH2_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH2_PORT GPIOA
#define GENERAL_TIM_CH2_PIN GPIO_Pin_7
// TIM3 输出比较通道3(PB0)
#define GENERAL_TIM_CH3_GPIO_CLK RCC_APB2Periph_GPIOB
#define GENERAL_TIM_CH3_PORT GPIOB
#define GENERAL_TIM_CH3_PIN GPIO_Pin_0
// TIM3 输出比较通道4(PB1)
#define GENERAL_TIM_CH4_GPIO_CLK RCC_APB2Periph_GPIOB
#define GENERAL_TIM_CH4_PORT GPIOB
#define GENERAL_TIM_CH4_PIN GPIO_Pin_1
宏定义了通用定时器的基本参数还有四个通道的GPIO
- GPIO配置
static void GENERAL_TIM_GPIO_Config(void)
{
// 1.定义一个GPIO_InitTypeDef结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
// 2.输出比较通道1 GPIO 初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE); // 开启通道1 GPIO时钟
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN; // 选择通道1引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50MHz
GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure); // 初始化GPIO
// 输出比较通道2 GPIO 初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);
// 输出比较通道3 GPIO 初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure);
// 输出比较通道4 GPIO 初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH4_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GENERAL_TIM_CH4_PORT, &GPIO_InitStructure);
}
四个通道 GPIO 初始化
- TIM模式配置
// TIM模式配置
static void GENERAL_TIM_Mode_Config(void)
{
// 开启定时器时钟,即内部时钟CK_INT=72M
GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK, ENABLE);
/*--------------------时基结构体初始化-------------------------*/
// 配置周期,这里配置为100K
// 1.定义一个TIM_TimeBaseInitTypeDef结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 2.自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM_Period;
// 3.驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM_Prescaler;
// 4.时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 5.计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 6.重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// 初始化定时器
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
- 输出比较结构体配置
/*---------------------输出比较结构体初始化--------------------*/
// 1.占空比配置
uint16_t CCR1_Val = 5; // 通道1的占空比为50%
uint16_t CCR2_Val = 4; // 通道2的占空比为40%
uint16_t CCR3_Val = 3; // 通道3的占空比为30%
uint16_t CCR4_Val = 2; // 通道4的占空比为20%
// 2.定义一个TIM_OCInitTypeDef结构体变量
TIM_OCInitTypeDef TIM_OCInitStructure;
// 3.配置为PWM模式1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
// 4.输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 5.输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
// 输出比较通道 1
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; // 输出比较值
TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure); // 初始化输出比较通道1
TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // 使能预装载
// 输出比较通道 2
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 输出比较通道 3
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 输出比较通道 4
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 使能计数器
TIM_Cmd(GENERAL_TIM, ENABLE);
}
其中一个新的库函数我们需要解释一下:
TIM_OC1PreloadConfig
是 STM32 微控制器中用于配置定时器输出比较通道的函数。其原型如下:
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
TIMx
: 指定定时器实例,如TIM1
,TIM2
等。TIM_OCPreload
: 预装载使能状态,取值为TIM_OCPreload_Enable
或TIM_OCPreload_Disable
。
功能: 启用或禁用通道1的预装载寄存器。启用预装载使得在更新事件发生时,比较寄存器的值可以被预装载寄存器的值替代,从而避免在运行中改变比较值。
示例:
// 启用通道1的预装载
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
// 这将确保在定时器更新事件时,新的比较值会被加载。
- 主函数
// TIM—通用定时器-4路PWM输出应用
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_GeneralTim.h"
int main(void)
{
// led 端口配置
LED_GPIO_Config();
// 定时器初始化
GENERAL_TIM_Init();
while(1)
{
}
}
3. 小结
如何利用通用定时器进行4路PWM输出,我们简化一下流程:
- 初始化 GPIO:配置对应的 GPIO 引脚为定时器输出模式。
- 初始化定时器:设置定时器的计数周期、预分频器等。
- 配置输出比较通道:设置每个通道的 PWM 参数。
- 启动定时器:启动定时器并开始输出 PWM 信号。
下面是一个简单的示例代码,使用 TIM2 定时器产生 4 路 PWM 输出信号。假设你使用的是 STM32F103 系列的微控制器,通道配置如下:
- 通道 1: GPIOA Pin 0
- 通道 2: GPIOA Pin 1
- 通道 3: GPIOA Pin 2
- 通道 4: GPIOA Pin 3
代码示例
#include "stm32f10x.h"
// 初始化 GPIO
void GPIO_Config(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 启用 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置 GPIOA 的四个引脚为定时器输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// 初始化定时器
void TIM_Config(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 启用 TIM2 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置定时器基准时间
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载寄存器值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器,APB1 时钟 / (71 + 1)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 配置通道 1 PWM 输出
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 499; // PWM 占空比的脉冲宽度 (50% 的占空比)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 极性高
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 1 的预装载
// 配置通道 2 PWM 输出
TIM_OCInitStructure.TIM_Pulse = 249; // 不同的占空比
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 2 的预装载
// 配置通道 3 PWM 输出
TIM_OCInitStructure.TIM_Pulse = 749; // 不同的占空比
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 3 的预装载
// 配置通道 4 PWM 输出
TIM_OCInitStructure.TIM_Pulse = 999; // 不同的占空比
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 4 的预装载
// 启动定时器
TIM_Cmd(TIM2, ENABLE);
}
// 主函数
int main(void) {
// 配置 GPIO
GPIO_Config();
// 配置定时器
TIM_Config();
while (1) {
// 主循环中可以进行其他操作
}
}
代码解释
- GPIO_Config:
- 启用 GPIOA 的时钟。
- 配置 GPIOA 的四个引脚为推挽输出模式,用于输出 PWM 信号。
- TIM_Config:
- 启用 TIM2 的时钟。
- 配置定时器 TIM2 的基准时间,包括周期(
TIM_Period
)、预分频器(TIM_Prescaler
)、计数模式等。 - 配置 TIM2 的四个通道为 PWM 输出模式,并设置各通道的占空比。
- 启动 TIM2 定时器。
- 主函数:
- 调用配置函数初始化 GPIO 和定时器。
- 进入无限循环,持续运行主程序。
该示例代码中,PWM 信号的占空比是通过调整 TIM_OCInitStructure.TIM_Pulse
来设置的。
2024.9.12 第一次修订,后期不再维护