autoquad使用定時器用作系統擷取時間的來源。該部分在初始化時調用timerInit()函數用來初始化定時器,其内部具體内容如下
void timerInit(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// Enable the TIMER_TIM global Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIMER_IRQ_CH;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIMER_EN;
// stop timer when core halted (debug)
DBGMCU_APB1PeriphConfig(TIMER_CORE_HALT, ENABLE);
/* Time base configuration for 1MHz (us)*/
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (TIMER_CLOCK / 1000000) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIMER_TIM, &TIM_TimeBaseStructure);
// reset
TIM_SetCounter(TIMER_TIM, 0);
timerCancelAlarm1();
timerCancelAlarm2();
timerCancelAlarm3();
timerCancelAlarm4();
// Output Compare for alarms
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC2Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC3Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC4Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
// go...
TIM_Cmd(TIMER_TIM, ENABLE);
}
這裡需要注意的是TIMER_TIM為宏定義,可以在aq_timer.h裡找到
這裡強調必須使用TIM2 or TIM5,因為在stm32f405系列隻有這兩個定時器為32位的。并且其下面配置定時器的周期和分頻系數,代碼如下
/* Time base configuration for 1MHz (us)*/
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (TIMER_CLOCK / 1000000) - 1;
可以看到其溢出計數值為0xFFFFFFFF即最大的32位數,為2^32-1,其分頻系數根據TIMER_CLOCK進行分頻,使其正好分頻到1MHZ,即計數器每過1us自加1。這樣計數器的CNT值即代表從定時器開始運作到目前的時間,并且是以us為機關。
autoquad源碼中多次調用擷取時間的函數原型為擷取定時器CNT的宏定義
這樣從定時器初始化完成後即可調用timerMicros()擷取目前時間。如果你認為定時器隻起到一個計數的作用那你就還是太小瞧autoquad代碼了。定時器還有比較器的功能,其初始化完計數器功能後下面又初始化其比較器部分功能,調用四個取消比較器的功能函數
timerCancelAlarm1();
timerCancelAlarm2();
timerCancelAlarm3();
timerCancelAlarm4();
這四個函數内容基本一緻,我們隻看第一個,代碼如下:
void timerCancelAlarm1(void) {
TIMER_TIM->DIER &= (uint16_t)~TIM_IT_CC1;
TIM_ClearITPendingBit(TIMER_TIM, TIM_IT_CC1);
}
這裡隻是禁止定時器的捕獲/比較 1中斷以及清除中斷标志位。下面的代碼即代表初始化定時器捕獲/比較功能。是以到現在我們還不知道他開啟捕獲功能是幹嘛用的。下面還有一個函數用來設定比較/捕獲功能:
void timerSetAlarm1(int32_t us, timerCallback_t *callback, int parameter) {
// schedule it
timerData.alarm1Callback = callback;
timerData.alarm1Parameter = parameter;
TIMER_TIM->SR = (uint16_t)~TIM_IT_CC1;
TIMER_TIM->CCR1 = TIMER_TIM->CNT + us;
TIMER_TIM->DIER |= TIM_IT_CC1;
}
從名字上來看這是設定通道1的捕獲功能函數,輸入參數為us時間,該參數用在如下位置:
可以看出其将比較器的捕獲時間設定為目前時間+us的時間,然後啟動捕獲比較的中斷功能,也就代表當該函數被調用us時間後會進入定時器比較中斷函數。
還有後面兩個參數timerCallback_t *callback, int parameter,其直接指派到結構體成員變量上,這兩個變量為定時器結構體下的回調函數指針和參數,具體形式如下:
typedef void timerCallback_t(int);
typedef struct {
timerCallback_t *alarm1Callback, *alarm2Callback, *alarm3Callback, *alarm4Callback;
int alarm1Parameter, alarm2Parameter, alarm3Parameter, alarm4Parameter;
uint32_t timerStart;
} timerStruct_t;
然後我們大概已經猜出比較器的用途了,其調用timerSetAlarm函數指定延時時間,當達到比較器門檻值後觸發比較器中斷,這時候在比較器中斷函數裡調用回調函數,即我們在調用timerSetAlarm時指定的函數,就可以達到定時一段時間後運作某個函數的功能。檢視定時器中斷函數内容,可以看到如下内容:
if ((itEnable & TIM_IT_CC1) != RESET && (itStatus & TIM_IT_CC1) != RESET) {
TIMER_TIM->SR = (uint16_t)~TIM_IT_CC1;
// Disable the Interrupt
TIMER_TIM->DIER &= (uint16_t)~TIM_IT_CC1;
timerData.alarm1Callback(timerData.alarm1Parameter);
}
可以看到其在中斷函數内調用了回調函數。這裡我們舉例子說明該部分用法。比如想實作1s後點亮LED燈的功能,可以編寫如下代碼:
這樣1s後即會執行turnOnLed函數,注意這裡turnOnLed函數必須和指定的回調函數結構類似,如下内容:
void turnOnLed(int unuse)
{
//點亮LED具體實作
}
即其傳回值和參數類型必須和回調函數定義的typedef void timerCallback_t(int)一樣。
這就是autoquad關于定時器的使用,其功能主要搭建工程的時間相關功能,後面可以調用timerMicros()擷取系統時間,也可以調用timerSetAlarm1函數進行定時觸發函數的功能。如果覺得寫的不錯就點個贊吧