先科普一下,什么是互补PWM:就是两组PWM信号,它们的波形是互补的,简单理解,就是这两个信号直接相加的话,结果是一条直线。互补PWM有时候需要增加一个“死区”,防止两个信号同时为1或者同时为0的瞬间出现。
波形如图:
好了,看懂图后,我就上代码啦,不客气l !
#ifndef __BSP_PWM_H__#define __BSP_PWM_H__ #include "bt.h" #include "gpio.h" #define PWM_PERIOD_4MS 0xbe00 void BSP_PWM_Config(void); void BSP_2Comp_PWM_Config(void); void BSP_PWM_SetDuty(uint8_t duty); void BSP_PWM_Deconfig(void); #endif
复制代码C文件,核心是定时器做的。
#include "bsp_pwm.h"#include "bsp_led.h" //Timer0 配置 static void App_Timer0Cfg(uint16_t u16Period, en_bt_cr_timclkdiv_t pclk_div, uint16_t u16CHxACompare, uint16_t DeadTime) { uint16_t u16CntValue; uint8_t u8ValidPeriod; stc_bt_mode23_cfg_t stcBtBaseCfg; stc_bt_m23_compare_cfg_t stcBtPortCmpCfg; stc_bt_m23_adc_trig_cfg_t stcBtTrigAdc; stc_bt_m23_dt_cfg_t stcBtDeadTimeCfg; stc_bt_m23_bk_input_cfg_t stcBtBrakeCfg; DDL_ZERO_STRUCT(stcBtBaseCfg); DDL_ZERO_STRUCT(stcBtPortCmpCfg); DDL_ZERO_STRUCT(stcBtTrigAdc); DDL_ZERO_STRUCT(stcBtDeadTimeCfg); Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能 stcBtBaseCfg.enWorkMode = BtWorkMode3; //三角波模式 stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK stcBtBaseCfg.enPRS = pclk_div;//BtPCLKDiv16; //PCLK/x 分频 //stcBtBaseCfg.enCntDir = BtCntUp; //向上计数,在三角波模式时只读 stcBtBaseCfg.enPWMTypeSel = BtComplementaryPWM; //互补输出PWM stcBtBaseCfg.enPWM2sSel = BtSinglePointCmp; //单点比较功能 stcBtBaseCfg.bOneShot = FALSE; //循环计数 stcBtBaseCfg.bURSSel = FALSE; //上下溢更新 Bt_Mode23_Init(TIM0, &stcBtBaseCfg); //TIM0 的模式23功能初始化 Bt_M23_ARRSet(TIM0, u16Period, TRUE); //设置重载值,并使能缓存 Bt_M23_CCR_Set(TIM0, BtCCR0A, u16CHxACompare); //设置比较值A,(PWM互补模式下只需要设置比较值A) stcBtPortCmpCfg.enCH0ACmpCtrl = BtPWMMode2; //OCREFA输出控制OCMA:PWM模式2 stcBtPortCmpCfg.enCH0APolarity = BtPortPositive; //正常输出 stcBtPortCmpCfg.bCh0ACmpBufEn = TRUE; //A通道缓存控制 stcBtPortCmpCfg.enCh0ACmpIntSel = BtCmpIntNone; //A通道比较控制:无 stcBtPortCmpCfg.enCH0BCmpCtrl = BtPWMMode2; //OCREFB输出控制OCMB:PWM模式2(PWM互补模式下也要设置,避免强制输出) stcBtPortCmpCfg.enCH0BPolarity = BtPortPositive; //正常输出 //stcBtPortCmpCfg.bCH0BCmpBufEn = TRUE; //B通道缓存控制使能 stcBtPortCmpCfg.enCH0BCmpIntSel = BtCmpIntNone; //B通道比较控制:无 Bt_M23_PortOutput_Cfg(TIM0, &stcBtPortCmpCfg); //比较输出端口配置 stcBtBrakeCfg.bEnBrake = TRUE; /*刹车使能*/ stcBtBrakeCfg.enBkCH0AStat = BtCHxBksLow; /*IO输出为低*/ stcBtBrakeCfg.enBkCH0BStat = BtCHxBksLow; /*IO输出为低*/ Bt_M23_BrakeInput_Cfg(TIM0, &stcBtBrakeCfg); u8ValidPeriod = 1; //事件更新周期设置,0表示三角波每半个周期更新一次,每+1代表延迟半个周期 Bt_M23_SetValidPeriod(TIM0,u8ValidPeriod); //间隔周期设置 stcBtDeadTimeCfg.bEnDeadTime = TRUE; stcBtDeadTimeCfg.u8DeadTimeValue = DeadTime; Bt_M23_DT_Cfg(TIM0, &stcBtDeadTimeCfg); //死区配置 u16CntValue = 0; Bt_M23_Cnt16Set(TIM0, u16CntValue); //设置计数初值 Bt_ClearAllIntFlag(TIM0); //清中断标志 Bt_Mode23_EnableIrq(TIM0,BtUevIrq); //使能TIM0 UEV更新中断 EnableNvic(TIM0_IRQn, IrqLevel0, TRUE); //TIM0中断使能 } //端口配置初始化 static void BSP_Timer0PortCfg(void) { stc_gpio_cfg_t stcTIM0Port; //结构体初始化清零 DDL_ZERO_STRUCT(stcTIM0Port); Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); //GPIO 外设时钟使能 stcTIM0Port.enDir = GpioDirOut; Gpio_Init(GpioPortA, GpioPin0, &stcTIM0Port); Gpio_SetAfMode(GpioPortA,GpioPin0,GpioAf7); //PA00设置为TIM0_CHA Gpio_Init(GpioPortA, GpioPin1, &stcTIM0Port); Gpio_SetAfMode(GpioPortA,GpioPin1,GpioAf3); //PA01设置为TIM0_CHB } /*带死区的周期4ms的互补PWM*/ void BSP_PWM_Config(void) { App_Timer0Cfg(6000, BtPCLKDiv16,3000,0x80); //Timer0 配置:周期 6000(T= 4ms); 通道A比较值2400; 通道B比较值互补模式不需要设置 BSP_Timer0PortCfg(); //Timer0 Port端口配置 Bt_M23_EnPWM_Output(TIM0, TRUE, FALSE); //TIM0 端口输出使能 Bt_M23_Run(TIM0); //TIM0 运行 } /*带死区的2路互补pwm输出(250ms+150usHighPuls)*/ void BSP_2Comp_PWM_Config(void) { uint16_t BCompare = 100; // 理论计算值为15 App_Timer0Cfg(23700, BtPCLKDiv256, 23700 - BCompare, 0x80); // 通道B比较值互补模式不需要设置 BSP_Timer0PortCfg(); //Timer0 Port端口配置 Bt_M23_EnPWM_Output(TIM0, TRUE, FALSE); //TIM0 端口输出使能 Bt_M23_Run(TIM0); //TIM0 运行 } /*duty : 0~99*/ void BSP_PWM_SetDuty(uint8_t duty) { Bt_M23_CCR_Set(TIM0, BtCCR0A, 6000 - 6000*duty/100); //设置通道A比较值 } /******************************************************************************* * TIM0中断服务函数 ******************************************************************************/ void Tim0_IRQHandler(void) { //Timer0 模式23 更新中断 if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq)) { Bt_ClearIntFlag(TIM0,BtUevIrq); //清中断标志 } }
复制代码欢迎留言点赞!