2024年C C++最新【C C++开源库】适合嵌入式的定时器调度器_c+,字节C C++高级岗

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

不同的场景,选择不同的工具和架构才是最合理的,SmartTimer只能做它力所能及的事情。

虽然SmartTimer是基于STM32开发的,但是它可以很方便的移植到其他的单片机上。

##2. SmartTimer的一般用法##

###2.1 Runlater。###

在单片机编程中,想实现在”xxx毫秒后调用xxx函数”的功能,一般有3种方法:

  1. 用阻塞的,非精确的方式,就是用for(i=0;i<0xffff;i++);这种循环等待的方式,来非精确的延迟一段时间,然后再顺序执行下面的程序;
  2. 利用硬件定时器实现异步的精确延时,把XXX函数在定时器中断里执行;
  3. 同样是利用硬件定时器,但是只在定时器中断里设置标志位,在系统的主While循环中检测这个标志位,当检测到标志置位后,去运行XXX函数。

从理论上来说,以上3种方式中,第3种采用定时器设定标志位的方法最好。因为首先主程序不用阻塞,在等待的时间里,MCU完全可以去做其他的事情,其次在定时器中断里不用占用太多的时间,节约中断资源。但这种方式有个缺点,就是实现起来相对麻烦一些。因为如果你要有N个runlater的需求,那么就得设置N个标志位,还要考虑定时器的分配、设定。在程序主While循环里也会遍布N个查询标志位的if语句。如果N足够多,其实大于5个,就会比较头疼。这样会使主While循环看起来很乱。这样的实现不够简洁、优雅。

SmartTimer首先解决的就是这个问题,它可以优雅地延迟调用某函数。

###2.2 Runloop###

在定时器编程方面还有另一个典型需求,就是“每隔xxx毫秒运行一次XXX函数,一共运行XXX次”。这个实现起来和runlater差不多,就是加一个运行次数的技术标志。我就不再赘述了。还是那句话:

SmartTimer可以优雅的实现Runloop功能。

###2.3 Delay### 并不是说非阻塞就一定比阻塞好,因为在某些场景下,必须得用到阻塞,使单片机停下来等待某个事件。那么SmartTimer也可以提供这个功能。

##3. SmartTimer的高级用法## 所谓的高级用法,并不是说SmartTimer有隐藏模式,能开启黑科技。而是说,如果你能转变思路,举一反三地话,可以利用SmartTimer提供的简单功能实现更加优化、合理的系统结构。

传统的单片机裸跑一般采用状态机模式,就是在主While循环里设定一些标志位或是设定好程序进行的步骤,根据事件的进程来跳转程序。简单的说来,这是一种顺序执行的程序结构。其灵活性和实时性并不高,尤其是当需要处理的业务越来越多,越来越复杂时,状态机会臃肿不堪,一不留神(其实是一定以及肯定)就会深埋bug于其中,调试解决BUG时也会异常痛苦。

如果你能转换一下思路,不再把业务逻辑中各个模块的关系看成基于因果(顺序),而是基于时间,模块间如果需要确定次序可以采用标志位进行同步。那么恭喜你,你已经有了采用实时系统的思想,可以尝试使用RT-thread等操作系统来完成你的项目了。但是,使用操作系统有几个问题,第一是当单片机资源有限的时候,使用操作系统恐怕不太合适;第二是学习操作系统本身有一定的难度,至少你需要花费一定的时间;第三如果你的项目复杂度没有那么高,使用操作系统有点大材小用。

那么,请允许我没羞没臊的说一句,其实利用SmartTimer中的Runloop功能可以简单的实现基于时间的主程序框架。

##4.关于Demo## 与源码一起提供的,还有一个Demo程序。这个Demo比较简单,主要是为了测试SmartTimer的功能。Demo程序基本可以体现Runlater,Runloop,Delay功能。同时也能基本体现基于时间的编程思想(单片机裸跑程序框架)。

##5.SmartTimer的使用## SmartTimer.h中声明的公开函数并不多,总共有8个:

void stim\_init ( void );

void stim\_tick (void);

void stim\_mainloop ( void );

int8\_t stim\_loop ( uint16\_t delayms, void (\*callback)(void), uint16\_t times);

int8\_t stim\_runlater ( uint16\_t delayms, void (\*callback)(void));

void stim\_delay ( uint16\_t delayms);

void stim\_kill\_event(int8\_t id);

void stim\_remove\_event(int8\_t id);

