一般情况下我们在控制指定数目PWM输出的时候,都是采用在对每一次的脉冲中断进行,虽然也能产生对硬件的PWM脉冲数目精确控制,但却是通过对每一次的脉冲都进行计数实现的,然而有的情况下我们用到PWM脉冲周期可能会达到us级甚至更低,这样的情况下,对于中断频繁计数脉冲这种状况,会非常的占用MCU的资源,甚至严重的情况下 可能会影响到程序的运行。下面介绍一种,无需对脉冲个数每个都进行计数而是产生指定脉冲个数后在中断中停止的方法。
同样,这种方法用到的是定时器的同步模式,可以通过中文参考手册找到。如下图
在这里用到的就是一个定时器作为另一个定时器的预分频器。
先说一下整体思路
程序用到的是定时器4和定时器3,定时器4作为主定时器,定时器3作为从定时器。(为了简单方便下面名字采用T4和T3)
T4的输出比较OC1产生PWM作为T3的脉冲时钟,同时T3不做分频处理,这样的话就可以直接对T4产生的脉冲数计数,我们先设置好T3的溢出个数,当T3的计数器数到指定的个数就会触发更新中断,然后在中断函数里对T4的OC1的比较值置0,即可停止计数。同时将T3的计数器设置成0,以备下一次计数。
以上便是过程分析,这种思路即可以达到us级甚至更低,而且不会对程序的主函数造成影响(如果T3预设的值比较小,而且时间太短且频繁的话也会有影响,但是考虑到一般情况下如果达到us级的脉冲个数一般都是一次计数几万或者几十万上百万的个数,当数完这些就得需要几十毫秒的时间,基本上对主函数程序没有影响)
下面列出定时器初始化过程和中断函数的简单处理
void PWM_Tim3Init(unsigned int pres,unsigned int period) {TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct;NVIC_InitTypeDef NVIC_InitTypeStruct;TIM_OCInitTypeDef TIM_OCInitTypeStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);TIM_TimeBaseInitTypeStruct.TIM_Prescaler=pres;TIM_TimeBaseInitTypeStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitTypeStruct.TIM_Period=period;TIM_TimeBaseInitTypeStruct.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitTypeStruct);TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);NVIC_InitTypeStruct.NVIC_IRQChannel=TIM3_IRQn;NVIC_InitTypeStruct.NVIC_IRQChannelPreemptionPriority=2;NVIC_InitTypeStruct.NVIC_IRQChannelSubPriority=2;NVIC_InitTypeStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitTypeStruct);TIM_SelectInputTrigger(TIM3,TIM_TS_ITR3);TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1);TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable);TIM3->CNT=0X00;TIM_Cmd(TIM3,ENABLE);}
void PWM_Tim4Init(unsigned int pres,unsigned int period) {GPIO_InitTypeDef GPIO_InitTypeStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct;TIM_OCInitTypeDef TIM_OCInitTypeStruct;NVIC_InitTypeDef NVIC_InitTypeStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitTypeStruct);TIM_TimeBaseInitTypeStruct.TIM_Prescaler=pres;TIM_TimeBaseInitTypeStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitTypeStruct.TIM_Period=period;TIM_TimeBaseInitTypeStruct.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitTypeStruct);TIM_OCInitTypeStruct.TIM_OCMode=TIM_OCMode_PWM1;TIM_OCInitTypeStruct.TIM_OutputState=TIM_OutputState_Enable;TIM_OCInitTypeStruct.TIM_Pulse=0;TIM_OCInitTypeStruct.TIM_OCPolarity=TIM_OCPolarity_High;TIM_OCInitTypeStruct.TIM_OCIdleState=TIM_OCIdleState_Set;TIM_OC1Init(TIM4,&TIM_OCInitTypeStruct);TIM_CtrlPWMOutputs(TIM4,ENABLE);TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_OC1Ref); TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);}
void TIM3_IRQHandler(void) {if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {TIM_SetCompare1(TIM4,0); //定时器4停止产生PWM,这样定时器3的时钟就停止了。如果重新开始计数只需重新设置即可TIM_ClearITPendingBit(TIM3, TIM_IT_Update );}}
#include "stm32f10x.h"#include "time.h"............int main(){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);MotorPWM_Tim3Init(0,CountValue); PWM_Tim4Init(71,Value);SetPWMValue(TIM4,1,Value/2);TIM_Cmd(TIM4,ENABLE);while(1){}}