第一部分 定时器输出频率可变的PWM信号 1.首先来看一下定时器输出PWM的几种模式 此处我们采用011翻转模式,该模式下当TIMx_CCR1=TIMx_CNT时翻转电平,经常用来调节占空比。此处我们可以不断地跟换TIMx_CNT,来产生PWM波。也可以产生一个固定频率的中断。由于作者一块芯片上驱动很多电机,所以采用同一个定时器来作为PWM输出和作为频率调整的定时器。如图所示
如上图,我们将ARR设置为最大65536,通过不断地修改CCRx的值进行电平翻转,然后实现修改频率。
2.程序相关配置,以STM32F407的TIM13为例
TIM_TimeBaseStructure.TIM_Prescaler=83;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period=65535;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM13,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState= TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM13, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Disable);
设置计数周期为1M,这里可以自己修改。由于有计步需求和频率调整,我开启了比较中断和更新中断(用作计算加减速的频率),初始化未开启PWM输出,在需要的时候开启输出
TIM_ITConfig(TIM13,TIM_IT_CC1|TIM_IT_Update,ENABLE );
NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM13, ENABLE);
TIM_CCxCmd(TIM13,TIM_Channel_1,TIM_CCx_Disable);
以上是定时器的配置和中断配置。接下来就是CCRx值得修改,计算CCRx值应该是多少。根据以上配置计数周期是1Mhz,例如我们需要产生一个10khz的PWM,就是1M/10k,一个周期两次翻转,就是1M/10k/2.所以CCRx就等于上次的CCRx值加上计算的比较值几:CCRx=CCRx+1M/10k/2。以下就是中断里边的计算操作
if(TIM_GetITStatus(TIM13, TIM_IT_CC1) != RESET)
{
MCR.count++;
if(MCR.count>=MCR.trip)
{
TIM_CCxCmd(TIM13,TIM_Channel_1,TIM_CCx_Disable);
}
parr=1000000/MCR.Nspeed/2;
TIM_ClearITPendingBit(TIM13,TIM_IT_CC1);
TIM13->CCR1 = TIM13->CCR1+parr;
}
else
TIM_ClearITPendingBit(TIM13,TIM_IT_CC1);
}
在中断里边不断地更新TIM13->CCR1的值。并进行计步,行程结束就停止输出。
第二部分 加减速曲线 这里采用的是S型加减速, 此处算法参考https://wenku.baidu.com/view/86c9fc305c0e7cd184254b35eefdc8d376ee14ae.html 这里作者采用的是直接在中断里边计算当前速度,强烈建议没有硬件FPU的话或者调节速度更快的话,最好将速度计算好放进数组进行调用。 规定加减速的几种状态
enum motor_run_state
{
SPEED_INCREASE=0,
SPEED_STABLE,
SPEED_DECREASE,
DISENABLE_SPEED
} ;
在中断里边不断地计算调整速度
if(TIM_GetITStatus(TIM13,TIM_IT_Update)!=RESET)
{
if(MCR[Motor_PushCardX].speed_state==SPEED_INCREASE)
{
MCR.runCount++;
if((MCR.Nspeed>=(MCR.Target_speed-50))&&(MCR.speed_state==SPEED_INCREASE))
{
MCR.runCount=0;
MCR.speed_state=SPEED_STABLE;
MCR.Nspeed=MCR.Target_speed;
}
else
{
MCR.Nspeed=(int)MCR.Target_speed/(1.0+exp((0-(14.0/MCR.speedUpCount)*MCR.runCount+7)))+MCR.incminspeed;
}
}
else if(MCR.speed_state==SPEED_DECREASE)
{
MCR.runCount++;
if((MCR.Nspeed<=(MCR.decminSpeed+50))&&(MCR.speed_state==SPEED_DECREASE))
{
MCR.runCount=0;
MCR.speed_state=SPEED_STABLE;
MCR.Nspeed=MCR.decminSpeed;
}
else
{
MCR.Nspeed=(int)MCR.Target_speed/(1.0+exp(-(0-(14.0/MCR.slowCount)*MCR.runCount+7)));
}
}
}
TIM_ClearITPendingBit(TIM13,TIM_IT_Update);
}
MCR.Nspeed:当前速度 MCR.Target_speed目标速度 MCR.speedUpCount加速到目标速度需要的次数 MCR.slowCount 减速到最小速度的次数。
以上仅供参考
|