?
?
我們在基于ST的標(biāo)準(zhǔn)庫或基于CubeMx建立工程,當(dāng)用到定時器并啟用其更新中斷時,可能會遇到一使能定時器中斷且計算器還未開始計數(shù)就立即進(jìn)入更新中斷服務(wù)程序的情況。
?
可能出現(xiàn)該現(xiàn)象的場合大概像下面樣子,即先使能定時器更新中斷,然后才去啟動計數(shù)器。
?
?
我們會發(fā)現(xiàn),剛一使能更新中斷還未啟動計數(shù)器,結(jié)果就跑到更新中斷服務(wù)程序里。
?
看看下面截圖,右邊TIMER控制寄存器CEN還未置1,SR寄存器里的UIF【更新事件標(biāo)志】已經(jīng)置1了。
?
?
也就是說,計數(shù)器還沒開始啟動就先進(jìn)了一次更新中斷。
?
這種情況很多時候?qū)ξ覀儜?yīng)用可能并無妨礙,但有時也可能帶來些問題或麻煩。比方:
?
1、誤動作。本來打算基于定時器運(yùn)作延時特定時間后再在更新中斷里完成的動作,這樣一來就會出現(xiàn)計數(shù)器還未開始工作就進(jìn)中斷執(zhí)行當(dāng)前本不該執(zhí)行的動作了。
2、誤計算。當(dāng)我們基于定時器捕獲功能進(jìn)行信號周期、占空比測量過程中,如果需要統(tǒng)計更新事件時,就有可能因為統(tǒng)計這個不該統(tǒng)計的更新事件而帶來誤差。
?
該問題怎么產(chǎn)生的呢?
問題是由于我們的TIMER初始化函數(shù)里,在對ARR/PSC等時基參數(shù)做好初始賦值后,軟件做了個手動產(chǎn)生更新事件的操作,目的就是讓剛才設(shè)置的那些時基參數(shù)立即生效,并讓定時器基于這些新設(shè)置的參數(shù)開始運(yùn)行。
?
代碼大致是下面的層次結(jié)構(gòu)及內(nèi)容:
?
MX_TIM_Inxit(); ==》
HAL_TIM_Base_Init(&htim)==》
TIM_Base_SetConfig()
?
void TIM_Base_SetConfig(TIM_TypeDef *TIMx,TIM_Base_InitTypeDef *Structure)
{
…..
/* Set the auto-reload preload */
MODIFY_REG(tmpcr1, TIM_CR1_ARPE, Structure->AutoReloadPreload);
TIMx->CR1 = tmpcr1;
/*Set the Autoreload value */
TIMx->ARR =(uint32_t)Structure->Period ;
/*Set the Prescaler value */
TIMx->PSC = Structure->Prescaler;
if(IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx))
{
/* Set the Repetition Counter value */
TIMx->RCR =Structure->RepetitionCounter;
}
/*Generate an update event to reload the Prescaler
and the repetition counter (only for advanced timer) value immediately*/
TIMx->EGR = TIM_EGR_UG;
}
?
其中,? TIMx->EGR = TIM_EGR_UG;這行代碼就是用來手動產(chǎn)生更新事件的。
?
我們知道,STM32定時器中有幾個由預(yù)裝寄存器和影子寄存器組成的寄存器組,他們分別是TIMx_PSC,TIMx_ARR,TIMx_CCR,TIMx_RCR. 【注:基本定時器或通用定時器沒有RCR寄存器】
那么如何消除這個問題呢?操作很簡單,TIMER初始化完成之后,使能定時器更新中斷之前加一句清除更新中斷請求位的代碼即可。比方類似下面操作。
或許有人問,我在TIMER初始化過程中自己組織代碼時沒有手動產(chǎn)生更新事件似乎也沒啥問題?定時器跑得好好的?即沒有類似下面打叉的語句。
?
?
的確,沒有這句產(chǎn)生更新事件的代碼定時器也能跑。
?
芯片復(fù)位后,ARR的預(yù)裝功能默認(rèn)關(guān)閉,此時改寫ARR預(yù)裝寄存器相當(dāng)于同時也更新了其影子寄存器【即實際起作用的寄存器】,但PSC和RCR預(yù)裝寄存器的內(nèi)容只能借助溢出產(chǎn)生更新事件更新到其影子寄存器而起作用。
?
我們以向上計數(shù)模式為例,更新事件基于當(dāng)前用戶給定的ARR值計數(shù)一個周期后發(fā)生溢出而產(chǎn)生,隨之新的PSC和RCR值才會生效。即二者的生效時間要延后一個周期。?【注:基本定時器或通用定時器沒有RCR寄存器】
?
如果說有人自行組織代碼,先將ARR的預(yù)裝控制位使能打開,然后才給ARR賦值,同樣不手動產(chǎn)生更新事件,那又會怎么樣呢?拋磚引玉,可以自行結(jié)合手冊琢磨和測試下。
?
?
ST的庫函數(shù)的寫法是合理的,當(dāng)然,如果緊跟著做個更新事件標(biāo)志的清零就更佳了,或許未來這個地方可以再改善下。
?
順便提下,當(dāng)你自己嘗試在代碼里適時而巧妙地使用手動定時器更新操作時,或許會發(fā)現(xiàn)這還是個不可多得的一個小技巧。
?
?
好,這個話題就聊到這里。其實,多年前也在這里分享過該話題,只是沒有單列出來。這次單列出來再分享下,以資提醒。
?
?
審核編輯:湯梓紅
評論
查看更多