解决单片机硬件定时器(Timer)不够用的问题
2015-04-28
适用情形
硬件Timer功能很多,单片机应用经常用到它
但是它的数量是固定的,少则2个多则5、6个,时常面临不够用的问题
简单类比
若定时器的作用是,定期执行某些程序(比如键盘扫描),则可以对定时器进行复用
使用“时标”,可以简单的做到分时复用一个TIMER,典型例子如下。
一个人,7点吃早餐,12点吃中餐,18点吃晚餐
假设该程序第一次运行时0点,每隔一小时运行一次
则程序可以这么写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| TIMER(){ static uint8 time = 0; switch(time){ case 7: 吃早餐(); break; case 12: 吃中餐(); break; case 18: 吃晚餐(); break; default: break; }
time++; if(time >= 24) time = 0; }
|
具体实现
我以相同原理,实现了一个以1ms为最小单位的的低速定时器。
可无限制增加执行的子程序(前提是内存足够,运行时间足够)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
#include <stdlib.h>
#include "fredivider.h"
typedef FREDIVIDER_InitTypeDef ItemSetup; typedef struct Item{ ItemSetup setup; uint16_t timeLable; struct Item* nextItem; }Item;
typedef Item* ItemsCollection;
ItemsCollection itemCollecion = NULL;
void FREDIVIDER_init(FREDIVIDER_InitTypeDef* initStruct){ if(itemCollecion == NULL){
itemCollecion = (Item*) malloc( sizeof(Item) ); Item* newItemPtr = itemCollecion; newItemPtr = (Item*) malloc( sizeof(Item) ); newItemPtr->setup = *initStruct; newItemPtr->timeLable = 0; newItemPtr->nextItem = NULL; itemCollecion->nextItem = newItemPtr; } else{ Item* ptr = itemCollecion; do{ ptr = ptr->nextItem; if(ptr->setup.Clk_Function == initStruct->Clk_Function){ ptr->setup = *initStruct; ptr->timeLable = 0; return; } }while(ptr->nextItem !=NULL); ptr->nextItem = (Item*) malloc( sizeof(Item) ); ptr = ptr->nextItem; ptr->setup = *initStruct; ptr->timeLable = 0; ptr->nextItem = NULL; }
}
void FREDIVIDER_clk(void){ if(itemCollecion == NULL) return; if(itemCollecion->nextItem == NULL) return;
Item *ptr = itemCollecion; do{ ptr = ptr->nextItem; if(ptr->setup.Enable != 0){ (ptr->timeLable)++; if(ptr->timeLable == ptr->setup.Prescaler){ ptr->timeLable = 0; (*(ptr->setup.Clk_Function)) (); } } } while(ptr->nextItem !=NULL); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
#ifndef _FREDIVIDER_H_ #define _FREDIVIDER_H_
#ifndef uint16_t #define uint16_t unsigned short #endif
#ifndef uint8_t #define uint8_t unsigned char #endif
typedef void (*Clk_Function)(void);
typedef struct{ Clk_Function Clk_Function; uint16_t Prescaler; uint8_t Enable; }FREDIVIDER_InitTypeDef;
typedef enum {FREDIVIDER_DISABLE = 0, FREDIVIDER_ENABLE = !FREDIVIDER_DISABLE} FREDIVIDER_InitTypeDef_Enable;
void FREDIVIDER_clk(void); void FREDIVIDER_init(FREDIVIDER_InitTypeDef* initStruct);
#endif
|
使用例子
__FreDriver,分频器,顾名思义,这里必然是需要提供一个时钟,每1ms需要调用一次FREDIVIDER_clk()__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include "fredriver.h"
void main() { TIM3_init(); FREDIVIDER_InitTypeDef FREDIVIDER_InitStruct; FREDIVIDER_InitStruct.Clk_Function = myprog_clk; FREDIVIDER_InitStruct.Prescaler = 200; FREDIVIDER_InitStruct.Enable = FREDIVIDER_ENABLE; FREDIVIDER_init(&FREDIVIDER_InitStruct); while(1){ if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update)){ TIM_ClearFlag(TIM3,TIM_FLAG_Update); FREDIVIDER_clk(); } } }
void myprog_clk(void) { }
|