回顾下之前的章节:
本文我们再介绍下定时器的使用,以及如何产生普通占空比PWM以及互补带死区的PWM。
定时是一个很重要的功能,人类无法改变时间但可以想办法掌控利用时间。
人类最早使用的工具是沙漏或水漏,这一瓢水漏完就是一个时辰,该下课了;这一桶水漏完就是三个时辰,该下班了。
在沙漏或者水漏的例子中,时间是如何计算的呢?
t = count * △t
△t是一坨沙/一滴水落下的时间,count为计数,这就是定时器的基本原理。
在嵌入式软件领域,定时器是系统工作的基础,什么时候该做什么事情,要求的极其精确,它的工作原理就是时基+计数。
一般参数定义为prescaler和period,假设MCU的时钟频率为100MHz,prescaler=999,period=9,那么:
我们软件就可以基于这个100us的定时进行业务处理。
具体代码可以参见:串口和CRC那一篇。
PWM的全称是脉冲宽度调制(Pulse Width Modulation),从应用的角度来理解,就是频率可以控制,宽度也可以控制的方波信号;在工业控制领域,可以通过PWM来调节明暗,快慢,大小,使用范围极其广泛。
PWM的介绍比较多了,直接给代码:
GD32:
static uint32_t get_alt_func_num(uint32_t TIMx)
{
switch (TIMx)
{
case TIMER0:
case TIMER1:
return GPIO_AF_1;
case TIMER2:
case TIMER3:
case TIMER4:
return GPIO_AF_2;
case TIMER7:
case TIMER8:
case TIMER9:
case TIMER10:
return GPIO_AF_3;
default:
return GPIO_AF_9;
}
}
static void timerx_PWM_init(uint32_t TIMx, uint16_t TIMCHx, rcu_periph_enum rcu, uint32_t gpio, uint16_t pin, uint16_t pulse)
{
timer_oc_parameter_struct timer_ocintpara;
gpio_init(rcu, gpio, GPIO_MODE_AF, get_alt_func_num(TIMx), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, pin);
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = 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_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMx, TIMCHx, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMx, TIMCHx, pulse);
timer_channel_output_mode_config(TIMx, TIMCHx, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMx, TIMCHx, TIMER_OC_SHADOW_DISABLE);
timer_primary_output_config(TIMx, ENABLE);
timer_auto_reload_shadow_enable(TIMx);
timer_enable(TIMx);
}
STM32:
static void get_oc_func(uint32_t TIMCHx, void (**TIM_OCInit)(TIM_TypeDef*, TIM_OCInitTypeDef*), void (**TIM_OCPreloadConfig)(TIM_TypeDef*, uint16_t))
{
switch (TIMCHx)
{
case TIM_Channel_1:
*TIM_OCInit = TIM_OC1Init;
*TIM_OCPreloadConfig = TIM_OC1PreloadConfig;
break;
case TIM_Channel_2:
*TIM_OCInit = TIM_OC2Init;
*TIM_OCPreloadConfig = TIM_OC2PreloadConfig;
break;
case TIM_Channel_3:
*TIM_OCInit = TIM_OC3Init;
*TIM_OCPreloadConfig = TIM_OC3PreloadConfig;
break;
case TIM_Channel_4:
*TIM_OCInit = TIM_OC4Init;
*TIM_OCPreloadConfig = TIM_OC4PreloadConfig;
break;
}
}
static void timerx_PWM_init(TIM_TypeDef *TIMx, uint16_t TIMCHx, uint32_t rcc, GPIO_TypeDef *gpio, uint16_t pin, uint16_t pulse)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
void (*TIM_OCInit)(TIM_TypeDef*, TIM_OCInitTypeDef*);
void (*TIM_OCPreloadConfig)(TIM_TypeDef*, uint16_t);
gpio_init(rcc, gpio, GPIO_Mode_AF_PP, GPIO_Speed_2MHz, pin);
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = pulse;
get_oc_func(TIMCHx, &TIM_OCInit, &TIM_OCPreloadConfig);
TIM_OCInit(TIMx, &TIM_OCInitStructure);
TIM_OCPreloadConfig(TIMx, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIMx, ENABLE);
TIM_CtrlPWMOutputs(TIMx, ENABLE);
TIM_Cmd(TIMx, ENABLE);
}
占空比30%:
占空比30%和50%的波形:
占空比30%和50%的波形
代码比较简单,这里说一下死区时间的配置。
芯片手册中的描述:
死区芯片手册描述
推导下计算公式:
画个图:
死区公式
GD32代码:
static void timerx_PWM_ON_init(uint32_t TIMx, uint16_t TIMCHx, rcu_periph_enum rcu, uint32_t gpio, uint16_t pin, rcu_periph_enum rcuN, uint32_t gpioN, uint16_t pinN, uint16_t pulse, uint16_t deadtime)
{
timer_oc_parameter_struct timer_ocintpara;
timer_break_parameter_struct breakpara;
gpio_init(rcu, gpio, GPIO_MODE_AF, get_alt_func_num(TIMx), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, pin);
gpio_init(rcuN, gpioN, GPIO_MODE_AF, get_alt_func_num(TIMx), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, pinN);
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(TIMx, TIMCHx, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMx, TIMCHx, pulse);
timer_channel_output_mode_config(TIMx, TIMCHx, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMx, TIMCHx, TIMER_OC_SHADOW_DISABLE);
timer_break_struct_para_init(&breakpara);
breakpara.deadtime = deadtime;
breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
timer_break_config(TIMx, &breakpara);
timer_primary_output_config(TIMx, ENABLE);
timer_auto_reload_shadow_enable(TIMx);
timer_enable(TIMx);
}
STM32代码:
static void timerx_PWM_ON_init(TIM_TypeDef *TIMx, uint16_t TIMCHx, uint32_t rcc, GPIO_TypeDef *gpio, uint16_t pin, uint32_t rccN, GPIO_TypeDef *gpioN, uint16_t pinN, uint16_t pulse, uint16_t deadtime)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
void (*TIM_OCInit)(TIM_TypeDef*, TIM_OCInitTypeDef*);
void (*TIM_OCPreloadConfig)(TIM_TypeDef*, uint16_t);
gpio_init(rcc, gpio, GPIO_Mode_AF_PP, GPIO_Speed_2MHz, pin);
gpio_init(rccN, gpioN, GPIO_Mode_AF_PP, GPIO_Speed_2MHz, pinN);
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_Pulse = pulse;
get_oc_func(TIMCHx, &TIM_OCInit, &TIM_OCPreloadConfig);
TIM_OCInit(TIMx, &TIM_OCInitStructure);
TIM_OCPreloadConfig(TIMx, TIM_OCPreload_Enable);
TIM_BDTRStructInit(&TIM_BDTRInitStructure);
TIM_BDTRInitStructure.TIM_DeadTime = deadtime;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIMx, &TIM_BDTRInitStructure);
TIM_CtrlPWMOutputs(TIMx, ENABLE);
TIM_ARRPreloadConfig(TIMx, ENABLE);
TIM_Cmd(TIMx, ENABLE);
}
在STM32中,复用的管脚需要配置,示例:
void timer1_ch2_pwm_ON_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE);
timerx_PWM_ON_init(TIM1, TIM_Channel_2, RCC_APB2Periph_GPIOE, GPIOE, GPIO_Pin_11, RCC_APB2Periph_GPIOE, GPIOE, GPIO_Pin_10, 70, 0xFF);
}
互补PWM波形:
互补PWM
死区时间5.12us:
死区时间5.12us
死区时间10.08us:
死区时间10.08us
--EOF--
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有