书接上回,上章我们讲到原理,本章我们来聊聊实现。
在笔者的实际项目经历中,梯形加减速运用的比较广泛,主要以其优秀的加减速能力、对算法实现资源的需求较小、实现难度适中而被广泛应用。下面就简单介绍一下基于MCU的算法实现过程,以STM32为例。
采用“梯形”加减速算法,在运动过程中分成以下四个状态:空闲状态,加速状态,匀速状态与减速状态。
脉冲产生单元:用来产生指定频率的脉冲信号。
脉冲计数单元:用来记录各个运动状态下输出的脉冲个数。
脉宽计算单元:根据总的脉冲个数及记录的各个运动状态下的脉冲输出个数,进行状态跳转及速度计算。
脉冲产生单元
初始化STM32定时器,在定时器中断里面,翻转IO口,输出脉冲信号。
//初始化定时器功能,用来翻转IO信号,产生脉冲输出信号
//初始化定时器功能,用来翻转IO信号,产生脉冲输出信号
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, DISABLE); //不使能TIMx
}
//设置定时器值,用来产生指定频率的脉冲信号
void Motor0TimeSet(unsigned int ARR,bool TimeEnable)
{
TIM3->ARR = (uint16_t)ARR;
if(TimeEnable) TIM_Cmd(TIM3, ENABLE);
else TIM_Cmd(TIM3, DISABLE);
}
//翻转IO
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update );
MotorPulsePinOut(&MotorControl[0]);
}
}
脉冲计数单元
用来记录各个阶段输出的脉冲信号;根据设置的值和输出脉冲进行加减速状态切换。
void MotorRunState(MOTOR_CTRL *Motor)
{
switch(Motor->NowState.RunState)
{
case MIDLE://开始
Motor->NowState.AllowMaxAddStep = Motor->SetData.RunStep/2;
Motor->NowState.RunState = MACC;
break;
case MACC://加速状态
Motor->NowState.AddStep ++;
Motor->NowState.RunStep ++;
if(Motor->NowState.AddStep >= Motor->NowState.AllowMaxAddStep)//三角形加速
Motor->NowState.RunState = MDEC;
else if(Motor->NowState.Speed >= Motor->SetData.SpeedMax)
Motor->NowState.RunState = MKEEP;
break;
case MKEEP://最大速度阶段
Motor->NowState.RunStep ++;
if(Motor->NowState.AddStep >= Motor->SetData.RunStep - Motor->NowState.RunStep)
Motor->NowState.RunState = MDEC;
break;
case MDEC://减速阶段
Motor->NowState.RunStep ++;
if(Motor->NowState.RunStep >= Motor->SetData.RunStep)//脉冲输出完成
{
Motor->TimeSet_Call_Back(Motor->NowState.TimeCountNum,false);//关闭定时器,停止脉冲信号输出
Motor->NowState.SysState = MOV_IDLE;
Motor->NowState.Consequence = 0; //执行结果
}
}
if(Motor->NowState.SysState)Motor->TimeSet_Call_Back(Motor->NowState.TimeCountNum,true);//设置下一次脉冲输出频率
}
速度计算单元
根据当前处于电机加减速的那个状态,进行速度计算。采用定时1MS计算一次速度的方式。
void MotorCalculateSpeed(MOTOR_CTRL *Motor)
{
switch(Motor->NowState.RunState)
{
case MIDLE:
Motor->NowState.Speed = Motor->SetData.Speed0;
break;
case MACC:
Motor->NowState.Speed += Motor->SetData.SpeedAdd;
if(Motor->NowState.Speed > Motor->SetData.SpeedMax)
Motor->NowState.Speed = Motor->SetData.SpeedMax;
break;
case MKEEP:
Motor->NowState.Speed = Motor->SetData.SpeedMax;
break;
case MDEC:
Motor->NowState.Speed -= Motor->SetData.SpeedAdd;
if(Motor->NowState.Speed < Motor->SetData.Speed0)
Motor->NowState.Speed = Motor->SetData.Speed0;
break;
}
if(Motor->NowState.Busy)
{
Motor->NowState.TimeCountNum = 1000*1000/Motor->NowState.Speed;//计算定时器应该重装的值
Motor->NowState.MotorRunTime++;//统计电机运行时间
}
}
以上是设计的核心思想和算法,旨在抛砖引玉,各位看官有更好的算法实现请在评论区留言,多多交流。若各位看官需要完整工程代码,请关注公众号或评论区私信留言。
好了,今天的分享就到这里。
各位看官,我们下期再见。
标签:TIM3,浅谈,嵌入式,NVIC,TIM,Motor,NowState,MCU,SetData From: https://blog.csdn.net/2401_84369443/article/details/139578067