在增量式編碼器位置計數過程中,每經過一個計數溢出,根據運轉方向,在update中斷里我們會對圈數加1或者減1
if ((TIMx->SR & TIM_FLAG_Update) == TIM_FLAG_Update) { /* Clear the interrupt pending flag */ TIM_ClearFlag(TIMx, TIM_FLAG_Update); /*record number of turns*/ if ((TIMx->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {/* encoder timer down-counting*/ pDVars_str->NbofTurns--; } else {/* encoder timer up-counting*/ pDVars_str->NbofTurns++; } }
這樣,計算當前位置時,采用
position = (int32_t)(pDVars_str->NbofTurns) * (int32_t)(pDParams_str->hPulseNumber) + TIMx->CNT;
但這樣會存在一個問題,由於NbofTurns與CNT沒有辦法同時讀取,也就是拍快照保存,這樣會導致一個問題,溢出發生在取兩個參與計算值中間,導致一個數據是溢出前采集,一個數據是溢出觸發中斷,經過中斷處理后采集,這樣就會使最終計算得到的位置信息恰好與實際值偏離出一個圈數的脈沖值。
改進思路是讀取時關閉update中斷,然后讀取兩個值
/*Disable update interrupts to have NbofTurns and CNT of the same period*/ TIMx->DIER &= (uint16_t)~TIM_IT_Update; /* NB:Std libray not used for perf issues*/ cnt = TIMx->CNT; NbofTurns = pDVars_str->NbofTurns; TIMx->DIER |= TIM_IT_Update; /* NB:Std libray not used for perf issue*/
然而這樣還是存在問題,中斷響應雖然暫時關閉了,但CNT的計數為了不遺漏位置信息而不能關閉,還是會造成事實溢出。最終改進代碼如下
/*Disable update interrupts to have NbofTurns and CNT of the same period*/ TIMx->DIER &= (uint16_t)~TIM_IT_Update; /* NB:Std libray not used for perf issues*/ cnt = TIMx->CNT; NbofTurns = pDVars_str->NbofTurns; if((TIMx->SR & TIM_FLAG_Update) == TIM_FLAG_Update) { if((TIMx->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {/* encoder timer down-counting*/ if(cnt > (pDParams_str->hPulseNumber/2)) { NbofTurns--; } } else {/* encoder timer up-counting*/ if(cnt < (pDParams_str->hPulseNumber/2)) { NbofTurns++; } } } TIMx->DIER |= TIM_IT_Update; /* NB:Std libray not used for perf issue*/ position = (int32_t)(NbofTurns) * (int32_t)(pDParams_str->hPulseNumber) + cnt;
在關閉中斷確保NbofTurns處於快照狀態,再判斷一次讀取到的CNT是否溢出,如溢出則做一次修正,確保兩個數據都處於快照狀態。