標(biāo)題:
51單片機(jī)基于一個(gè)定時(shí)器實(shí)現(xiàn)多個(gè)軟件定時(shí)器
[打印本頁(yè)]
作者:
lw1997
時(shí)間:
2019-11-2 23:31
標(biāo)題:
51單片機(jī)基于一個(gè)定時(shí)器實(shí)現(xiàn)多個(gè)軟件定時(shí)器
本帖最后由 lw1997 于 2019-11-2 23:33 編輯
軟件定時(shí)器是用程序模擬出來的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬個(gè)軟件定時(shí)器,這樣程序在需要使用較多定時(shí)器的時(shí)候就不會(huì)受限于硬件資源的不足,這是軟件定時(shí)器的一個(gè)優(yōu)點(diǎn),即數(shù)量不受限制。但由于軟件定時(shí)器是通過程序?qū)崿F(xiàn)的,其運(yùn)行和維護(hù)都需要耗費(fèi)一定的CPU資源,同時(shí)精度也相對(duì)硬件定時(shí)器要差一些。在RTOS等操作系統(tǒng)中,都帶有軟件定時(shí)器,原理大同小異。典型的實(shí)現(xiàn)方法是:通過一個(gè)硬件定時(shí)器產(chǎn)生固定的時(shí)鐘節(jié)拍,每次硬件定時(shí)器中斷到,就對(duì)一個(gè)全局的時(shí)間標(biāo)記加一,每個(gè)軟件定時(shí)器都保存著到期時(shí)間,程序需要定期掃描所有運(yùn)行中的軟件定時(shí)器,將各個(gè)到期時(shí)間與全局時(shí)鐘標(biāo)記做比較,以判斷對(duì)應(yīng)軟件定時(shí)器是否到期,到期則執(zhí)行相應(yīng)的回調(diào)函數(shù),并關(guān)閉該定時(shí)器
程序如下,通過一個(gè)硬件定時(shí)器產(chǎn)生固定的時(shí)鐘節(jié)拍,用4個(gè)LED演示效果:
#include "reg51.h"
//#include "STC89C5xRC.h"
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;
unsigned char softTimer_8s_flag = 0; //8s定時(shí)器flag
#define NULL 0
#define SOFT_TIMER_MAX 4 //定時(shí)器個(gè)數(shù)
//定義定時(shí)器ID
#define ID_1S_LED_TASK 0
#define ID_2S_LED_TASK 1
#define ID_4S_LED_TASK 2
#define ID_8S_LED_TASK 3
typedef void (*pFun)(void); //callback 函數(shù)指針類型
typedef enum tmrMode {
MODE_ONE_SHOT = 0, //單次模式
MODE_PERIODIC, //周期模式
} tmrMode;
typedef enum tmrState {
SOFT_TIMER_STOPPED = 0, //停止
SOFT_TIMER_RUNNING, //運(yùn)行
SOFT_TIMER_TIMEOUT, //超時(shí)
SOFT_TIMER_WAITING //等待
} tmrState;
typedef struct softTimer {
unsigned char state; //狀態(tài)
unsigned char mode; //模式
unsigned int period; //定時(shí)周期
unsigned int count; //定時(shí)計(jì)數(shù)用
pFun callback; //定時(shí)器回調(diào)函數(shù)
} softTimer;
//定時(shí)器結(jié)構(gòu)數(shù)組
softTimer softTimerList[SOFT_TIMER_MAX] = {0};
//設(shè)定定時(shí)器
void softTimer_Creat(unsigned char id,tmrMode mode,unsigned int interval,pFun cb)
{
softTimerList[id].mode = mode;
softTimerList[id].period = interval;
softTimerList[id].count = 0;
softTimerList[id].callback = cb;
softTimerList[id].state = SOFT_TIMER_STOPPED;
}
//打開定時(shí)器
void softTimer_Start(unsigned int id)
{
softTimerList[id].state = SOFT_TIMER_RUNNING;
}
//停止定時(shí)器
void softTimer_Stop(unsigned int id)
{
softTimerList[id].state = SOFT_TIMER_STOPPED;
}
//清除定時(shí)器狀態(tài)(用于執(zhí)行事件后手動(dòng)清除定時(shí)器狀態(tài))
void softTimer_Clr(unsigned int id)
{
if(softTimerList[id].mode == MODE_ONE_SHOT){
softTimerList[id].state = SOFT_TIMER_STOPPED;
}else{
softTimerList[id].state = SOFT_TIMER_RUNNING;
}
}
//獲取定時(shí)器狀態(tài)
unsigned char softTimer_GetState(unsigned int id)
{
return softTimerList[id].state;
}
void softTimer_Update(void) //更新定時(shí)器狀態(tài),在硬件定時(shí)器中1ms調(diào)用一次
{
unsigned char id;
for(id = 0 ;id <= SOFT_TIMER_MAX ; id++ ){
switch (softTimerList[id].state){
case SOFT_TIMER_STOPPED:
break;
case SOFT_TIMER_RUNNING:
if(softTimerList[id].count < softTimerList[id].period){
softTimerList[id].count ++;
}else{
softTimerList[id].count = 0;
softTimerList[id].state = SOFT_TIMER_TIMEOUT;
softTimerList[id].callback();
}
break;
case SOFT_TIMER_TIMEOUT:
if(softTimerList[id].mode == MODE_ONE_SHOT) {
softTimerList[id].state = SOFT_TIMER_STOPPED;
} else {
softTimerList[id].count ++;
softTimerList[id].state = SOFT_TIMER_RUNNING;
}
break;
default: //state error
break;
}
}
}
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD = 0x00; //設(shè)置定時(shí)器模式
TL0 = 0xC0; //設(shè)置定時(shí)初值
TH0 = 0xE0; //設(shè)置定時(shí)初值
EA = 1;
ET0 = 1;
TR0 = 1;
}
void Interrupt() interrupt 1
{
TL0 = 0xC0; //重載定時(shí)初值
TH0 = 0xE0; //重載定時(shí)初值
softTimer_Update(); //1ms更新一次softTimer
}
void Delayms(unsigned int ms) //@12.000MHz
{
unsigned char i, j;
while(--ms) {
i = 2;
j = 239;
do {
while (--j);
} while (--i);
}
}
void softTimer_1s_cb(void)
{
LED1 = ~LED1;
}
void softTimer_2s_cb(void)
{
LED2 = ~LED2;
}
void softTimer_4s_cb(void)
{
LED3 = ~LED3;
}
void softTimer_8s_cb(void)
{
softTimer_8s_flag = 1;
}
void main() //主函數(shù)
{
LED1=0;LED2=0;LED3=0;LED4=0;
//配置相應(yīng)定時(shí)器
softTimer_Creat(ID_1S_LED_TASK,MODE_PERIODIC,1000,softTimer_1s_cb);
softTimer_Creat(ID_2S_LED_TASK,MODE_PERIODIC,2000,softTimer_2s_cb);
softTimer_Creat(ID_4S_LED_TASK,MODE_ONE_SHOT,4000,softTimer_4s_cb);
softTimer_Creat(ID_8S_LED_TASK,MODE_PERIODIC,8000,softTimer_8s_cb);
//打開相應(yīng)定時(shí)器
softTimer_Start(ID_1S_LED_TASK);
softTimer_Start(ID_2S_LED_TASK);
softTimer_Start(ID_4S_LED_TASK);
softTimer_Start(ID_8S_LED_TASK);
Timer0Init();//初始化定時(shí)器0
while(1) {
//盡量少用延時(shí),如果事件處理耗時(shí)較長(zhǎng),應(yīng)在main中執(zhí)行
if(softTimer_8s_flag == 1)
{
LED4=~LED4;
Delayms(200);//模擬耗時(shí)事件
softTimer_8s_flag = 0;
}
}
}
復(fù)制代碼
51hei截圖20191102225852.png
(56.18 KB, 下載次數(shù): 79)
下載附件
2019-11-2 23:32 上傳
程序及仿真:
51單片機(jī)軟件定時(shí)器測(cè)試.7z
(48.06 KB, 下載次數(shù): 109)
2019-11-2 23:23 上傳
點(diǎn)擊文件名下載附件
程序及
下載積分: 黑幣 -5
作者:
wulingqing
時(shí)間:
2019-11-3 11:17
這種想法好,謝謝樓主
作者:
1481714970
時(shí)間:
2019-11-3 20:29
想法很好,學(xué)到了學(xué)到了
作者:
jifengjianwu
時(shí)間:
2020-1-10 07:07
謝謝樓主分享,學(xué)習(xí)了。
作者:
hello1994
時(shí)間:
2020-1-22 11:30
怎么中定時(shí)器中斷中調(diào)用定時(shí)器更新函數(shù),這樣會(huì)導(dǎo)致定時(shí)不準(zhǔn)確。為什么不在主函數(shù)中調(diào)用?在定時(shí)器就是只更新計(jì)時(shí)變量。
作者:
hello1994
時(shí)間:
2020-1-22 11:36
如果采用在硬件定時(shí)器中斷中變量計(jì)數(shù)的這種形式,需要添加防止計(jì)時(shí)變量溢出措施。如:變量自動(dòng)清零同時(shí)校驗(yàn)延時(shí)時(shí)間是否超出定時(shí)范圍
作者:
13534702358
時(shí)間:
2020-3-21 11:14
好厲害的樣子!有點(diǎn)復(fù)雜了 看不是很懂
作者:
wjd801008
時(shí)間:
2020-10-27 08:54
謝謝分享,樓主辛苦了!
作者:
q651881054
時(shí)間:
2022-1-7 08:30
經(jīng)過壓力測(cè)試了么?
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1