下面我将逐一介绍 ###5.1 必要的前提### SmartTimer能够工作的必要条件是:

  • A. 设置Systick的定时中断(也可以是其他的硬件定时器TIMx,我选择的是比较简单的Systick),我默认设置为1ms中断一次,使用者可以根据自己的情况来更改。Systick时钟的设置在stim_init函数中,该函数必须在主程序初始化阶段调用一次。
  • B. 在定时器中断函数中调用stim_tick();可以说,这个函数是SmartTimer的引擎,如A步骤所述,默认情况下,每1ms,定时器中断会调用一次stim_tick();
  • C. 在主While循环中执行stim_mainloop(),这个函数主要有两个作用,一是执行定时结束后的回调函数;二是回收使用完毕的timer事件的资源。

###5.2 开始使用SmartTimer### 做好以上的搭建工作后,就可以开始使用SmartTimer了。

int8_t stim_runlater ( uint16_t delayms, void (*callback)(void));

该函数接受两个参数,返回定时事件的id。参数delayms传入延迟多长时间,注意这里的单位是根据之前A步骤里,你设置的时间滴答来确定的(默认单位是1ms);第二个参数是回调函数的函数指针,目前只支持没有参数,且无返回值的回调函数,未来会考虑加入带参数和返回值的回调。 举例:

timer\_runlater(100,ledflash); //100豪秒(100\*1ms=100ms)后,执行void ledflash(void)函数

如果在stim_init()中,设置的时钟滴答为10ms执行一次,那么传入同样的参数,意义就会改变:

timer\_runlater(100,ledflash); //1秒(100\*10ms=1000ms=1S)后,执行void ledflash(void)函数

int8_t stim_loop ( uint16_t delayms, void (*callback)(void), uint16_t times);

这个函数的参数意义同runlater差不多,我就不详细说明了。 该函数接收3个参数,delayms为延迟时间,callback为回调函数指针,times是循环次数。 举例(以1ms滴答为例):

timer\_runloop(50,ledflash,5); // 每50ms,执行一次ledflash(),总共执行5次` `timer\_runloop(80,ledflash, TIMER\_LOOP\_FOREVER); // 每80ms,执行一次ledflash(),无限循环。

void timer_delay ( uint16_t delayms); //延迟xx ms

这个函数会阻塞主程序,并延迟一段时间。

void stim_kill_event(int8_t id);

void stim_remove_event(int8_t id);

这两个函数,可以将之前设定的定时事件取消。比如之前用stim_loop无限循环了一个事件,当获取某个指令后,需要取消这个任务,则可以用这两个函数取消事件调度。这两个函数的区别是:

void stim\_kill\_event(int8\_t id); //直接取消事件,忽略未处理完成的调度任务。` `void stim\_remove\_event(int8\_t id);//将已经完成计时的调度任务处理完毕之后,再取消事件

###5.3 注意事项### SmartTimer可接受的Timer event数量是有上限的,这个上限由smarttimer.h中的宏定义

#define TIMEREVENT\_MAX\_SIZE 20

来决定的。默认为20个,你可以根据实际情况增加或减少。但不可多于128个

源码分析

smarttimer.h

/\*
 \* =====================================================================================
 \*
 \* Filename: smarttimer.h
 \*
 \* Description: 
 \*
 \* Version: 1.1
 \* Created: 2016/7/14 ÐÇÆÚËÄ ÉÏÎç 10:48:35
 \* Revision: none
 \* Compiler: armcc
 \*
 \* Author: lell 
 \* Organization: 
 \*
 \* =====================================================================================
 \*/
#ifndef \_\_SMARTTIMER\_H\_\_
#define \_\_SMARTTIMER\_H\_\_
#include "stm32f10x.h"

//#define STIM\_DEBUG


#ifndef NULL
#define NULL ((void \*)0)
#endif

#define CLOSE\_INTERRUPT() \_\_ASM("CPSID I")
#define OPEN\_INTERRUPT() \_\_ASM("CPSIE I") 


#define STIM\_EVENT\_MAX\_SIZE 20 /\*max size of timer event number \*/
#define STIM\_LOOP\_FOREVER (uint16\_t)0xffff

#define STIM\_INVALID 0xff

#define STIM\_EVENT\_IDLE 0x00
#define STIM\_EVENT\_ACTIVE 0x01
#define STIM\_EVENT\_RECYCLE 0x02

void stim\_init ( void );
void stim\_tick (void);
void stim\_mainloop ( void );
int8\_t stim\_loop ( uint16\_t delayms, void (\*callback)(void), uint16\_t times);
int8\_t stim\_runlater ( uint16\_t delayms, void (\*callback)(void));
void stim\_delay ( uint16\_t delayms);
void stim\_kill\_event(int8\_t id);
void stim\_remove\_event(int8\_t id);

