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