定时本质上也是延时操作,但是长时间的延时操作会影响到其他模块正常运行,所以可以采取定时器+计数+标志位的方式来完成一些较长时间的定时。
uint tick_num; //用于计时的变量
uint tick_max; //用于设定计时的时间
uchar tick_flag; //计时的状态 0计时,1计时完成,其他计时停止
void tim0_isr() interrupt 1{
if(0==tick_flag){ //允许计时
if(++tick_num>=tick_max){
tick_flag=1; //计时完成,设置标志位,提供给任务函数检测
}
}
}
void main(){
tim0_init(); //1ms定时器初始化
tick_num=0; //初始化计时变量
tick_max=1000; //设置需要及时的时间,基数是定时器时间,这里是1ms,1000就是1秒
tick_flag=0; //初始化定时标志位,也意味着定时开始
while(1){
//实现一个1秒LED变换
if(tick_flag==1){ //检测计时是否完成
LED=!LED;
//重新开始计时
tick_num=0;
tick_max=1000;
tick_flag=0;
}
}
}
本质上就是定时计数,例如1ms的定时中断里,计1000就是1秒,计60000就是1分钟,然后这个计数再用一个标志位来控制。
但是这样始终还是有点麻烦(不够花里胡哨),例如在需要多路计时时,需要复制黏贴好多变量,所以可以在这个原理的基础上,用结构体和函数封装一下,用得比较方便。
//定义一些软件定时器的状态
#define TICK_RUN 0 //计时
#define TICK_STOP 1 //停止
#define TICK_SUCCE 2 //定时完成
//用到了enum,用来确定软件计时器的最大数量
enum TICK_HANDLE_ENUM{
TICK1, //enum第一个默认是0
TICK2, //1
TICK3, //2
TICK_MAX, //3 最后一个的大小是enum里面的参数数量-1,所以在TICK_MAX前添加软件定时器名字,这样TICK_MAX就刚好能够说明你需要多少个软件定时器
};
//把三个用于计时的变量放结构体里
typedef struct TICK_STRUCT{
u16 tick_max;
u16 tick_now;
u8 status;
}tick_st;
tick_st tick[TICK_MAX]; //用到了结构体数组,方便多个软件定时的时候使用。就是tick_st这个结构体类型的数组,数组里的每一个参数都是一个tick_st结构体
//这个函数放在定时器中断里,完成定时中的计数行为
void tick_callback(void){
u8 i;
for(i=0;i<TICK_MAX;i++){ //查询数组里的所有结构体
if(tick[i].status == TICK_RUN){
if(++tick[i].tick_now>=tick[i].tick_max){
tick[i].status=TICK_SUCCE;
}
}
}
}
//计时开始---其实就初始化那三个变量
void tick_creat(u8 tick_handle, u16 tick_time){
tick[tick_handle].status = TICK_RUN;
tick[tick_handle].tick_max = tick_time;
tick[tick_handle].tick_now = 0;
}
//获取软件定时器的状态
u8 tick_read_status(u8 tick_handle){
return tick[tick_handle].status;
}
//关闭定时器,复位定时器状态
void tick_rst(u8 tick_handle){
tick[tick_handle].status = TICK_STOP;
}
//
void tim0_isr() interrupt 1{
tick_callback();
}
void main(){
tim0_init(); //1ms定时器初始化
tick_creat(TICK1,1000);
tick_creat(TICK2,2000);
tick_creat(TICK3,3000);
/*
示例:
计时1:1秒执行一次,循环
计时2:计时3执行后2秒执行一次
计时3:3秒执行一次,循环
*/
while(1){
if(tick_read_status(TICK1)==TICK_SUCCE){
//功能函数
tick_creat(TICK1,1000);
}
if(tick_read_status(TICK2)==TICK_SUCCE){
tick_rst(TICK2);
//功能函数
}
if(tick_read_status(TICK3)==TICK_SUCCE){
//功能函数
tick_creat(TICK2,2000);
tick_creat(TICK3,3000);
}
}
}
// tick_handle也可以用enum TICK_HANDLE_ENUM作为传参类型,避免脑子一抽,给了一个过大的参数
这样使用就4个函数
tick_creat:开始一个定时
tick_read_status:读取一个定时的状态
tick_rst:复位一个定时任务
tick_callback:放硬件定时器中断里,
要添加软件定时器数量也只需要在枚举里对应位置添加定时器名字就可以。