#ifdef STIM\_DEBUG
uint8\_t stim\_get\_eventnum(void);
void stim\_print\_status(void);
#endif

#endif 

smarttimer.c

/\*
 \* =====================================================================================
 \*
 \* Filename: smarttimer.c
 \*
 \* Description: software timer dispath
 \*
 \* Version: 1.1
 \* Created: 2015/7/14 ÐÇÆÚËÄ ÉÏÎç 10:37:39
 \* Revision: none
 \* Compiler: armcc
 \*
 \* Author: lell(elecsunxin@gmail.com) 
 \* Organization: 
 \*
 \* =====================================================================================
 \*/
//#include <stdlib.h>
#include "smarttimer.h"

#ifdef STIM\_DEBUG
#include <stdio.h>
#endif

struct stim\_event{
  uint32\_t tick_punch;         
  uint32\_t interval;    
  uint32\_t looptimes;   
  uint8\_t id;     
  uint8\_t stat;
  struct stim\_event \*next;
  struct stim\_event \*prev;
};

struct stim\_event\_list{
  struct stim\_event \*head;
  struct stim\_event \*tail;
  uint8\_t count;
};


struct stim\_event\_list\_manager{
  struct stim\_event\_list list[2]; 
  uint8\_t cur_index;
};


static struct stim\_event event_pool[STIM_EVENT_MAX_SIZE];
static struct stim\_event\_list\_manager list_manager;
static struct stim\_event\_list recycle_list;

static void (\*callback_list[STIM_EVENT_MAX_SIZE])(void);
static uint8\_t mark_list[STIM_EVENT_MAX_SIZE];
static uint32\_t current_tick;



/\* 
 \* === FUNCTION ======================================================================
 \* Name: init\_linked
 \* Description: init a stim\_event\_list linked
 \* =====================================================================================
 \*/
static void init\_linked ( struct stim\_event\_list \*list )
{
  list->head = list->tail = NULL;
  list->count = 0;
}		/\* ----- end of static function init\_linked ----- \*/


/\* 
 \* === FUNCTION ======================================================================
 \* Name: remove\_node
 \* Description: remove a node from a stim\_event\_list linked
 \* =====================================================================================
 \*/
static void remove\_node ( struct stim\_event \*event, struct stim\_event\_list \*list )
{

  if(list->head == event){
    list->head = event->next;
    if(list->head == NULL){
      list->tail = NULL;
    }else{
      event->next->prev = NULL;
    }
  }else{
    event->prev->next = event->next;
    if(event->next == NULL){
      list->tail = event->prev;
    }else{
      event->next->prev = event->prev;
    }
  }

  list->count--;
}		/\* ----- end of static function remove\_event ----- \*/


/\* 
 \* === FUNCTION ======================================================================
 \* Name: insert\_node\_prev
 \* Description: insert a nodes in stim\_event\_list linked
 \* =====================================================================================
 \*/
static void insert\_node\_prev ( struct stim\_event \*new_node,struct stim\_event \*node,struct stim\_event\_list \*list )
{
  new_node->next = node;
  if(node->prev == NULL){
    list->head = new_node;
    new_node->prev = NULL;
  }else{
    new_node->prev = node->prev;
    node->prev->next = new_node;
  }
  node->prev = new_node;

  list->count++;
}		/\* ----- end of static function insert\_node\_prev ----- \*/

/\* 
 \* === FUNCTION ======================================================================
 \* Name: insert\_to\_tail
 \* Description: insert a nodes in stim\_event\_list linked
 \* =====================================================================================
 \*/
static void insert\_to\_tail ( struct stim\_event \*new_node ,struct stim\_event\_list \*list)
{
  struct stim\_event \*node = list->tail;

  if(list->count == 0){
    list->head = new_node;
    list->tail = new_node;
    new_node->next = NULL;
    new_node->prev = NULL;
  }else{
    node->next = new_node;
    new_node->prev = node;
    new_node->next = NULL;
    list->tail = new_node;
  }

  list->count++;
}		/\* ----- end of static function insert\_event ----- \*/

/\* 
 \* === FUNCTION ======================================================================
 \* Name: malloc\_event
 \* Description: get a new event struct from event\_pool
 \* return: a pointer of event struct. 
 \*
 \* =====================================================================================
 \*/
