新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 關(guān)于51單片機(jī)定時(shí)器的靈活使用

關(guān)于51單片機(jī)定時(shí)器的靈活使用

作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
前段時(shí)間,做一個(gè)項(xiàng)目,有串口收發(fā)指令判斷,按鍵類型判斷,長(zhǎng)短按之類,power的定時(shí)關(guān)電,事件的輪詢掃描更新和display的定時(shí)掃描。這些要求就對(duì)定時(shí)器提出了要求,但是我的51單片機(jī)只有兩個(gè)定時(shí)器,其中一個(gè)又有debug口的波特率產(chǎn)生之用。于是乎我可以用的定時(shí)器就只剩下了一個(gè)。怎么辦?可能大家都只能用變量在定時(shí)中斷函數(shù)去做多了任務(wù)就行了,但是我總是感覺這樣會(huì)導(dǎo)致代碼看起來太不具有條理性,而且對(duì)于日后的管理不是很容易。思來想去,就想到了linux內(nèi)核中對(duì)于定時(shí)器的封裝,那種面向?qū)ο蟮乃枷搿?p>

本文引用地址:http://butianyuan.cn/article/201611/318667.htm

想法有了,我覺得實(shí)現(xiàn)就是很簡(jiǎn)單了。下面給大家貼上我的代碼:

.h 文件:

#ifndef __SC_TIMER_H#define __SC_TIMER_H/* SC_Common.h文件中包含了對(duì)數(shù)據(jù)類型的定義和包含對(duì)應(yīng)的單片機(jī)的配置頭文件,這里就沒有列出,根據(jù)個(gè)人所使用情況而定 */#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;			/* 定時(shí)器的id,實(shí)則指明了起所在數(shù)組中的位置 */S8 isRuning;			/* 表明當(dāng)前timer是否正在運(yùn)行 */U16 curTimes;			/* 當(dāng)前timer時(shí)間 */U16 expireTimes;		/* 當(dāng)前timer的溢出時(shí)間 */U8 existInArry;		        /* 當(dāng)前的timer是否存在于數(shù)組之中 */TimerFunc timerFunc;	        /* 當(dāng)前timer的指定運(yùn)行函數(shù) */} 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*/

下面是這部分思想的重點(diǎn)實(shí)現(xiàn),無非就是向timerArray數(shù)組中添加刪除定時(shí)器,簡(jiǎn)言之,即所謂的增刪改查,還有就是啟動(dòng)停止定時(shí)器,考慮到51單片機(jī)的性能,沒有像linux內(nèi)核中那樣用鏈表實(shí)現(xiàn),同時(shí)定時(shí)器的總數(shù)也是有上限要求的。

.c文件:

#include "SC_Timer.h"#include #include /* 這里采用數(shù)組的方式管理各個(gè)timer結(jié)構(gòu)體 */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; itimerId >= 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;}/* *  定時(shí)器的中斷函數(shù)負(fù)責(zé)判斷各個(gè)事件的時(shí)間是否到達(dá),如果到達(dá)調(diào)用相應(yīng)的相應(yīng)函數(shù)進(jìn)行運(yùn)行*  由于51單片機(jī)的函數(shù)指針是沒有堆棧保護(hù)的,所以這里加入了匯編指令執(zhí)行堆棧的保護(hù),個(gè)人*  水平有限,這里希望大家指正是否有錯(cuò)誤之處,謝謝*/void Tm0Isr(void) interrupt 1{	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;}}}}

本文中的數(shù)據(jù)類型都是通過typedef轉(zhuǎn)化過的,為了時(shí)時(shí)刻刻關(guān)于自己的內(nèi)存使用量,,定義如下

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;

個(gè)人認(rèn)為這個(gè)對(duì)于項(xiàng)目后面的能夠有效快速的進(jìn)行起到了很大的幫助。 典型的用法如下:

Timer pressKeyTimer;        /* 這里的timer請(qǐng)使用全局變量,大家應(yīng)該懂的,就是變量的生命周期的問題啦 */pressKeyTimer.curTimes	  = 0;pressKeyTimer.expireTimes = 11;pressKeyTimer.timerFunc   = JudgeKeyType;AddTimer(&pressKeyTimer);StartTimer(&pressKeyTimer);

至此,到規(guī)定的時(shí)間11msec時(shí),就會(huì)調(diào)用這里的JudeKeyType函數(shù),進(jìn)行輪詢發(fā)現(xiàn)是否有按鍵按下,并判斷其類型。

望有改進(jìn)意見,謝謝高手指正。



評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