加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

STM32 简单多任务调度

(2012-09-17 22:13:12)
标签:

it

分类: 摘抄
 

    STM32的开发目前大多数还开处于“裸奔”的阶段,处于开发成本的考虑,可能还未嵌入任何的RTOS系统,由于没有操作系统的支持,因而不能方便的对多任务进行调度和管理,在main函数中你可能会写成如下方式:

  1. int main(void 
  2.  
  3.     while (1)  
  4.      
  5.         Task1(); // 调用任务1   
  6.         Task2(); // 调用任务2   
  7.      
  8.  
int main(void)
{
        while (1)
        {
                Task1(); // 调用任务1
                Task2(); // 调用任务2
        }
}

       但简单这样写的话会存在一个问题,假如任务1是一个很紧急的任务,如AD采样任务,需要不断的去执行,而任务2是一个不太紧急的任务,只要保证一段时间执行一次就行(如控制LED灯闪烁,只需要每1s钟闪烁一次),这样的话一是频繁的调用任务2占用了任务1执行的时间,二是任务2根本不需要这样频繁的执行,白白耗费了CPU的处理。因此可以考虑实现一个调度策略来解决这个问题。对于每个任务,我们可以定义这样一个结构:

  1. typedef struct 
  2.       void (*fTask)(void);  
  3.       int64u uNextTick;  
  4.       int32u uLenTick;  
  5. }sTask;  
typedef struct{
          void (*fTask)(void);
          int64u uNextTick;
          int32u uLenTick;
}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. };  
// 任务列表
static sTask mTaskTab[] = 
{
         {Task_SysTick,    0, 0}
        ,{Task1,           0, 10}    // 10ms执行一次
        ,{Task2,           0, 200}   // 200ms执行一次       
};

        其中第一个任务Task_SysTick为计算系统时间的任务,用以获取上电后运行的时间(Task_SysTick任务相关代码附在文章后面)。这里默认任务下一次执行的时间为0,在main函数中,不断的轮询这个数组,然后将当前任务的下一次调用时间和当前时间比较,如果发现轮到该任务执行,就执行该任务,执行完成后,将该任务的下一次执行时间设为当前时间加任务的调度时间,然后按照此方法去执行下一个需要执行的任务,代码如下:

  1. while (1)  
  2.  
  3.     // 任务循环   
  4.     for (i 0; 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.   
       while (1)
        {
                // 任务循环
                for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
                {
                        if (mTaskTab[i].uNextTick <= GetTimingTick())
                        {
                                mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
                                mTaskTab[i].fTask();    
                        }
                }
        } 

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

附:

        完整的main文件代码:

  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. int main(void 
  25.  
  26.     int 0;  
  27.     // 硬件初始化   
  28.     HW_init();  
  29.     // 初始化系统Tick任务   
  30.     dev_SysTick_init(void);  
  31.     // ...     
  32.     while (1)  
  33.      
  34.         // 任务循环   
  35.         for (i 0; ARRAYSIZE(mTaskTab); i++)  
  36.          
  37.             if (mTaskTab[i].uNextTick <= GetTimingTick())  
  38.              
  39.                 mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;  
  40.                 mTaskTab[i].fTask();      
  41.              
  42.          
  43.       
#ifndef ARRAYSIZE
#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

// 任务结构
typedef struct{
          void (*fTask)(void);
          u64 uNextTick;
          u32 uLenTick;
}sTask;


// 任务列表
static sTask mTaskTab[] = 
{
         {Task_SysTick,    0, 0}
        ,{Task1,           0, 10}   // 10ms执行一次 
        ,{Task2,           0, 200}  // 200ms执行一次        
        
        // 在这之前添加任务
};


int main(void)
{
        int i = 0;
        // 硬件初始化
        HW_init();
        // 初始化系统Tick任务
        dev_SysTick_init(void);
        // ...  
        while (1)
        {
                // 任务循环
                for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
                {
                        if (mTaskTab[i].uNextTick <= GetTimingTick())
                        {
                                mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
                                mTaskTab[i].fTask();    
                        }
                }
        } 
}


Task_SysTick任务相关代码:

  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.       
  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.       
  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.  

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有