单片机裸机任务切换

使用单片机的滴答定时器作为核心时间,实现多任务定时周期执行从而完成任务切换。

1.滴答定时器的配置

bsp_systicker.c:

/*
========================================================================================================================
* 【文件包含】                                         【文件包含】                                          【文件包含】
========================================================================================================================
*/
#include "bsp_systicker.h"


/*
========================================================================================================================
*【本地宏定义】                                       【本地宏定义】                                       【本地宏定义】
========================================================================================================================
*/



/*
========================================================================================================================
*【本地数据类型定义】                              【本地数据类型定义】                              【本地数据类型定义】
========================================================================================================================
*/
/*
************************************************************************************************************************
* 类型定义 :  系统滴答时钟 相关操作数据结构                                                                                                     
************************************************************************************************************************
*/
typedef struct
{
  Ticker_t    TickCount;       /*滴答时钟计数*/
}SysTicker_t;


/*
========================================================================================================================
*【变量定义 & 各种声明】                          【变量定义 & 各种声明】                          【变量定义 & 各种声明】    
========================================================================================================================
*/
static SysTicker_t SysTicker;


/*
========================================================================================================================
*【函数定义】                                          【函数定义】                                          【函数定义】
========================================================================================================================
*/
/*
************************************************************************************************************************
* 函数名称 : BSP_GPIO_Init                                                                                                        
* 功能描述 : 系统定时器初始化。                                                                                                        
* 输入参数 : 无                                                                                                         
* 返回参数 : 无                                                                                                         
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
void BSP_SysTicker_Init(void)
{
  SysTick_Config(SYSTICK_CLK_HZ / SYS_TICKER_PER_SEC);   /* 默认使用内核时钟 core clock*/

  SysTicker.TickCount = 0;     
}


/*
************************************************************************************************************************
* 函数名称 : BSP_SysTicker_GetCurTick                                                                                                        
* 功能描述 : 获取当前系统的tick计数。                                                                                                        
* 输入参数 : 无                                                                                                         
* 返回参数 : 当前系统的tick计数
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
Ticker_t BSP_SysTicker_GetCurTick(void)
{
  return SysTicker.TickCount;
}

/*
************************************************************************************************************************
* 函数名称 : BSP_SysTicker_CalLag                                                                                                        
* 功能描述 : 计算时间差。                                                                                                        
* 输入参数 : tick -- 之前的tick计数      
* 返回参数 : tick计数 与 系统当前tick 计数 的差值。  
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
Ticker_t BSP_SysTicker_CalLag(Ticker_t tick)
{
  if(SysTicker.TickCount >= tick)
  {
    return (SysTicker.TickCount - tick);
  }
  else /*系统时间计数值已经溢出*/
  {
    return (SysTicker.TickCount + (TICKER_MAX-tick) + 1);
  }
}


/*
************************************************************************************************************************
* 函数名称 : SysTick_Handler                                                                                                        
* 功能描述 : 系统定时器中断函数                                                                                                        
* 输入参数 : 无                                                                                                         
* 返回参数 : 无                                                                                                         
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
void SysTick_Handler()
{
  SysTicker.TickCount++;
}

bsp_systicker.h: 

#ifndef  _BSP_SYSTICKER_H_
#define  _BSP_SYSTICKER_H_


/*
========================================================================================================================
* 【文件包含】                                         【文件包含】                                          【文件包含】
========================================================================================================================
*/
#include "bsp.h"


/*
========================================================================================================================
*【全局宏定义】                                       【全局宏定义】                                       【全局宏定义】
========================================================================================================================
*/
#ifndef BSP_CFG_SYS_TICKER_PERIOD
#define  BSP_CFG_SYS_TICKER_PERIOD          1                          /*系统ticker的周期时间,单位ms*/
#endif

#ifndef BSP_CFG_SYS_TICKER_MAX
#define  BSP_CFG_SYS_TICKER_MAX             0xFFFF                     /*系统ticker的的最大计数值,两字节最大0xFFFF*/
#endif


#define  SYS_TICKER_PERIOD                  BSP_CFG_SYS_TICKER_PERIOD  /*系统ticker的周期时间,单位ms*/
#define  SYS_TICKER_PER_SEC                 (1000/SYS_TICKER_PERIOD)   /*每秒ticker的次数*/

