1. 程式人生 > >【轉載】1個定時器多處複用的問題

【轉載】1個定時器多處複用的問題

 問題: 在一個工程中往往需要用到多個定時,然而我們採用的CPU一般也只有2,3個定時器。顯然是不夠用的,那麼應該怎麼辦呢?

       我想如果使用過系統的人都會知道,在系統中有個時鐘節拍,而多個任務都是共同使用這個時鐘節拍進行延時或任務切換。那麼我們是否可以借鑑一下呢?

1個定時器多處複用的問題(原創) - 我心永恆 - ARM-新的夢想

下面我們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;                                        

 // 匹配通道0匹配中斷並復位T0TC
     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效率會高一些。