标题:
51单片机基于一个定时器实现多个软件定时器
[打印本页]
作者:
lw1997
时间:
2019-11-2 23:31
标题:
51单片机基于一个定时器实现多个软件定时器
本帖最后由 lw1997 于 2019-11-2 23:33 编辑
软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。但由于软件定时器是通过程序实现的,其运行和维护都需要耗费一定的CPU资源,同时精度也相对硬件定时器要差一些。在RTOS等操作系统中,都带有软件定时器,原理大同小异。典型的实现方法是:通过一个硬件定时器产生固定的时钟节拍,每次硬件定时器中断到,就对一个全局的时间标记加一,每个软件定时器都保存着到期时间,程序需要定期扫描所有运行中的软件定时器,将各个到期时间与全局时钟标记做比较,以判断对应软件定时器是否到期,到期则执行相应的回调函数,并关闭该定时器
程序如下,通过一个硬件定时器产生固定的时钟节拍,用4个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定时器flag
#define NULL 0
#define SOFT_TIMER_MAX 4 //定时器个数
//定义定时器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 函数指针类型
typedef enum tmrMode {
MODE_ONE_SHOT = 0, //单次模式
MODE_PERIODIC, //周期模式
} tmrMode;
typedef enum tmrState {
SOFT_TIMER_STOPPED = 0, //停止
SOFT_TIMER_RUNNING, //运行
SOFT_TIMER_TIMEOUT, //超时
SOFT_TIMER_WAITING //等待
} tmrState;
typedef struct softTimer {
unsigned char state; //状态
unsigned char mode; //模式
unsigned int period; //定时周期
unsigned int count; //定时计数用
pFun callback; //定时器回调函数
} softTimer;
//定时器结构数组
softTimer softTimerList[SOFT_TIMER_MAX] = {0};
//设定定时器
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;
}
//打开定时器
void softTimer_Start(unsigned int id)
{
softTimerList[id].state = SOFT_TIMER_RUNNING;
}
//停止定时器
void softTimer_Stop(unsigned int id)
{
softTimerList[id].state = SOFT_TIMER_STOPPED;
}
//清除定时器状态(用于执行事件后手动清除定时器状态)
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;
}
}
//获取定时器状态
unsigned char softTimer_GetState(unsigned int id)
{
return softTimerList[id].state;
}
void softTimer_Update(void) //更新定时器状态,在硬件定时器中1ms调用一次
{
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; //设置定时器模式
TL0 = 0xC0; //设置定时初值
TH0 = 0xE0; //设置定时初值
EA = 1;
ET0 = 1;
TR0 = 1;
}
void Interrupt() interrupt 1
{
TL0 = 0xC0; //重载定时初值
TH0 = 0xE0; //重载定时初值
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() //主函数
{
LED1=0;LED2=0;LED3=0;LED4=0;
//配置相应定时器
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);
//打开相应定时器
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();//初始化定时器0
while(1) {
//尽量少用延时,如果事件处理耗时较长,应在main中执行
if(softTimer_8s_flag == 1)
{
LED4=~LED4;
Delayms(200);//模拟耗时事件
softTimer_8s_flag = 0;
}
}
}
复制代码
51hei截图20191102225852.png
(56.18 KB, 下载次数: 79)
下载附件
2019-11-2 23:32 上传
程序及仿真:
51单片机软件定时器测试.7z
(48.06 KB, 下载次数: 109)
2019-11-2 23:23 上传
点击文件名下载附件
程序及
下载积分: 黑币 -5
作者:
wulingqing
时间:
2019-11-3 11:17
这种想法好,谢谢楼主
作者:
1481714970
时间:
2019-11-3 20:29
想法很好,学到了学到了
作者:
jifengjianwu
时间:
2020-1-10 07:07
谢谢楼主分享,学习了。
作者:
hello1994
时间:
2020-1-22 11:30
怎么中定时器中断中调用定时器更新函数,这样会导致定时不准确。为什么不在主函数中调用?在定时器就是只更新计时变量。
作者:
hello1994
时间:
2020-1-22 11:36
如果采用在硬件定时器中断中变量计数的这种形式,需要添加防止计时变量溢出措施。如:变量自动清零同时校验延时时间是否超出定时范围
作者:
13534702358
时间:
2020-3-21 11:14
好厉害的样子!有点复杂了 看不是很懂
作者:
wjd801008
时间:
2020-10-27 08:54
谢谢分享,楼主辛苦了!
作者:
q651881054
时间:
2022-1-7 08:30
经过压力测试了么?
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1