#define  TICKER_MAX                         BSP_CFG_SYS_TICKER_MAX    


/*
========================================================================================================================
*【全局数据类型定义】                              【全局数据类型定义】                              【全局数据类型定义】
========================================================================================================================
*/
/*
************************************************************************************************************************
* 类型定义 :                                                                                                       
************************************************************************************************************************
*/
#if (0xFFFF == TICKER_MAX)
typedef  uint16_t              Ticker_t;                
#elif (0xFF == TICKER_MAX)
typedef  uint8_t               Ticker_t;                 
#else 
typedef  uint32_t              Ticker_t;                 
#endif



/*
========================================================================================================================
*【全局声明】                                          【全局声明】                                          【全局声明】
========================================================================================================================
*/
void BSP_SysTicker_Init(void);
Ticker_t BSP_SysTicker_GetCurTick(void);
Ticker_t BSP_SysTicker_CalLag(Ticker_t tick);


#endif                        /* End of module include.  */

其中SYSTICK_CLK_HZ是MCU主频值,需要根据具体的MCU进行修改。SysTick_Config()函数是设置MCU的滴答定时器函数,ARM芯片CM0、CM3的官方库里面基本都有。 

2.任务调度函数

ESF_Tmr.c:

/*
========================================================================================================================
* 【文件包含】                                         【文件包含】                                          【文件包含】
========================================================================================================================
*/
#include "ESF_Tmr.h"


/*
========================================================================================================================
*【本地宏定义】                                       【本地宏定义】                                       【本地宏定义】
========================================================================================================================
*/


/*
========================================================================================================================
*【本地数据类型定义】                              【本地数据类型定义】                              【本地数据类型定义】
========================================================================================================================
*/


/*
========================================================================================================================
*【变量定义 & 各种声明】                          【变量定义 & 各种声明】                          【变量定义 & 各种声明】    
========================================================================================================================
*/


/*
========================================================================================================================
*【函数定义】                                          【函数定义】                                          【函数定义】
========================================================================================================================
*/
/*
************************************************************************************************************************
* 函数名称 : ESF_TmrExeFuncScheduling                                                                                                         
* 功能描述 : 定时执行功能函数的调度                                                                    
* 输入参数 : pTmrExeFuncTab -- 定时执行的功能函数表数组
*            FuncTabSum     -- 功能函数表数组的大小                                                                              
* 返回参数 : 无                                                                 
* 补充说明 : 1、定时执行实现原理:
*               每个定时执行的函数(pTmrExeFunc()),都有其对应的执行周期(ExePeriod)与 时间片计数值(pTickCount)。
*               该函数会将时间片计数值(pTickCount)与系统的时间计数值做比较,
*               当【系统时间计数值 - 时间片计数值(pTickCount) >= 执行周期(ExePeriod)】 时,
*               则执行相应的定时函数,并更新 时间片计数值(pTickCount)。   
*
*            2、执行周期(ExePeriod)的建议:
*               由于每个功能都有单独的时间计数值(pTickCount)。因此可以将各个功能的执行周期设置成不同的值。
*               尽量将执行周期错开,避免在同一个执行周期同时执行太多的功能。
************************************************************************************************************************
*/
void ESF_TmrExeFuncScheduling(const ESF_TmrExeFunc_t *pTmrExeFuncTab, uint8_t FuncTabSum)
{
  uint8_t i;
  Ticker_t lag;

  for(i=0; i<FuncTabSum; i++)
  {
    lag = BSP_SysTicker_CalLag(*(pTmrExeFuncTab[i].pTickCount));     /*计算时间差*/
 
    if(lag >= pTmrExeFuncTab[i].ExePeriod)                           /*时间差值 大于等于 执行周期*/
    {
      if(pTmrExeFuncTab[i].pTmrExeFunc != NULL)                      /*功能要存在*/
      {
        pTmrExeFuncTab[i].pTmrExeFunc(pTmrExeFuncTab[i].ExePeriod);  /*时间到,则执行功能*/
      }
      (*(pTmrExeFuncTab[i].pTickCount)) += lag;                      /*更新时间计数*/
    }  
  }                                                     
}

