【轉載】1個定時器多處複用的問題
問題: 在一個工程中往往需要用到多個定時,然而我們採用的CPU一般也只有2,3個定時器。顯然是不夠用的,那麼應該怎麼辦呢?
我想如果使用過系統的人都會知道,在系統中有個時鐘節拍,而多個任務都是共同使用這個時鐘節拍進行延時或任務切換。那麼我們是否可以借鑑一下呢?
下面我們LPC2131舉例說明:
①. 巨集定義:
#define T0_CLOCK_TICK (100) // 1S中計數次數
#define T0_TASK_NUM (3) // 3個定時
②. 進行定義一個定時陣列:
uint32 T0_Counter[T0_TASK_NUM] = {0}; // NUM 為需要使用的定時個數
③. 在相應的定義一個數組來儲存標誌位:
uint8 T0_Mark[T0_TASK_NUM] = {0}; // 標誌位為1表示定時時間到
④. 編寫定時器初始化函式:
/**************************************************************************************
* FunctionName : Timer0Init()
* Description : 初始化定時器0
* EntryParameter : NO
* ReturnValue : NO
**************************************************************************************/
void Timer0Init(void)
{
/*Fcclk = Fosc x 4 = 11.0592MHz x 4 = 44.2368MHz
Fpclk = Fcclk / 4 = 44.2368MHz / 4 = 11.0592MHz*/
T0TC = 0; // 定時器設定為0
T0PR = 0; // 設定定時器0分頻為1分頻
T0MCR = 0x03;
T0MR0 = Fpclk/T0_CLOCK_TICK; // 比較值(1/T0_CLOCK_TICK s定時值)
T0TCR = 0x00; // 關閉定時器0
T0Open(); // 開定時器
/* 設定定時器0中斷IRQ*/
VICIntSelect = 0x00; // 所有中斷通道設定為IRQ中斷
VICVectCntl4 = 0x20|0x04; // 定時器0中斷通道分配最高優先順序
VICVectAddr4 = (uint32)IRQ_Time0; // 設定中斷服務程式地址向量
VICIntEnable = 1 << 0x04; // 使能定時器0中斷
}
⑤. 編寫中斷服務函式:
/**************************************************************************************
* FunctionName : IRQ_Time0()
* Description : 定時器0中斷服務
* EntryParameter : NO
* ReturnValue : NO
**************************************************************************************/
void __irq IRQ_Time0(void) // 中斷服務函式
{
uint8 i;
for (i=0; i<T0_TASK_NUM; i++)
{
if (T0_Counter[i] != 0)
{
T0_Counter[i]--; // 計數值減1
if (T0_Counter[i] == 0)
{
T0_SetMark(i); // 相應標誌位置1
}
}
}
T0IR = 0x01; // 清除中斷標誌
VICVectAddr = 0x00; // 通知VIC中斷處理結束
}
⑥. 編寫標誌位置位函式:
/**************************************************************************************
* FunctionName : T0_SetMark()
* Description : 設定相應標準位
* EntryParameter : NO
* ReturnValue : NO
**************************************************************************************/
void T0_SetMark(uint8 num)
{
switch (num)
{
case 0: T0_Mark[0] = 1; break; // 標誌位置位
case 1: T0_Mark[1] = 1; break; //
case 2: T0_Mark[2] = 1; break; //
default: break;
}
}
⑦. 編寫相應的函式,在需要使用的函式中設定計數時間:
void Function1(void)
{
T0_Mark[0] = 0; // 清除標誌位
T0_Counter[0] = 100 ; // 1s計數器100次
while (1)
{
if (T0_Mark[0] == 1) // 判斷時間是否到
{
T0_Mark[0] = 0; // 清除標誌
...
}
}
}
⑧. 編寫其他函式,按照以上方法。
注意事項:
①. 可以根據具體需要更改計數個數。
②. 定時器計數1S的此時可以根據具體需要設定,如果設定計數此時太多,CPU的效率會降低,但是精確度會高一下;反正精確度低,但是CUP效率會高一些。