对于经常接触单片机控制步进电机 伺服电机的工程师来说, 步进电机加减速可以有各种实现方法, 本来有可以用的驱动, 可是我总感觉有什么不完善的地方, 抽时间写了个感觉功能足够完善的, 共享一下, 也希望有大神指点指点, 给点意见,

  实现的功能有  查表法加减速控制, 可以运动过程中限制最大速度, 运功过程中重新设置目标位置, 如果设置的目标位置在另一方向 或者 在减速范围之内, 会自动减速停止后反向运行到目标位置。 Offset可以对应当前速度, 两个Pos是以脉冲数定义的电机绝对位置, 方向使用了 -1,0 +1, Pos直接 + 方向 来累积位置。

调用方法: 直接设置目标位置, 根据是否停止 决定是否在此设置方向, 其实不设置也没问题, 如果方向不对,中断函数内 也会走错误的方向一步后自动调转方向,  感觉不严谨, so do it here。。。

{
        motTurn.aimPos   =    xxxxxxxx;
         if(0 == motTurn.Offset)    // 检查停止, 停止可以设置方向, 否则直接en tim
         {
             if(motTurn.aimPos > motTurn.curPos)
                 TurnDir(Right);
             else TurnDir(Left);
         }  delay_us(5);
         Turn_Enable(ENABLE);}
 
typedef enum     // 方向 枚举
 {
     Left = (char)-1, Stop = (char)0, Right = (char)1
 }Dir;typedef struct    // 电机主要数据结构体
 {
     s32 aimPos;
     s32 curPos;         //根据 发送的 pluse 确定的位置, 右转为正, 左转为负, 校准时置零
     u16 Offset;          //  查表偏移    Dir dir;      //  -1 Left, 1 Right,  0, Stop
     u8  err;
 };MOT_DAT motTurn;
 void TIM2_IRQHandler(void)   //TIM2中断, 全部的 电机驱动都在这个中断中
 {    
     static s32 lastAimPos,  newPwmNum;   //保存的上次目标 位置,   新的需要移动脉冲量
     static u32 pwm_num=0;   //剩余需要发送 脉冲数
     static u8  last_dir=0, stopCal = 0;    //
     
     if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)    //检查TIM2 ccr2比较中断 发生与否
     {                      
         .curPos += motTurn.dir;        //  不管还有没有脉冲数,  进此中断, 一个脉冲就发完了, 需要位置 计数                                                                
         
         if(lastAimPos != motTurn.aimPos)    //    允许 运动过程中 调整目标位置
         {
             lastAimPos = motTurn.aimPos;
             newPwmNum  = motTurn.aimPos - motTurn.curPos;
             
 //    u32 calPlusNum(u8* stopCalFlag)   // use motTurn    这里这个函数未提取出去,                 //为了可以随意设置目标位置,而不需 检查停止
 //{
             if(0 == pwm_num)
             {
                 if(newPwmNum > 0)
                 {
                     TurnDir(Right);
                     pwm_num = newPwmNum;
                 }
                 else
                 {
                     TurnDir(Left);
                     pwm_num = -newPwmNum;                    
                 }
             }else
             {
                 if(newPwmNum > 0)
                 {
                     if(motTurn.dir == Right)
                     {
                         if(pwm_num > newPwmNum)
                         {
                             if(newPwmNum >= SP_OFF_MAX)
                                 pwm_num = newPwmNum;
                             else
                                 stopCal = 1;        // 需要停止后  计算, 反向移动
                         }else
                             pwm_num = newPwmNum;
                     }else
                         stopCal = 1;
                 }else
                 {
                     newPwmNum = -newPwmNum;
                     if(motTurn.dir == Left)
                     {
                         if(pwm_num > newPwmNum)
                         {
                             if(newPwmNum >= SP_OFF_MAX)
                                 pwm_num = newPwmNum;
                             else
                                 stopCal = 1;        // 需要停止后 反向移动
                         }else
                             pwm_num = newPwmNum;
                     }else
                         stopCal = 1;
                 }
             }
         }
 //}
         if(pwm_num > motTurn.Offset)                         //    确定处于加速还是减速过程
         {
             if(motTurn.Offset < SP_OFF_MAX)                            //need 加速  每个电机的加速表最大值
                 motTurn.Offset++;
             else if(motTurn.Offset > SP_OFF_MAX)                    //need 减速
                 motTurn.Offset--;
         }
         else if(motTurn.Offset)                                                 //need 减速
             motTurn.Offset--;        if(pwm_num)                                                        //未走完, 计位置,重装值
         {
             pwm_num--;
             TIM_SetAutoreload(TIM2, pwm_value2[motTurn.Offset]);    
             TIM_SetCompare2(  TIM2, pwm_value2[motTurn.Offset]/4);
         }else            //                          //走完了 停止 或者 需要反向 走
         {
         }else            //if(pwm_nu == 0)        //走完了, 或限位了, 停止...
         {
             if(stopCal)  //需要停止后  再计算反向步数, 反向运行      --为了可以随意设置目标位置,而不需 先停止
             {
                 newPwmNum = motTurn.aimPos - motTurn.curPos;
                 if(newPwmNum > 0)
                 {
                     TurnDir(Right);
                     pwm_num = newPwmNum;
                 }
                 else
                 {
                     TurnDir(Left);
                     pwm_num = -newPwmNum;
                 }
                 stopCal = 0;
             }else    // 目标到达, 停止
             {
                 Turn_Enable(DISABLE);//关闭pwm    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
                 motTurn.Offset=0;    //            return;
             }
         }
         TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);  //清除TIMx更新中断标志  
     }
 }