CKS32F4xx系列MCU互补PWM

cathy的头像
cathy 发布于:周一, 12/04/2023 - 09:36 ,关键词:

互补输出简介

互补输出只能在高级控制定时器(TIM1和TIM8)上使用,可以输出两路互补信号,包括主输出OCx和互补输出OCxN。基于比较输出一节的内容,OCx和OCxN都可以输出一定频率和占空比的PWM波形,且他们的极性是相反的,如图1所示,OCxREF是参考信号,OCx输出信号与参考信号相同,只是它的上升沿相对于参考信号的上升沿有一个延迟,OCxN输出信号与参考信号相反,只是它的上升沿相对于参考信号的下降沿有一个延迟,这个延迟时间,我们是可以通过死区寄存器配置的,本节中我们可以设置为0。

1.png

图1 带死区插入的互补输出

2.png

图2捕获比较通道的输出阶段

如图3所示,因为互补输出多用于PWM控制电机的项目中,所以紧急情况下的刹车控制是必不可少的,OSSR的含义是运行模式下的关闭状态选择,OSSI的含义是空闲模式下的关闭状态选择,MOE的含义是主输出使能,一般的应用模式为,当短路输入为有效状态,MOE又硬件异步清零,OSSI设置为0,禁止OC\OCN输出,OSI1\OSI1N设置为0,OC1\OC1N输出为0,达到紧急刹车的目的。

3.png

图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可以从数据手册表中查看:

3.png

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); //根据指定的参数初始化 TIMx

3)设置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_OutputState\OutputNState用来设置比较输出使能,也就是使能PWM输出到端口。参数TIM_OCPolarity\OCNPolarity用来设置极性是高还是低。参数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);   //打开TIM1

5)修改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)
{
    PIO_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); //初始化 PA7\PA8
    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输出设置。

来源:中科芯MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 8