STM32 简单多任务调度

STM32的开发目前大多数还开处于“裸奔”的阶段,处于开发成本的考虑,可能还未嵌入任何的RTOS系统,由于没有操作系统的支持,因而不能方便的对多任务进行调度和管理,在main函数中你可能会写成如下方式:
  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的处理。因此可以考虑实现一个调度策略来解决这个问题。对于每个任务,我们可以定义这样一个结构:
  1. typedef struct{
  2.           void (*fTask)(void);
  3.           int64u uNextTick;
  4.           int32u uLenTick;
  5. }sTask;
复制代码

其中fTask为任务指针,指向具体的任务,uNextTick为该任务下一次执行的时间,uLenTick为任务的调度周期或叫调度频率,即每隔多长时间执行一次。

        按照这个结构,可以预先定义一个结构体数组,然后将要调用的任务和任务的调度时间按照如下方式罗列出来:

  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函数中,不断的轮询这个数组,然后将当前任务的下一次调用时间和当前时间比较,如果发现轮到该任务执行,就执行该任务,执行完成后,将该任务的下一次执行时间设为当前时间加任务的调度时间,然后按照此方法去执行下一个需要执行的任务,代码如下:
  1.         while (1)
  2.         {
  3.                 // 任务循环
  4.                 for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
  5.                 {
  6.                         if (mTaskTab[i].uNextTick <= GetTimingTick())
  7.                         {
  8.                                 mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
  9.                                 mTaskTab[i].fTask();        
  10.                         }
  11.                 }
  12.         }
复制代码

   这样,就可以对多个任务做一个简单的调度,以后添加任务时只需要在mTaskTab表中添加即可,需要强调的是,由于执行每个任务也需要耗费时间,就会导致一个任务的实际调度周期可能会比设定的调度周期要长,这样会存在时间不准的情况,当然这仅仅是适合于对轮询周期不是很严格的任务,如果想要任务在严格的时间周期内执行或者需要更精确的时间处理,则必须采用定时器的方式了。

附:


        完整的main文件代码:

  1. #ifndef ARRAYSIZE
  2. #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
  3. #endif

  4. // 任务结构
  5. typedef struct{
  6.           void (*fTask)(void);
  7.           u64 uNextTick;
  8.           u32 uLenTick;
  9. }sTask;


  10. // 任务列表
  11. static sTask mTaskTab[] = 
  12. {
  13.          {Task_SysTick,    0, 0}
  14.         ,{Task1,           0, 10}   // 10ms执行一次        
  15.         ,{Task2,           0, 200}  // 200ms执行一次        
  16.         
  17.         // 在这之前添加任务
  18. };

  19. /*******************************************************************************
  20. * Function Name  : main
  21. * Description    : Main program.
  22. * Input          : None
  23. * Output         : None
  24. * Return         : None
  25. *******************************************************************************/
  26. int main(void)
  27. {
  28.         int i = 0;
  29.         // 硬件初始化
  30.         HW_init();
  31.         // 初始化系统Tick任务
  32.         dev_SysTick_init(void);
  33.         // ...  
  34.         while (1)
  35.         {
  36.                 // 任务循环
  37.                 for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
  38.                 {
  39.                         if (mTaskTab[i].uNextTick <= GetTimingTick())
  40.                         {
  41.                                 mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
  42.                                 mTaskTab[i].fTask();        
  43.                         }
  44.                 }
  45.         }
复制代码
Task_SysTick任务相关代码:
  1. volatile int64u g_TimingTick = 0;
  2. volatile int64u g_TimingTickOld = 0;

  3. //=================================================================================================
  4. //【函 数 名 称】 void dev_SysTick_init(void)
  5. //【参       数】 
  6. //【功       能】 初始化
  7. //【返   回  值】 None
  8. //【创   建  者】 2010-07-27 firehood
  9. //=================================================================================================
  10. void dev_SysTick_init(void)
  11. {
  12.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  13.         /* Time base configuration */
  14.         TIM_TimeBaseStructure.TIM_Period = 65535;               
  15.         TIM_TimeBaseStructure.TIM_Prescaler = 36000-1; 
  16.         TIM_TimeBaseStructure.TIM_ClockDivision = 0;    
  17.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
  18.         
  19.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  20.         
  21.         TIM_SetCounter(TIM2, 0);

  22.         /* TIM enable counter */
  23.         TIM_Cmd(TIM2, ENABLE);
  24. }

  25. //=================================================================================================
  26. //【函 数 名 称】 void GetTimingTick(void)
  27. //【参       数】 
  28. //【功       能】 获取MCU启动后的运行时间
  29. //【返   回  值】 MCU启动后的运行时间,单位ms
  30. //【创   建  者】 2010-07-27 firehood
  31. //=================================================================================================
  32. int64u GetTimingTick(void)
  33. {
  34.         return g_TimingTick;
  35. }

  36. //=================================================================================================
  37. //【函 数 名 称】 void Task_SysTick(void)
  38. //【参       数】 
  39. //【功       能】 Tick任务,从TIM2获取系统时间
  40. //【返   回  值】 None
  41. //【创   建  者】 2010-07-27 firehood
  42. //=================================================================================================
  43. void Task_SysTick(void)
  44. {
  45.         int16u temp = TIM_GetCounter(TIM2);

  46.         if (temp > 1000)
  47.         {
  48.                 TIM_SetCounter(TIM2, 0);
  49.                 g_TimingTickOld = g_TimingTickOld + temp;
  50.                 temp = 0;
  51.         }
  52.         g_TimingTick = g_TimingTickOld + temp;
  53. }
复制代码
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值