STM32 简单多任务调度

2019-07-25 10:43发布


  STM32的开发目前大多数还开处于“裸奔”的阶段,处于开发成本的考虑,可能还未嵌入任何的RTOS系统,由于没有操作系统的支持,因而不能方便的对多任务进行调度和管理,在main函数中你可能会写成如下方式:[cpp] view plaincopy 1.  int main(void)   2.  {   3.      while (1)   4.      {   5.          Task1(); // 调用任务1   6.          Task2(); // 调用任务2   7.      }   8.  }  
       但简单这样写的话会存在一个问题,假如任务1是一个很紧急的任务,如AD采样任务,需要不断的去执行,而任务2是一个不太紧急的任务,只要保证一段时间执行一次就行(如控制LED灯闪烁,只需要每1s钟闪烁一次),这样的话一是频繁的调用任务2占用了任务1执行的时间,二是任务2根本不需要这样频繁的执行,白白耗费了CPU的处理。因此可以考虑实现一个调度策略来解决这个问题。对于每个任务,我们可以定义这样一个结构:[cpp] view plaincopy 1.  typedef struct{   2.        void (*fTask)(void);   3.        int64u uNextTick;   4.        int32u uLenTick;   5.  }sTask;  
        其中fTask为任务指针,指向具体的任务,uNextTick为该任务下一次执行的时间,uLenTick为任务的调度周期或叫调度频率,即每隔多长时间执行一次。        按照这个结构,可以预先定义一个结构体数组,然后将要调用的任务和任务的调度时间按照如下方式罗列出来:[cpp] view plaincopy 1.  // 任务列表   2.  static sTask mTaskTab[] =    3.  {   4.       {Task_SysTick,    0, 0}   5.      ,{Task1,           0, 10}    // 10ms执行一次   6.      ,{Task2,           0, 200}   // 200ms执行一次      7.  };  
        其中第一个任务Task_SysTick为计算系统时间的任务,用以获取上电后运行的时间(Task_SysTick任务相关代码附在文章后面)。这里默认任务下一次执行的时间为0,在main函数中,不断的轮询这个数组,然后将当前任务的下一次调用时间和当前时间比较,如果发现轮到该任务执行,就执行该任务,执行完成后,将该任务的下一次执行时间设为当前时间加任务的调度时间,然后按照此方法去执行下一个需要执行的任务,代码如下:[cpp] view plaincopy 1.  while (1)   2.  {   3.      // 任务循环   4.      for (i = 0; i < ARRAYSIZE(mTaskTab); i++)   5.      {   6.          if (mTaskTab.uNextTick <= GetTimingTick())   7.          {   8.              mTaskTab.uNextTick += mTaskTab.uLenTick;   9.              mTaskTab.fTask();       10.         }   11.     }   12. }   
        这样,就可以对多个任务做一个简单的调度,以后添加任务时只需要在mTaskTab表中添加即可,需要强调的是,由于执行每个任务也需要耗费时间,就会导致一个任务的实际调度周期可能会比设定的调度周期要长,这样会存在时间不准的情况,当然这仅仅是适合于对轮询周期不是很严格的任务,如果想要任务在严格的时间周期内执行或者需要更精确的时间处理,则必须采用定时器的方式了。附:        完整的main文件代码:[cpp] view plaincopy 1.  #ifndef ARRAYSIZE   2.  #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))   3.  #endif   4.     5.  // 任务结构   6.  typedef struct{   7.        void (*fTask)(void);   8.        u64 uNextTick;   9.        u32 uLenTick;   10. }sTask;   11.    12.    13. // 任务列表   14. static sTask mTaskTab[] =    15. {   16.      {Task_SysTick,    0, 0}   17.     ,{Task1,           0, 10}   // 10ms执行一次    18.     ,{Task2,           0, 200}  // 200ms执行一次       19.        20.     // 在这之前添加任务   21. };   22.    23. /*******************************************************************************  24. * Function Name  : main  25. * Description    : Main program.  26. * Input          : None  27. * Output         : None  28. * Return         : None  29. *******************************************************************************/   30. int main(void)   31. {   32.     int i = 0;   33.     // 硬件初始化   34.     HW_init();   35.     // 初始化系统Tick任务   36.     dev_SysTick_init(void);   37.     // ...     38.     while (1)   39.     {   40.         // 任务循环   41.         for (i = 0; i < ARRAYSIZE(mTaskTab); i++)   42.         {   43.             if (mTaskTab.uNextTick <= GetTimingTick())   44.             {   45.                 mTaskTab.uNextTick += mTaskTab.uLenTick;   46.                 mTaskTab.fTask();       47.             }   48.         }   49.     }   
} Task_SysTick任务相关代码:[cpp] view plaincopy 1.  volatile int64u g_TimingTick = 0;   2.  volatile int64u g_TimingTickOld = 0;   3.     4.  //=================================================================================================   5.  //【函 数 名 称】 void dev_SysTick_init(void)   6.  //【参       数】    7.  //【功       能】 初始化   8.  //【返   回  值】 None   9.  //【创   建  者】 2010-07-27 firehood   10. //=================================================================================================   11. void dev_SysTick_init(void)   12. {   13.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   14.    15.     /* Time base configuration */   16.     TIM_TimeBaseStructure.TIM_Period = 65535;                  17.     TIM_TimeBaseStructure.TIM_Prescaler = 36000-1;    18.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;       19.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    20.        21.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);   22.        23.     TIM_SetCounter(TIM2, 0);   24.    25.     /* TIM enable counter */   26.     TIM_Cmd(TIM2, ENABLE);   27. }   28.    29. //=================================================================================================   30. //【函 数 名 称】 void GetTimingTick(void)   31. //【参       数】    32. //【功       能】 获取MCU启动后的运行时间   33. //【返   回  值】 MCU启动后的运行时间,单位ms   34. //【创   建  者】 2010-07-27 firehood   35. //=================================================================================================   36. int64u GetTimingTick(void)   37. {   38.     return g_TimingTick;   39. }   40.    41. //=================================================================================================   42. //【函 数 名 称】 void Task_SysTick(void)   43. //【参       数】    44. //【功       能】 Tick任务,从TIM2获取系统时间   45. //【返   回  值】 None   46. //【创   建  者】 2010-07-27 firehood   47. //=================================================================================================   48. void Task_SysTick(void)   49. {   50.     int16u temp = TIM_GetCounter(TIM2);   51.    52.     if (temp > 1000)   53.     {   54.         TIM_SetCounter(TIM2, 0);   55.         g_TimingTickOld = g_TimingTickOld + temp;   56.         temp = 0;   57.     }   58.     g_TimingTick = g_TimingTickOld + temp;   59. }  

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
CallMeWater
1楼-- · 2019-07-25 15:52
有意思,学习了
xinyuan123
2楼-- · 2019-07-25 16:02
有本书叫时间触发嵌入式系统设计模式,可以看看
l6931639
3楼-- · 2019-07-25 21:28
 精彩回答 2  元偷偷看……

一周热门 更多>