ESF_Tmr.h:

#ifndef ESF_TMR_H
#define ESF_TMR_H


/*
========================================================================================================================
* 【文件包含】                                         【文件包含】                                          【文件包含】
========================================================================================================================
*/
#include "bsp_systicker.h"


/*
========================================================================================================================
*【全局宏定义】                                       【全局宏定义】                                       【全局宏定义】
========================================================================================================================
*/


/*
========================================================================================================================
*【全局数据类型定义】                              【全局数据类型定义】                              【全局数据类型定义】
========================================================================================================================
*/
/*
************************************************************************************************************************
* 类型定义 :  定时执行的功能函数,处理结构体。                                                                                  
*             将需要定时执行的函数以数组表的方式组织,定义在Flash(ROM)中,
*             而Flash中的数据是不可改变的,因此用*pTickCount指针指向RAM中可操作的数据。
************************************************************************************************************************
*/
typedef struct
{
  void      (*pTmrExeFunc)(Ticker_t  ExePeriod);  /*要执行的函数*/
  Ticker_t  ExePeriod;                            /*执行周期*/
  Ticker_t  *pTickCount;                          /*指向时间计数变量*/
}ESF_TmrExeFunc_t; 



/*
========================================================================================================================
*【对外声明】                                          【对外声明】                                          【对外声明】
========================================================================================================================
*/
void ESF_TmrExeFuncScheduling(const ESF_TmrExeFunc_t *pTmrExeFuncTab, uint8_t ExeSum);


#endif

3.使用方法举例

/*
************************************************************************************************************************
* 函数名称 : Task1                                                                                                        
* 功能描述 : 100ms执行一次                                                                                     
* 输入参数 : ExePeriod 函数执行周期                                                                                  
* 返回参数 : 无                                                                   
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
void Task1(Ticker_t ExePeriod)
{
    printf("Task1\r\n");
}

/*
************************************************************************************************************************
* 函数名称 : Task2                                                                                                        
* 功能描述 : 200ms执行一次                                                                                     
* 输入参数 : ExePeriod 函数执行周期                                                                                  
* 返回参数 : 无                                                                   
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
void Task2(Ticker_t ExePeriod)
{
    printf("Task2\r\n");
}

/*
************************************************************************************************************************
* 函数名称 : Task3                                                                                                        
* 功能描述 : 150ms执行一次                                                                                     
* 输入参数 : ExePeriod 函数执行周期                                                                                  
* 返回参数 : 无                                                                   
* 补充说明 : 无                                                                                                         
************************************************************************************************************************
*/
void Task3(Ticker_t ExePeriod)
{
    printf("Task3\r\n");
}


#define  TASK_TICK_COUNT_BUF_NUM   3
static Ticker_t SaveData_TickCount[TASK_TICK_COUNT_BUF_NUM   ];

static const ESF_TmrExeFunc_t  Task_TmrExeFuncTab[] = 
{
  /*   执行函数              执行周期(ms)         时间计数变量*/
  {     Task1,                100,             &SaveData_TickCount[0]},
  {     Task2,                200,             &SaveData_TickCount[1]},
  {     Task3,                150,             &SaveData_TickCount[2]}
};

#define  TASK_TMR_EXE_FUNC_TAB_NUM     TAB_NUM(Task_TmrExeFuncTab)


void main(void)
{
  while(1)
  {
    /*调度功能函数表------------------------------------------------*/
    ESF_TmrExeFuncScheduling(SaveData_TmrExeFuncTab, SAVEDATA_TMR_EXE_FUNC_TAB_NUM);
  }
}

上面main函数省略了底层IO初始化的相关内容,最后打印出来的数据应该如下:

Task1

Task3

Task1

Task2

Task1

Task3

Task1

Task2

......


PS:整个系统架构要是非阻塞式的

对于有需要延时的可以使用以下方案,这样如果Task的执行周期变了,原本的代码也不会收到太影响

void Task(Ticker_t ExePeriod)
{
  Static Ticker_t Ticker=0;

  if(Ticker >= 2000)
  {
    Ticker = 0;
    //执行相应内容
  }
  else
  {
    Ticker += ExePeriod;
  }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值