static struct stim\_event\* malloc\_event (void)
{
  uint8\_t i;
  for(i = 0; i < STIM_EVENT_MAX_SIZE; i++){
    if(event_pool[i].stat == STIM_EVENT_IDLE){
      event_pool[i].stat = STIM_EVENT_ACTIVE;
      return &event_pool[i];
    }
  }
  return NULL;
}		/\* ----- end of static function stim\_malloc\_event ----- \*/


/\* 
 \* === FUNCTION ======================================================================
 \* Name: free\_event
 \* Description: release event to event\_pool
 \* =====================================================================================
 \*/
static void free\_event (struct stim\_event \*event)
{
  callback_list[event->id] = NULL;
  mark_list[event->id] = STIM_INVALID;

  event->stat = STIM_EVENT_IDLE;
  event->interval = 0;
  event->looptimes = 0;
  event->tick_punch = 0;
  event->prev = NULL;
  event->next = NULL;

}		/\* ----- end of static function stim\_free\_event ----- \*/


/\* 
 \* === FUNCTION ======================================================================
 \* Name: insert\_event
 \* Description: insert a timer event to a special list
 \* =====================================================================================
 \*/
static void insert\_event ( struct stim\_event \*event,struct stim\_event\_list \*list )
{
  uint8\_t i;
  struct stim\_event \*node;

  if(list->count == 0){
    //insert event to a empty linked
    insert\_to\_tail(event,list);
  }else{
    node = list->head;
    for(i = 0; i < list->count; i++){
      if(event->tick_punch > node->tick_punch){
        node = node->next;
      }else{
        break;
      }
    }

    if(node == NULL){
      //insert event to linked tail
      insert\_to\_tail(event,list);
    }else{
      //insert event to a linked
      insert\_node\_prev(event,node,list);
    }
  }
}		/\* ----- end of static function insert\_event ----- \*/



/\* 
 \* === FUNCTION ======================================================================
 \* Name: find\_event
 \* Description: 
 \* =====================================================================================
 \*/
static struct stim\_event\* find\_event ( int8\_t id, struct stim\_event\_list \*list )
{ 
	uint8\_t i;
  struct stim\_event \*event;
  event = list->head;
  for(i = 0; i < list->count; i++){
    if(event->id == id){
      break;
    }else{
      event = event->next;
    }
  }

  return event;
}		/\* ----- end of static function find\_event ----- \*/



/\* 
 \* === FUNCTION ======================================================================
 \* Name: recyle\_event
 \* Description: insert an event which stat is STIM\_EVENT\_RECYCLE into recycle linked
 \* =====================================================================================
 \*/
static void recyle\_event ( struct stim\_event \*event )
{
  struct stim\_event\_list \*list = &list_manager.list[list_manager.cur_index];

  remove\_node(event,list);
  insert\_to\_tail(event,&recycle_list);
}		/\* ----- end of static function recyle\_event ----- \*/





/\*
 \* === FUNCTION ======================================================================
 \* Name: push\_event
 \* Description: push a stim\_event to event linked list.
 \* =====================================================================================
 \*/
static struct stim\_event\* push\_event ( uint32\_t delayms, void (\*callback)(void),uint16\_t times )
{
  struct stim\_event \*event;

  event = malloc\_event();
  event->interval = delayms;
  event->looptimes = times;
  event->next = NULL;
  event->tick_punch = current_tick + delayms;

  mark_list[event->id] = 0;
  if(callback != NULL){
    callback_list[event->id] = callback;
  }

  if(event->tick_punch < current_tick){
    insert\_event(event,&list_manager.list[list_manager.cur_index ^ 0x01]);
  }else{
    insert\_event(event,&list_manager.list[list_manager.cur_index]);
  }

  return event;
}		/\* ----- end of static function stim\_push\_delay\_event ----- \*/


/\*
 \*
 \* === FUNCTION ======================================================================
 \* Name: stim\_delay
 \* Description: wait some milliseconds.It will blocking process until time out.
 \* =====================================================================================
 \*/
void stim\_delay ( uint16\_t delayms)
{

  struct stim\_event \*event;
  CLOSE\_INTERRUPT();  
  event = push\_event(delayms,NULL,1);
  OPEN\_INTERRUPT();
  while(mark_list[event->id] == 0);
}		/\* ----- end of function stim\_delay ----- \*/




/\*
 \* === FUNCTION ======================================================================
 \* Name: stim\_runlater
 \* Description: run callback function after some milliseconds by asynchronous.
 \* =====================================================================================
 \*/
