加入收藏 | 设为首页 |

ope电竞app官网-单片机高档编程之软定时器的完成

海外新闻 时间: 浏览:270 次

说到守时器,我们必定都不生疏,每个学习单片机的人都需求熟练掌握其守时器的运用,因为它实在太常用了。一般的运用办法便是初始化一个硬件守时器,让其在固定的时刻后发生一个守时器中止,然后在守时器中止服务程序(ISR)里边置位,累加或累减某个变量,在while(1)中判别这个变量,当其值满意想要的条件,即需求守时的时刻,就履行相应的功用。当然假如功用履行的句子比较少,也可直接在ISR中履行。当程序中有多个当地需求守时,那就多请求几个变量,在while(1)中多几个判别。

那么问题来了,有没有一种办法能将上述的请求变量,判别变量,履行功用等细节封装成一种固定的接口,让工程师在使用程序开发时简略定心的运用呢?有,那便是软守时器。望文生义,软守时器便是用软件完成的守时器功用,它依据某个硬件守时器。

一,要点来了,现在手把手教你怎样完成:

1,在硬件守时器ISR中做一个1毫秒的tick累加

volatile u16 ms_tick=0;

static void TIMER0_ISR(void)

{

........

ms_tick=((ms_tick==0xffff)? 0 : (ms_tick+1));

........

}

2,界说软守时器结构体数组timer_buff[]

#define TIMER_MAX 30 // 守时器最大个数,依据实践需求界说

#define INVALID_ID 0xff // 无效的ID

typedef enum{

MODE_SINGLE , // 单次形式,履行一次后主动封闭

MODE_REPEAT // 重复形式,重复履行,直到手动封闭中止

}mode_t;

typedef struct{

u8 valid; // 守时器是否有用

u8 on; // 守时器的开关

mode_t mode; // 守时器的形式

u16 start_time; 守时器的开始tick

u16 delay; 守时时刻,单位毫秒

FuncU32_t cb; 时刻届时履行的回调函数

u32 para; 回调函数的参数

}timer_t;

static timer_t timer_buff[TIMER_MAX]={0};

3,界说初始化函数,在体系初始化时调用一次

void sw_timer_init(void)

{

memset(timer_buff,0,sizeof(timer_buff));

}

4,界说守时器发动函数

static u8 valid_timer_cnt=0;保存有用守时器的总个数

u8 timer_start(u8 *p_id, mode_t mode, u16 delay, FuncU32_t cb, u32 para)

{

u8 i;

if(!cb)return 0;

if(!delay)return 0;

if(*p_id == INVALID_ID){ 假如ID无效,就从头请求一个

if(valid_timer_cnt>=TIMER_MAX)return 0; 假如守时器个数满,回来请求失利

for(i=0;i

if(!timer_buff[i].valid){

*p_id=i;

timer_buff[i].valiope电竞app官网-单片机高档编程之软定时器的完成d=1; 让当时守时器有用

valid_timer_cnt++;

break;

}

}

}

timer_buff[*p_id].mode=mode;

timer_buff[*p_id].delay=delay;

timer_buff[*p_id].cb=cb;

timer_buff[*p_id].para=para;

timer_buff[*p_id].start_time=ms_tick; 保存开始tick

timer_buff[*p_id].on=1; 发动当时守时器

return 1; 回来成功

}

5,界说守时器中止函数

void timer_stop(u8 *p_id)

{

if(*p_id == INVALID_ID)return;

if(!timer_buff[*p_id].on)return;

timer_buff[*p_id].on龙星凉=0;

}

6,界说守时器铲除函数

void timerope电竞app官网-单片机高档编程之软定时器的完成_delete(u8 *p_id)

{

if(*p_id == INVALID_ID)return;

timer_buff[*p_id].valid=0;

timer_buff[*p_id].on=0;

valid_timer_cnt--;

*p_id=INVALID_ID;

}

7,界说获取有用守时器的总个数

u8 timer_num_get(void)

{

return valid_timer_cnt;

}

8,界说守时器处理task,放在while(1)中,详细思路,研读代码即可理解

void timer_task(void)

{

static u8 i;

static u32 temp;

for(i=0;i

if(timer_buff[i].valid && timer_buff[i].on){

if(ms_tick >= timer_buff[i].start_time){

temp=timer_buff[i].start_time;

temp += timer_buff[i].delay;

if(ms_tick >= temp){

if(timer_buff[i].mode == MODE_SINGLE)timer_buff[i].on=0;

timer_buff[i].start_time=ms_tick;

if(timer_buff[i].cb)

timer_buff[i].cb(timer_buff[i].para);

}

}

else{

if((0xffff-timer_buff[i].start_time+ms_tick) >= timer_buff[i].delay){

if(timer_buff[i].mode == MODE_SINGLE)timer_buff[i].on=0;

timer_buff[i].start_time=ms_tick;

if(timer_buff[i].cb)

timer_buff[i].cb(timer_buff[i].para);

}

}

}

}

}

二,以上为整个软守时器功用完成的过程,下面举例说明一下:

1,在体系初始化函数中调用sw_timer_init()

2, main中履行task

while(1){

timer_task();

}

2,用户程序中界说守时器ID变量 static u8 app_tID=INVALID_ID;需求多少个守时器就界说多少个变量,用户后续对该守时器的全部操作需求传入此变量,一个ID变量对应一个守时器。留意该变量一定要初始化成INVALID_ID,界说今后不得人工更改!

3,发动守时器

static void app_tCB(u32 para)

{

该用户函数每20毫秒被回调一次,参数para=100

}

timer_start(&app_tID,MODE_REPEAT,20,app_tCB,100);

4,中止守时器 timer_stop(&app_tID);

5,删去守时器 timer_delete(&app_tID);

仔细的小伙伴可能会发现,该架构中所有的回调参数都是u32,最多只能包容4个字节,实践上一般使用也满足,用起来简略便利。假如实践参数超越四个字节,能够将参数强转成空指针,即void *pPara,传递一个空类型的地址作为参数,在用户回调函数中依照实践类型再做一次强转即可完成多参数传递。

三,优缺陷剖析

长处:1,该架构只需占用一个硬ope电竞app官网-单片机高档编程之软定时器的完成件守时器,便可完成几十个乃至上百个守时器的功用,只需内存满足;

2,程序员能够随时灵敏的发动,中止,删去守时器,逻辑上很简略操控,有助于完成较杂乱的逻辑和DEBUG

3,用简略的几个api将硬件底层跟使用上层解耦,程序员能够更好,更简略的专心于事务逻辑的完成。程序模块化也更简略完成

缺陷:1,因为在task中运转,实时性没有硬ope电竞app官网-单片机高档编程之软定时器的完成件守时器ISR高,关于实时性要求很高的场合,比方:信号丈量,信号组成等场景,不太适用

2,理论上讲该守时器的最大差错有1个tick,假如tick是1毫秒,最ope电竞app官网-单片机高档编程之软定时器的完成大差错便是1毫秒

关于软守时器,今日就讲到这儿,欢迎我们活跃留言转发,您的参加是小编的最大动力!

喜爱的小伙伴能够重视我,后边继续有干货出现哦~~~~