历史上的今天
今天是:2025年01月22日(星期三)
2020年01月22日 | 51单片机基于一个定时器实现多个软件定时器
2020-01-22 来源:51hei
软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。但由于软件定时器是通过程序实现的,其运行和维护都需要耗费一定的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);//模拟耗时事件
史海拾趣
|
用MSP430P315 单片机的A/D 转换器,实现阻性温度传感器的电阻检测;用查表和线性插值结合的方法,简化标度变换的算法结构。对电池电压的降低进行补偿的同时分析补偿电阻的精度对温度检测的影响。 … 查看全部问答> |
|
/************************************************ *技术直接转销售还是先转技术支持再转销售好呢? ************************************************/ 我是09年毕业的,毕业的时候,是在一家医疗器材公司工作。 最近换了一家公司,是搞 ...… 查看全部问答> |
|
老师让做一个dsp和pc通过并口epp通信的东西,在xp下对并口操作是不是要写个驱动?老板让我用WinDriver,我想问问关于并口开发要怎样调试呢?以前没有做过关于并口通信东西,所以想请问各位老大,希望能给指点一下… 查看全部问答> |
|
在Wince中添加一个较大的位图,设想有一个相对较小的取景框,当这个框快速移动时,我想显示屏幕上位图移动的动画效果。我在evc中代码如下: CBitmap m_bitmap; BITMAP bm; ...… 查看全部问答> |
|
4月21日(周六)东方标准特邀请嵌入式软件仿真开源(SkyEye)项目核心成员、AKA 嵌入式小组成员康烁,为大家做《利用SkyEye进行操作系统分析及SkyEye的最新进展》的讲座。 康烁--作为自由软件爱好者,精通嵌入式系统移植,驱动开发,多年嵌入式开发 ...… 查看全部问答> |




