步进伺服电机加减速 及 位置速度控制关键程序

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

  实现的功能有  查表法加减速控制, 可以运动过程中限制最大速度, 运功过程中重新设置目标位置, 如果设置的目标位置在另一方向 或者 在减速范围之内, 会自动减速停止后反向运行到目标位置。 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更新中断标志  
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章