在增量式编码器位置计数过程中,每经过一个计数溢出,根据运转方向,在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是否溢出,如溢出则做一次修正,确保两个数据都处于快照状态。