想法有了,我觉得实现就是很简单了。下面给大家贴上我的代码:
.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 4 typedef 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("%bu\n", 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) interrupt 1 { U8 i = 0; TL0 = T0TIMES; TH0 = T0TIMES >> 8; for(i=0; i = timerArray[i].expireTimes) { #pragma asm push ACC push DPH push DPL #pragma endasm (*timerArray[i].timerFunc)(); #pragma asm pop DPL pop DPH pop ACC #pragma endasm timerArray[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函数,进行轮询发现是否有按键按下,并判断其类型。
望有改进意见,谢谢高手指正。
上一篇:51单片机定时器量程的硬件扩展方式
下一篇:51单片机定时器初值的计算
推荐阅读最新更新时间:2024-03-16 14:53