新闻中心

EEPW首页>嵌入式系统>设计应用> 关于51单片机定时器的灵活使用

关于51单片机定时器的灵活使用

作者: 时间:2016-11-20 来源:网络 收藏
前段时间,做一个项目,有串口收发指令判断,按键类型判断,长短按之类,power的定时关电,事件的轮询扫描更新和display的定时扫描。这些要求就对定时器提出了要求,但是我的51单片机只有两个定时器,其中一个又有debug口的波特率产生之用。于是乎我可以用的定时器就只剩下了一个。怎么办?可能大家都只能用变量在定时中断函数去做多了任务就行了,但是我总是感觉这样会导致代码看起来太不具有条理性,而且对于日后的管理不是很容易。思来想去,就想到了linux内核中对于定时器的封装,那种面向对象的思想。

本文引用地址://m.amcfsurvey.com/article/201611/318667.htm

想法有了,我觉得实现就是很简单了。下面给大家贴上我的代码:

.h 文件:

#ifndef __SC_TIMER_H#define __SC_TIMER_H/* SC_Common.h文件中包含了对数据类型的定义和包含对应的单片机的配置头文件,这里就没有列出,根据个人所使用情况而定 */#include "SC_Common.h"#ifdef MODE1T#define T0TIMES (65536-FOSC/1000)#define T1TIMES (65536-10*FOSC/1000)#else#define T0TIMES (65536-FOSC/12/1000) // 0.1ms#define T1TIMES (65536-10*FOSC/12/1000) // 10ms#endif /*MODE1T*/#define TIMER_SIZE 4typedef struct{U8 timerId; /* 定时器的id,实则指明了起所在数组中的位置 */S8 isRuning; /* 表明当前timer是否正在运行 */U16 curTimes; /* 当前timer时间 */U16 expireTimes; /* 当前timer的溢出时间 */U8 existInArry; /* 当前的timer是否存在于数组之中 */TimerFunc timerFunc; /* 当前timer的指定运行函数 */} Timer;void InitTimer(void);S8 AddTimer(Timer *timer);S8 DelTimer(Timer *timer);S8 StartTimer(Timer *timer);S8 ModifyTimer(Timer *timer);S8 StopTimer(Timer *timer);S8 IsRunningTimer(Timer *timer);#endif /*__SC_TIMER_H*/

下面是这部分思想的重点实现,无非就是向timerArray数组中添加删除定时器,简言之,即所谓的增删改查,还有就是启动停止定时器,考虑到51单片机的性能,没有像linux内核中那样用链表实现,同时定时器的总数也是有上限要求的。

.c文件:

#include "SC_Timer.h"#include
        
         #include
         
          /* 这里采用数组的方式管理各个timer结构体 */Timer timerArray[TIMER_SIZE];U8 timerUsed = 0;void InitTimer(void){TMOD |= 0x01;TL0 = T0TIMES;TH0 = T0TIMES >> 8;ET0 = 1;TR0 = 1;timerUsed = 0;memset(timerArray, 0, sizeof(timerArray));}S8 AddTimer(Timer *timer){if(timerUsed >= TIMER_SIZE)timerUsed = 0;/*×Ô¶šÒåtimerIdµÄÉú³É·œÊœ¬ŒŽŽú±íÆäÔÚÊý×éÖеÄλÖÃ*/timer->timerId = timerUsed;timerArray[timerUsed] = *timer;timerUsed++;timer->existInArry = 1;timer->isRuning = 0;printf("%bun", timer->timerId);return 0;}static void Del_Timer(Timer *timerArray, U8 *timerUsed, U8 pos){U8 i = 0;U8 len = *timerUsed;for(i=pos; i
          
           timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;if(timerUsed <= 0)return -1;Del_Timer(timerArray, &timerUsed, timer->timerId);timer->existInArry = 0;return 0;}S8 StartTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].isRuning = 1;return 0;}S8 ModifyTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].curTimes = timer->curTimes;timerArray[timer->timerId].expireTimes = timer->expireTimes;timerArray[timer->timerId].timerFunc = timer->timerFunc;return 0; }S8 StopTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].isRuning = 0;return 0;}S8 IsRunningTimer(Timer *timer){S8 ret = -1;if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return ret;ret = timerArray[timer->timerId].isRuning;return ret;}/* * 定时器的中断函数负责判断各个事件的时间是否到达,如果到达调用相应的相应函数进行运行* 由于51单片机的函数指针是没有堆栈保护的,所以这里加入了
           汇编指令执行堆栈的保护,个人* 水平有限,这里希望大家指正是否有错误之处,谢谢*/void Tm0Isr(void)
           interrupt1{ U8 i = 0;TL0 = T0TIMES;TH0 = T0TIMES >> 8;for(i=0; i
           
            = timerArray[i].expireTimes){#pragma asmpush ACCpush DPHpush DPL#pragma endasm(*timerArray[i].timerFunc)();#pragma asmpop DPLpop DPHpop ACC#pragma endasmtimerArray[i].curTimes = 0;}}}}
           
          
         
        

本文中的数据类型都是通过typedef转化过的,为了时时刻刻关于自己的内存使用量,,定义如下

typedef unsigned char U8;typedef unsigned short int U16;typedef unsigned long int U32;typedef signed char S8;typedef signed short int S16;typedef signed long int S32;typedef bit BOOL;

个人认为这个对于项目后面的能够有效快速的进行起到了很大的帮助。 典型的用法如下:

Timer pressKeyTimer; /* 这里的timer请使用全局变量,大家应该懂的,就是变量的生命周期的问题啦 */pressKeyTimer.curTimes = 0;pressKeyTimer.expireTimes = 11;pressKeyTimer.timerFunc = JudgeKeyType;AddTimer(&pressKeyTimer);StartTimer(&pressKeyTimer);

至此,到规定的时间11msec时,就会调用这里的JudeKeyType函数,进行轮询发现是否有按键按下,并判断其类型。

望有改进意见,谢谢高手指正。



评论


技术专区

关闭