步進伺服電機加減速 及 位置速度控制關鍵程序

    對於經常接觸單片機控制步進電機 伺服電機的工程師來說, 步進電機加減速可以有各種實現方法, 本來有可以用的驅動, 可是我總感覺有什麼不完善的地方, 抽時間寫了個感覺功能足夠完善的, 共享一下, 也希望有大神指點指點, 給點意見,有問題 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更新中斷標誌  
    }
}

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