【转载】1个定时器多处复用的问题

时间:2021-09-29 23:34:41

 问题: 在一个工程中往往需要用到多个定时,然而我们采用的CPU一般也只有2,3个定时器。显然是不够用的,那么应该怎么办呢?

       我想如果使用过系统的人都会知道,在系统中有个时钟节拍,而多个任务都是共同使用这个时钟节拍进行延时或任务切换。那么我们是否可以借鉴一下呢?

【转载】1个定时器多处复用的问题

 

下面我们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效率会高一些。