PWM输出实例:
PWM在电力电子技术中占据着重要的地位,被广泛地用在逆变电路之中。利用STM32定时器的PWM输出功能,可以直接获取PWM波。根据面积等效原理,利用规则采样法、查表法可以调制出SPWM波及各种调制PWM波形。
这里实现的是输入占空比固定的PWM波形
PS:
通用定时器TIM3产生4路不同占空比的PWM波。(仅仅适合本实例))
TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
main函数:
int main(void)
{
TIM3_PWM_Init();
while(1)
{}
}
main函数十分简单,调用 TIM3_PWM_Init()把TIM初始化成PWM输出模式后,内核就把所有的工作都交给TIM外设,完全有TIM来控制GPIO引脚输出PWM波.
定时器初始化:
void TIM3_PWM_Init(void)
{
TIM3_GPIO_Config();
TIM3_Mode_Config();
}
调用TIM3_GPIO_Config()作为TIM外设通道复用的GPIO引脚进行初始化,再调用TIM3_Mode_Config()对TIM外设进行初始化.
GPIO初始化:
static void TIM3_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/使能TIM3时钟/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/使能GPIO引脚 4个通道 GPIOA_Pin6和Pin7 GPIOB_Pin0和Pin1/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*都是一样的配置*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
使能了TIM3外设的时钟,并对TIM3通道相应的GPIO引脚作了相应的配置,使能GPIO时钟,分别是PA6、PA7、PB0和PB1。它们被配置为复用输出,翻转速率为50MHz。
(关于TIM3通道的GPIO引脚映射可以在《STM32 数据手册》的引脚定义表找到,GPIO复用模式配置可从《STM32 参考手册》的GPIO章节找到)
TIM引脚定义
TIM模式配置
定时器3模式初始化:
static void TIM3_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//PWM 信号电平跳变值
u16 CCR1_Val = 500;
u16 CCR2_Val = 375;
u16 CCR3_Val = 250;
u16 CCR4_Val = 125;
//这里为时基配置
TIM_TimeBaseStructure.TIM_Period = 999;
//当定时器从0计数到999,即为1000次,为一个定时周期
TIM_TimeBaseStructure.TIM_Prescaler = 0;
//配置TIMx_CLK预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//设置时钟分频系数:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//配置为 PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
//设置跳变值,当计数器计数到这个值时,电平发生跳变
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//当定时器计数值小于 CCR1_Val 时为高电平
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能通道 1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
//设置通道 2 的电平跳变值,输出另外一个占空比的 PWM
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能通道 2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
//设置通道 3 的电平跳变值,输出另外一个占空比的 PWM
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //使能通道 3
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
//设置通道 4 的电平跳变值,输出另外一个占空比的 PWM
TIM_OC4Init(TIM3, &TIM_OCInitStructure); //使能通道 4
//装载捕获、比较寄存器
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 使能 TIM3 重载寄存器 ARR
TIM_Cmd(TIM3, ENABLE); //使能定时器 3
}
这个配置可以分为3部分,分别为时基初始化,输出模式初始化和装载捕获、比较寄存器的数值。
时基初始化:
使用了一个TIM_TimeBaseInitTypeDef类型的结构体。时基初始化,即配置基本定时器只具有的那部分功能
TIM_TimeBaseStructure.TIM_Period = 999;
定时周期,实质就是存储到重载寄存器 TIMx——ARR的数值,脉冲计数器从0累加到这个值上溢或从这个值下溢。这个数值加1然后乘以时钟源周期就是实际定时周期。
这里设置为999,所以定时周期为(999+1)*T,T为时钟源周期
TIM_TimeBaseStructure.TIM_Prescaler = 0;
对定时器时钟TIMxCLK的预分频值,分频后作为脉冲计数器TIMx_CNT的驱动时钟,得到脉冲计数器的时钟频率为:f CK_CNT=f TIMx_CLK /(N+1),其中N为赋给本成员的是时钟分频值.
这里设置为0,就是不对TIMxCLK分频,例如:已知AHB时钟频率为72MHz、TIMxCLK为72MHz,所以输出到脉冲计数器TIMx_CNT的时钟频率为 f CK_CNT =72MHz/1=72MHz。
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
时钟分频因子,这个TIM_ClockDivision和TIM_Prescaler分频是不一样的,TIM_Prescaler分频配置是对TIMx_CLK进行分频,分频后的时钟被输出到脉冲计数器TIMx_CNT,而TIM_ClockDivision虽然也是对TIMxCLK进行分频,但它分频后的时钟频率为f DTS,是被输出到定时器的ETRP数字滤波器部分,会影响滤波器的采样频率.TIM_ClockDivision可以被配置为1分频(f DTS = f TIMxCLK),2分频和四分频,ETRP数字滤波器的作用是对外部时钟TIMxETR进行滤波.
这里只使用了内部时钟 TIMxCLK作为定时器时钟源,所以配置 TIM_ClockDivision为任何值都无影响.
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
脉冲计数器 TIMx_CNT的计数模式,分别有向上计数,向下计数,中央对齐模式.
向上计数:TIMx_CNT从0向上累加到TIM_Period中的值(重载寄存器TIMx_ARR的值),产生上溢事件;
向下计数:TIMxCNT 从TIM_Period的值累减至0,产生下溢事件;
中央对齐模式:向上,向下计数的合体,TIMxCNT从0累加到TIM_Period的值减1时,产生一个上溢事件,然后向下计数到1时,产生一个计数器下溢事件,再从0开始重新计数,一直循环.
这里是配置成 TIM_CounterMode_Up(向上计数模式)
填充完配置参数后,调用库函数TIM_TimeBaseInit()把这些控制参数写到寄存器中,定时器的时基配置就完成了。
输出模式配置:
通用定时器的输出模式由 TIM_OCInitTypeDef类型结构体来配置.
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
输出模式配置,主要使用的为PWM1和PWM2模式。
PW1模式:在向上计数时,当TIMx_CNT小于(不知道为什么要用中文小于才能显示下面其他内容)TIMx_CCRn(比较寄存器,其数值等于TIM_Pulse成员的内容)时,通道n输出为有效电平,否则为无效电平,向下计数时,当TIMx_CNT>TIMx_CCRn时通道n为无效电平,否则为有效电平.PWM2模式和PWM1模式相反.
(其中的有效电平好无效电平并不是固定对应高电平和低电平,也是需要配置的)
这里使用了PWM1模式.
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
配置输出模式的状态或关闭输出.
这里配置成TIM_OutputState_Enable(使能输出)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
有效电平的极性,把PWM模式中的有效电平设置为高电平或低电平.
这里是配置成TIM_OCPolarity_High(有效电平为高电平),因为在上面把输出模式配置为PWM1模式,向上计数,所以在TIMx_CNT小于TIMx_CCRn时,通过到n输出为高电平,否则为低电平.
TIM_OCInitStructure. = CCR1_Val;
跳动,即为比较寄存器 TIMx_CCR的数值,当脉冲计数器 TIMx_CNT与 TIMx_CCR的比较结果发生变化时,输出脉冲将发生变化.
这里向1,2,3,4通道的TIM_Pulse分别赋值为500,375,250,125,定时器向上计数,PWM1模式,有效高电平为高,定时周期为1000(TIM_Period=999),所以当TIMx_CNT计数值小于 TIM_Pulse值时,输出高电平,否则为低电平,即各通道输出PWM的占空比为D=TIM_Pulse/(TIM_Period+1),即分别为 50%、37.5%、25%、12.5%。
填充完输出模式初始化结构体后,要调用输出模式初始化函数TIM_OCxInit()对各个通道进行初始化(x表示定时器的通道).如TIM_OC1Init()是用来初始化定时器的通道1的,TIM_OC2Init()是用来初始化定时器的通道2的.
PS:
调用各个通道初始化函数前,需要对初始化结构体的 TIM_Pulse重新赋值,因为这里的成员配置都一样,而占空比是不同的.
最后使用了TIM_OCxPreloadConfig()配置了各通道的比较寄存器TIM_CCR 预装载使能,使用 TIM_ARRPreloadConfig()把重载寄存器 TIMx_ARR使能,最后用 TIM_Cmd()使能定时器 TIM3,定时器外设就开始工作了.
PS:
总结以下定时器的配置:
1,设定TIM信号周期;
2,设定TIM预分频值(TIM_Prescaler);
3,设定TIM分频系数(TIM_ClockDivision);
4,设定TIM计数模式;
5,根据TIM_TimeBaseInitStruct这个结构体里面的值初始化TIM;
6,设定TIM的OC模式;
7,TIM的输出使能;
8,设定电平跳变值;
9,设定PWM信号的极性;
10,使能TIM信号通道;
11,使能TIM比较寄存器CCRX重载;
12,使能TIM重载寄存器ARR;
13,使能TIM计数器;
这个实例输出的为占空比固定的PWM波,如果想利用定时器输出SPWM波,就需要不断改变PWM的占空比,可以利用库函数TIM_SetCompare()查表修改比较寄存器中的值(就是脉冲宽度)来实现.