下面分享GD32F427,基于GD官方库,控制TIMER0 的PWM通道channel0,channel0N和channel2输出PWM,其中channel0和channel0N为互补输出PWM。
本工程中SSysClock为120M。先初始化时钟。初始化完后Get 一下时钟是否正确,APB时钟是否符合datasheet要求。
SysClk = rcu_clock_freq_get(CK_SYS); //120M
HClk = rcu_clock_freq_get(CK_AHB); //120M
PClk1 = rcu_clock_freq_get(CK_APB1); //30M
PClk2 = rcu_clock_freq_get(CK_APB2); //60M
IO初始化:涉及的IO是PE8,PE9,PE12,分别是TIMER0_C H0_ON,TIMER0_C H0,TIMER0_C H2_ON。
datasheet如下:
rcu_periph_clock_enable(RCU_GPIOE);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE,GPIO_PIN_8);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_8);
gpio_af_set(GPIOE, GPIO_AF_1,GPIO_PIN_8);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE,GPIO_PIN_9);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);
gpio_af_set(GPIOE, GPIO_AF_1,GPIO_PIN_9);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE,GPIO_PIN_12);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_12);
gpio_af_set(GPIOE, GPIO_AF_1,GPIO_PIN_12);
下面分享PWM参数。本例输出PWM的频率为40K,互补输出的占空比带死区控制,分频psc和period计算按公式:
PWM周期T = (1+psc)*(1+period)/(SysClock*CLK_DIV);
SysClock 也就是定时器时钟,倍频为到120M,CLK_DIV为分频系数,默认选TIMER_CKDIV_DIV1。
然后是Channel0和Channel0N的输出配置,关注timer_ocintpara 结构体即可。设置通道是否输出,输出极性,空闲状态极性等参数。
然后设置输出的占空比,占空比是比值,参数除period即可得占空比,实际应用中根据需要的占空比倒推出分子即可。
然后设置PWM输出模式和影子设置。
然后是死区设置,死区时间计算:代码如下:
uint8_t deadtime(uint8_t pwmfre_KHz,uint8_t myCLK_MHz, uint8_t mydutyc)
{
float T_TDS;
T_TDS = (float)1000 / myCLK_MHz; // 1000/60 = 16.6666 1000/48 = 20.8333
float DT;//死区时间
DT = (50 - mydutyc) *10000 / pwmfre_KHz; // (50-20)*10000/40 = 7500
uint8_t dt;
if ( DT >= 0 && DT <= T_TDS * 127) //16.666 *127 = 2116
{
dt = (uint8_t)(DT / T_TDS);
}
else if ( DT >= T_TDS * 128 && DT <= T_TDS * 254) //16.666 *128 = 2133.338 16.666 *254=4233
{
dt = (uint8_t)(DT / (2 * T_TDS) + 64 );
}
else if ( DT >= T_TDS * 256 && DT <= T_TDS * 504) //16.666 *256= 4266 16.666 *504 = 8400 ,20.8333333*256=5,333.3333248 , 20.8333333*504=10499
{
dt = (uint8_t)(DT / (8 * T_TDS) + 160 ); // 216, 205
}
else
{
dt = (uint8_t)(DT / (16 * T_TDS) + 192 );
}
return dt;
}
按照输出40Khz PWM脉冲,120M系统时钟,20%占空比,死区计算时间函数为:
deadtime = deadtime(40,120,20);
定时器初始化以及PWM参数初始化代码如下,上代码:
void Drv_PWM_TimerConfig(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
timer_break_parameter_struct timer_breakpara;
rcu_periph_clock_enable(RCU_TIMER0);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
timer_deinit(TIMER0);
/* TIMER0 configuration */
timer_initpara.prescaler = 3-1;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 1000-1;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0,&timer_initpara);
/* CH0/CH0N configuration in PWM mode0 */
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0,TIMER_CH_0,&timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 500);
timer_channel_output_mode_config(TIMER0,TIMER_CH_0,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);
/* automatic output enable, break, dead time and lock configuration*/
timer_breakpara.runoffstate = TIMER_ROS_STATE_ENABLE;//TIMER_ROS_STATE_DISABLE
timer_breakpara.ideloffstate = TIMER_IOS_STATE_ENABLE;//TIMER_IOS_STATE_DISABLE
timer_breakpara.deadtime = 216; //216
timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_HIGH;
timer_breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
timer_breakpara.protectmode = TIMER_CCHP_PROT_0;
timer_breakpara.breakstate = TIMER_BREAK_DISABLE; //TIMER_BREAK_ENABLE
timer_break_config(TIMER0,&timer_breakpara);
/*channel 2 pwm output*/
timer_ocintpara.outputstate = TIMER_CCX_DISABLE; // TIMER_CCX_ENABLE
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE; // TIMER_CCXN_DISABLE
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW; //TIMER_OC_IDLE_STATE_HIGH
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW; //TIMER_OCN_IDLE_STATE_LOW
timer_channel_output_config(TIMER0,TIMER_CH_2,&timer_ocintpara);
timer_channel_output_mode_config(TIMER0,TIMER_CH_2,TIMER_OC_MODE_PWM0);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, 500);
timer_channel_output_mode_config(TIMER0,TIMER_CH_2,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0,TIMER_CH_2,TIMER_OC_SHADOW_DISABLE);
/* TIMER0 primary output function enable */
timer_primary_output_config(TIMER0,ENABLE);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER0);
/* TIMER0 counter enable */
timer_enable(TIMER0);
}
特别注意的是,GD官方库的例程,比如互补输出或者死区控制的,有的参数并不对,比如
timer_breakpara.runoffstate = TIMER_ROS_STATE_ENABLE;//TIMER_ROS_STATE_DISABLE
timer_breakpara.ideloffstate = TIMER_IOS_STATE_ENABLE;//TIMER_IOS_STATE_DISABLE
timer_breakpara.deadtime = 216; //216
timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_HIGH;
timer_breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
timer_breakpara.protectmode = TIMER_CCHP_PROT_0;
timer_breakpara.breakstate = TIMER_BREAK_DISABLE; //TIMER_BREAK_ENABLE
timer_break_config(TIMER0,&timer_breakpara);
里的runoffstate ,ideloffstate ,breakstate ,这些,官方demo里的 是我注释后的参数,并不能正常输出,导致我排查问题找了接近两天,然后对比ST库的函数和参数,才改正过来,才能正常输出。好了 下面上波形。
Channel0 是PE8的输出
Channel1是PE9 的输出
Channel2是PE12的输出