int8\_t stim\_runlater ( uint16\_t delayms, void (\*callback)(void))
{
  struct stim\_event \*event;

  CLOSE\_INTERRUPT(); 
  event = push\_event(delayms,callback,1);
  OPEN\_INTERRUPT(); 
  return event->id;
}		/\* ----- end of function stim\_runlater ----- \*/
/\*
 \* === FUNCTION ======================================================================
 \* Name: stim\_loop
 \* Description: looping invok each interval by asynchronous.
 \* =====================================================================================
 \*/
int8\_t stim\_loop ( uint16\_t delayms, void (\*callback)(void), uint16\_t times)
{
  struct stim\_event \*event;

  CLOSE\_INTERRUPT();  
  event = push\_event(delayms,callback,times);
  OPEN\_INTERRUPT(); 
  return event->id;
}		/\* ----- end of function stim\_loop ----- \*/



/\* 
 \* === FUNCTION ======================================================================
 \* Name: stim\_kill\_event
 \* Description: 
 \* =====================================================================================
 \*/
void stim\_kill\_event(int8\_t id)
{
  uint8\_t i;
  struct stim\_event\_list \*list;
  struct stim\_event \*event;

  CLOSE\_INTERRUPT();  
  for(i = 0; i < 2; i++){
    list = &list_manager.list[i];
    event = find\_event(id,list);
    if(event != NULL){
      remove\_node(event,list);
      free\_event(event);
      break;
    }
  }
  OPEN\_INTERRUPT(); 
}


/\* 
 \* === FUNCTION ======================================================================
 \* Name: stim\_remove\_event
 \* Description: 
 \* =====================================================================================
 \*/
void stim\_remove\_event(int8\_t id)
{
  uint8\_t i;
  struct stim\_event\_list \*list;
  struct stim\_event \*event;

  CLOSE\_INTERRUPT();  
  for(i = 0; i < 2; i++){
    list = &list_manager.list[i];
    event = find\_event(id,list);
    if(event != NULL){
      event->stat = STIM_EVENT_RECYCLE;
      recyle\_event(event);
      break;
    }
  }
  OPEN\_INTERRUPT(); 
}



/\*
 \* === FUNCTION ======================================================================
 \* Name: stim\_tick
 \* Description: engine of smarttimer.
 \* It must be execute in systick( or hardware timer) interrupt
 \* =====================================================================================
 \*/
void stim\_tick (void)
{
  struct stim\_event \*event;
  struct stim\_event\_list \*list;

  if(((current_tick + 1) & 0xffffffff) < current_tick){
    list_manager.cur_index ^= 0x01;
  }
  current_tick++;

  list = &list_manager.list[list_manager.cur_index];
  event = list->head;

  while(event != NULL && event->tick_punch <= current_tick){
    mark_list[event->id] += 1;



    if((event->looptimes != STIM_LOOP_FOREVER) && 
        (--event->looptimes == 0)){
      event->stat = STIM_EVENT_RECYCLE;
      recyle\_event(event);
    }else{
      event->tick_punch = current_tick + event->interval;
      remove\_node(event,list);
      if(event->tick_punch < current_tick){
        list = &list_manager.list[list_manager.cur_index ^ 0x01];
      }
      insert\_event(event,list);
    }
    event = event->next;
  }

}		/\* ----- end of function stim\_dispach ----- \*/


/\* 
 \* === FUNCTION ======================================================================
 \* Name: stim\_mainloop
 \* Description: checkout mark\_list,and execute callback funtion if mark be setted.
 \* this function must be execute by while loop in main.c
 \* =====================================================================================
 \*/
void stim\_mainloop ( void )
{
  uint8\_t i;
  struct stim\_event \*event;

  for(i = 0; i < STIM_EVENT_MAX_SIZE; i++){
    if((mark_list[i] != STIM_INVALID) && (mark_list[i] > 0)){
      if(callback_list[i] != NULL){
        callback_list[i]();
      }
      mark_list[i] -= 1;


![img](https://img-blog.csdnimg.cn/img_convert/90dd334d17880b2dab97da6820493003.png)
![img](https://img-blog.csdnimg.cn/img_convert/b58489944ec17b6d6dcce72b330acbed.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

op in main.c
 \* =====================================================================================
 \*/
void stim\_mainloop ( void )
{
  uint8\_t i;
  struct stim\_event \*event;

  for(i = 0; i < STIM_EVENT_MAX_SIZE; i++){
    if((mark_list[i] != STIM_INVALID) && (mark_list[i] > 0)){
      if(callback_list[i] != NULL){
        callback_list[i]();
      }
      mark_list[i] -= 1;


[外链图片转存中...(img-L0JUB2LB-1715555734764)]
[外链图片转存中...(img-DV1GHTTH-1715555734764)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值