MCU微课堂
CKS32F4xx系列
MCU互补PWM
互补输出简介
互补输出只能在高级控制定时器(TIM1和TIM8)上使用,可以输出两路互补信号,包括主输出OCx和互补输出OCxN。基于比较输出一节的内容,OCx和OCxN都可以输出一定频率和占空比的PWM波形,且他们的极性是相反的,如图1所示,OCxREF是参考信号,OCx输出信号与参考信号相同,只是它的上升沿相对于参考信号的上升沿有一个延迟,OCxN输出信号与参考信号相反,只是它的上升沿相对于参考信号的下降沿有一个延迟,这个延迟时间,我们是可以通过死区寄存器配置的,本节中我们可以设置为0。
图1 带死区插入的互补输出
图2捕获比较通道的输出阶段
如图3所示,因为互补输出多用于PWM控制电机的项目中,所以紧急情况下的刹车控制是必不可少的,OSSR的含义是运行模式下的关闭状态选择,OSSI的含义是空闲模式下的关闭状态选择,MOE的含义是主输出使能,一般的应用模式为,当短路输入为有效状态,MOE又硬件异步清零,OSSI设置为0,禁止OCOCN输出,OSI1OSI1N设置为0,OC1OC1N输出为0,达到紧急刹车的目的。
图3 控制位和输出状态
配置步骤
互补输出实际跟比较输出章节一样使用的是定时器的功能,所以相关的函数设置同样在库函数文件CKS32f4xx_tim.h和CKS32f4xx_tim.c文件中。 1)开启TIM1和GPIO时钟,配置PA7、PA8选择复用功能GPIO_AF_TIM1输出。 要使用TIM1,我们必须先开启TIM1的时钟,这点相信大家看了这么多代码,应该明白了。这里我们还要配置PA7、PA8为复用(GPIO_AF_TIM1)输出,才可以实现TIM1_CH1的互补PWM经过PA7、PA8输出。库函数使能TIM1时钟的方法是:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //>>TIM1 时钟使能这在前面章节已经提到过。当然,这里我们还要使能GPIOA的时钟。然后我们要配置PA7引脚映射至GPIO_AF_TIM1,复用为定时器1,调用的函数为:
GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1); //>>GPIOA7 复用为定时器1配置PA8引脚映射至GPIO_AF_TIM1,复用为定时器1,调用的函数为:
GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //>>GPIOA8 复用为定时器1这个方法跟我们串口实验讲解一样,调用的同一个函数,最后设置PA7为复用功能输出这里我们只列出GPIO初始化为复用功能的一行代码:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //>>复用功能这里还需要说明一下,对于定时器通道的引脚关系,大家可以查看CKS32F4对应的数据手册,比如我们PWM实验,我们使用的是定时器1的通道1,对应的引脚PA7可以从数据手册表中查看:
2)初始化TIM1,设置TIM1的ARR和PSC等参数。 在开启了TIM1的时钟之后,我们要设置ARR和PSC两个寄存器的值来控制输出PWM的周期。这在库函数是通过TIM_TimeBaseInit函数实现的,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为:
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx3)设置TIM1_CH1的PWM模式,使能TIM1的CH1输出。 设置TIM1_CH1为PWM模式(默认是冻结的)通过配置TIM1_CCMR1的相关位来控制TIM1_CH1的模式。在库函数中,PWM通道设置是通过函数TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道1,所以使用的函数是TIM_OC1Init()。
Void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);这种初始化格式大家学到这里应该也熟悉了,所以我们直接来看看结构体TIM_OCInitTypeDef的定义:
typedef struct { uint16_t TIM_OCMode; uint16_t TIM_OutputState; uint16_t TIM_OutputNState; */ uint16_t TIM_Pulse; uint16_t TIM_OCPolarity; uint16_t TIM_OCNPolarity; uint16_t TIM_OCIdleState; uint16_t TIM_OCNIdleState; } TIM_OCInitTypeDef;这里我们讲解一下与我们要求相关的几个成员变量: 参数TIM_OCMode设置模式是PWM还是输出比较,这里我们是PWM模式。 参数TIM_OutputStateOutputNState用来设置比较输出使能,也就是使能PWM输出到端口。参数TIM_OCPolarityOCNPolarity用来设置极性是高还是低。参数TIM_OCIdleState和TIM_OCNIdleState用来设置空闲时的输出状态。 要实现我们上面提到的场景,方法是:
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //>>选择模式 PWM TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //>>比较输出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Enable; //>>比较输出使能 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //>>输出极性高 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //>>输出极性低 TIM_OCInitStructure. TIM_OCIdleState = TIM_OCNIdleState_Reset; //>>当MOE=0重置输出空闲状态 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //>>当MOE=0重置输出空闲状态 TIM_OCInitStruct.TIM_Pulse=100;//待装入捕获比较寄存器的脉冲值 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //>>根据指定的参数初始化外设TIM1 OC1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR上的预装载寄存器4)使能 TIM1。 在完成以上设置了之后,我们不开启刹车功能,并使能TIM1,使能TIM1的方法前面已经讲解过:
TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;//自动输出功能使能 TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能刹车输入 TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //刹车输入管脚极性高 TIM_BDTRStructure.TIM_DeadTime=0; //输出打开和关闭状态之间的延时 TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 锁电平参数: 不锁任何位 TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //设置在运行模式下非工作状态选项 TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //设置在运行模式下非工作状态选项 TIM_BDTRConfig(TIM1,&TIM_BDTRStructure); TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIM1在ARR上的预装载寄存器 TIM_CtrlPWMOutputs(TIM1,ENABLE); //PWM使能主输出MOE=1 TIM_Cmd(TIM1,ENABLE); //打开TIM15)修改TIM1_CCR1来控制占空比。 最后,在经过以上设置之后,PWM其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改TIM1_CCR1则可以控制CH1的输出占空比。在库函数中,修改TIM1_CCR1占空比的函数是:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);理所当然,对于其他通道,分别有一个函数名字,函数格式为:
TIM_SetComparex(x=1,2,3,4)
通过以上5个步骤,我们就可以控制TIM1的CH1输出互补PWM波了。 3代码示例 添加PWM配置文件pwm.c和pwm.h。 pwm.c源文件代码如下:
//>>TIM1 PWM 部分初始化 //>>PWM 输出初始化 //>>arr:自动重装值 psc:时钟预分频数 void TIM1_PWM_Init(u32 arr,u32 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//TIM1 时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能 PORTA 时钟 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1); //PA7 复用为 TIM1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //PA8 复用为 TIM1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8; //GPIOF9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA7PA8 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//初始化定时器 1 //初始化 TIM1 Channel1 互补PWM 模式 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //>>选择模式 PWM TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //>>比较输出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Enable; //>>比较输出使能 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //>>输出极性低 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //>>输出极性低 TIM_OCInitStructure. TIM_OCIdleState = TIM_OCNIdleState_Reset; //>>当MOE=0重置输出空闲状态 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //>>当MOE=0重置输出空闲状态 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //>>根据指定的参数初始化外设TIM1 OC1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR上的预装载寄存器 TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;//自动输出功能使能 TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能刹车输入 TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //刹车输入管脚极性高 TIM_BDTRStructure.TIM_DeadTime=0; //输出打开和关闭状态之间的延时 TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 锁电平参数: 不锁任何位 TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //设置在运行模式下非工作状态选项 TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //设置在运行模式下非工作状态选项 TIM_BDTRConfig(TIM1,&TIM_BDTRStructure); TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIM1在ARR上的预装载寄存器 TIM_CtrlPWMOutputs(TIM1,ENABLE); //PWM使能主输出MOE=1 TIM_Cmd(TIM1,ENABLE); //打开TIM1 TIM_SetCompare1(TIM1,300); //>>设置pwm的占空比为300/500 = 60% }此部分代码包含了上面介绍的PWM输出设置的前5个步骤。这里我们关于TIM1的设置就不再说了。接下来,我们看看主程序里面的main函数如下:
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//>>设置系统中断优先级分组 2 delay_init(168); //>>初始化延时函数 TIM1_PWM_Init(500-1,84-1); //>>定时器时钟为 84M,分频系数为 84,所以计数频率 //>> 84M/84=1Mhz,重装载值500,所以PWM频率为1M/500=2Khz. while(1) { } }这里,我们先设置好了NVIC终端优先级,然后初始化延时函数和timer,在timer的初始化参数中我们把PWM的频率设置成2K,将占空比设置成60%,完成PWM输出设置。
审核编辑:黄飞
评论
查看更多