在STM32F103上实现基于事件优先级的任务系统

  这个应该属于是状态机的范畴,看了一本《UML 状态机图的使用C/C++设计》里面介绍的Vannilla内核跟介绍的实现思想很像。基于状态机思想设计的程序,可以有效运行于裸机上,基于OS的任务调度的思想,可以设置优先级,打乱程序的执行顺序。与操作系统不同的是,操作系统可以打断任务运行,并把保留每个任务的栈数据,而这个系统即使新加入的任务的优先级比正在运行的任务优先级高,也只能等待上一个任务执行完毕才会被运行。应避免使用延时函数,对于占用时间长的任务,可以对其进行状态分解,比如按键任务:在状态1,首次检测到按下;状态2,下次循环时检测到按键还是处于按下状态时,切换到该状态;状态3,下次循环还是检测按键被按下时切换到改状态,并执行安检任务。利用循环做其他事情的时间所占的时间用来和消抖的时间做抵消,这就是一个简单的状态机任务。

以下程序尽量做到与硬件相关。

  具体实现方法:构建一个任务表示任务属性的结构体

 1 typedef uint32_t event_t;
 2 typedef uint32_t tsTaskPriority_t;
 3 
 4 typedef void ( *pfTsTaskEventHandler_t )( event_t );
 5 
 6  typedef struct tsTaskTableEntry_tag {
 7    event_t events;          //任务事件
 8    tsTaskPriority_t priority; //任务优先级
 9    pfTsTaskEventHandler_t pfTaskEventHandler; //任务执行函数
10  } tsTaskTableEntry_t;

接口头文件 interface.h:

 1 #ifndef _INTERFACE_H_
 2 #define _INTERFACE_H_
 3 
 4 #include "sys.h"
 5 
 6 #define FALSE            0
 7 #define TRUE             1
 8 
 9 typedef uint32_t event_t;
10 typedef uint32_t tsTaskID_t;
11 typedef uint32_t tsTaskPriority_t;
12 typedef uint32_t index_t;
13 typedef uint8_t  bool_t;
14 
15 #define gTsMaxTasks_c                   10                  //最大任务数
16 #define gTsIdleTaskID_c                 (( tsTaskID_t )  0 ) //空闲任务ID
17 #define gTsInvalidTaskID_c              (( tsTaskID_t ) -1 )  //空任务指针
18 #define gTsIdleTaskPriority_c           (( tsTaskPriority_t )  0 ) //空闲任务优先级
19 #define gTsInvalidTaskPriority_c        (( tsTaskPriority_t ) -1 ) //空任务优先级
20 
21 
22 #define _Interrupt_enable()              INTX_ENABLE()             //打开总中断
23 #define _Interrupt_disable()             INTX_DISABLE()            //关闭总中断
24 
25 typedef void ( *pfTsTaskEventHandler_t )( event_t );               //函数指针
26 typedef void ( *pfTimerEventHandler_t )( event_t );                //时间函数指针
27 
28 
29 #define NumberOfElements(array)     ((sizeof(array) / (sizeof(array[0])))) //获取任务队列的大小
30     
31 #endif

既然是基于事件在跑任务,接下来就是事件处理的头文件

event.h

 1 #ifndef _EVENT_H_
 2 #define _EVENT_H_
 3 #include "sys.h"
 4 #include "stdint.h"
 5 #include "interface.h"
 6 
 7 
 8 typedef struct tsTaskTableEntry_tag {
 9   event_t events;               //任务事件
10   tsTaskPriority_t priority;    //任务优先级
11   pfTsTaskEventHandler_t pfTaskEventHandler; //任务执行的函数
12 } tsTaskTableEntry_t;
13 
14 extern tsTaskTableEntry_t maTsTaskTable[gTsMaxTasks_c];    //任务队列  容量为10 可以设置宏定义修改
15 extern tsTaskID_t maTsTaskIDsByPriority[NumberOfElements(maTsTaskTable)]; //优先级列表
16 
17 void IdleTask(event_t events); //空闲任务优先级最低切必须实现,可以在其中实现低功耗功能
18 void TS_ClearEvent(tsTaskID_t taskID,event_t events); //清除任务的事件
19 void TS_Init(void); //任务列表初始化 
20 tsTaskID_t TS_CreateTask(tsTaskPriority_t taskPriority,pfTsTaskEventHandler_t pfTaskEventHandler); //向添加任务到任务列表
21 void TS_DestroyTask  (tsTaskID_t taskID); //从任务列表删除任务
22 bool_t TS_PendingEvents(void);  //查询任务列表是否有可执行的任务
23 void TS_SendEvent(tsTaskID_t taskID,event_t events); //发送消息给制指定的任务 也就是 任务属性中 event
24 void TS_Scheduler(void);  //任务调度
25 
26 #endif

接下来是事件函数的实现:

event.c

  1 #include "event.h"
  2 #include "stdint.h"
  3 #include "global.h"
  4 #include "task.h"
  5 #include "string.h"
  6 #include "delay.h"
  7 #include "timer_event.h"
  8 
  9 static tsTaskTableEntry_t maTsTaskTable[gTsMaxTasks_c];
 10 static tsTaskID_t         maTsTaskIDsByPriority[NumberOfElements(maTsTaskTable)];
 11 
 12 static tsTaskID_t         gIdleTaskID = 0;
 13 
 14 // 清除任务事件标志
 15 void TS_ClearEvent(tsTaskID_t taskID,event_t events)
 16 {
 17 
 18   _Interrupt_disable();            //关闭总中断
 19   maTsTaskTable[taskID].events &= ~events;  // 清标志位,置0
 20   _Interrupt_enable();              //打开总中断
 21 }
 22 
 23 /* Initialize the task scheduler. */
 24 void TS_Init(void) {
 25   memset(maTsTaskTable, (u8)gTsInvalidTaskPriority_c, sizeof(maTsTaskTable));            // 清除任务表为无效
 26   memset(maTsTaskIDsByPriority, (u8)gTsInvalidTaskID_c, sizeof(maTsTaskIDsByPriority));  // 清除优先级表为无效
 27 
 28   gIdleTaskID = TS_CreateTask(IDLE_TASK_PRIORITY, IdleTask);  //创建空闲任务  优先级 0 
 29   gIdleTaskID = TS_CreateTask(PRINTF_TASK_PRIORITY,test_printf);  //打印任务函数 优先级 1 
 30 // gIdleTaskID = TS_CreateTask(LED_FLASH_PRIORITY,LED_Flash);  //打印任务函数 优先级 2
 31   addTimerEvent(CYCLE_EVENT,1,1000,LED_Flash);  //添加定时器事件
 32   
 33     
 34     
 35     
 36     if(gTsInvalidTaskID_c == gIdleTaskID)
 37     {
 38       printf("Task is create failed\r\n");  
 39     }
 40   
 41 }  
 42 /* TS_Init() */
 43 
 44 
 45 /****************************************************************************/
 46 
 47 /* Add a task to the task table.
 48  * Return the task ID, or gTsInvalidTaskID_c if the task table is full.
 49  *
 50  * taskPriority == 0 is reserved for the idle task, and must never be specified
 51  * for any other task. TS_CreateTask() does not check for this.
 52  *
 53  * Note that TS_CreateTask() does not prevent a given event handler function
 54  * pointer from being added more than once to the task table.
 55  *
 56  * Note that if TS_CreateTask() is called with a taskPriority that is the
 57  * same as the priority of a task that is already in the task table, the
 58  * two tasks will end up in adjacent slots in the table. Which one is
 59  * called first by the scheduler is not specified.
 60  */
 61 tsTaskID_t TS_CreateTask(tsTaskPriority_t taskPriority,pfTsTaskEventHandler_t pfTaskEventHandler)
 62 {
 63   index_t i;
 64   index_t freeSlot = gTsInvalidTaskID_c;    //默认为空ID  -1
 65   index_t sizeofTaskId = sizeof(maTsTaskIDsByPriority[0]);
 66 
 67   /* Try to find a free slot in the task table. 发现任务表的空闲位置,索引保存到freeSlot*/
 68   for (i = 0, freeSlot = gTsInvalidTaskID_c;(i < NumberOfElements(maTsTaskTable)); ++i) {
 69     if (maTsTaskTable[i].priority == gTsInvalidTaskPriority_c) {
 70       freeSlot = i;
 71       break;
 72     }
 73   }                                     /* for (i = 0, freeSlot = 0xFF; ... */
 74 
 75   if (freeSlot == gTsInvalidTaskID_c) {
 76     return gTsInvalidTaskID_c;  // 任务表已满
 77   }
 78 
 79   // 初始化任务条目
 80   maTsTaskTable[freeSlot].events = 0;
 81   maTsTaskTable[freeSlot].pfTaskEventHandler = pfTaskEventHandler;
 82   maTsTaskTable[freeSlot].priority = taskPriority;
 83 
 84   /* maTsTaskIDsByPriority is maintained in sorted order, so 1) find the */
 85   /* place where this new task should go; 2) move everything up; and 3) add */
 86   /* the new task. */
 87 
 88   /* 优先级从小到大,等级从高到低 */
 89   for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); i++) {
 90     /* If the end of the table is reached, just add the new task. */
 91     if (maTsTaskIDsByPriority[i] == gTsInvalidTaskPriority_c)
 92     {
 93       break;  // 如果里面存入的是非法的优先级,则说明结束
 94     }
 95     
 96     /* If all tasks from this point on have lower priorities than the task */
 97     /* being added, move the rest up and insert the new one. */
 98    
 99      /* 找到优先级比其大的第一个索引,之后将该索引(包含自己)后的数据都后移,空闲出此位置 */
100     if (maTsTaskTable[maTsTaskIDsByPriority[i]].priority < taskPriority) {
101       memcpy(&maTsTaskIDsByPriority[i + 1],
102                          &maTsTaskIDsByPriority[i],
103                          (NumberOfElements(maTsTaskIDsByPriority) - i - 1) * sizeofTaskId);
104       break;
105     }
106   }                                     /* for (i = 0; ... */
107   maTsTaskIDsByPriority[i] = freeSlot;  // 插入上面找到的索引位置
108 
109   return freeSlot;
110 }                                       /* TS_CreateTask() */
111 
112 
113 
114 /* Remove a task from the task table. */
115 void TS_DestroyTask(tsTaskID_t taskID)
116 {
117   index_t i;
118   index_t sizeofTaskId = sizeof(maTsTaskIDsByPriority[0]);
119 
120   if (maTsTaskTable[taskID].priority == gTsInvalidTaskPriority_c) {
121     return;
122   }
123 
124   /* Mark this slot in the task descriptor table as unused. */
125    /* 清除任务表中的记录 */
126   maTsTaskTable[taskID].priority = gTsInvalidTaskPriority_c;
127 
128   /* Remove this task's ID from the priority table. Find it's position */
129   /* in the table, and shift everything else down. */
130   
131   /* 找到优先级中的索引,将后面的索引前移,并将最后一个位置的索引标记为无效 */
132   for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); i++) {
133     if (maTsTaskIDsByPriority[i] == taskID) {
134       memcpy(&maTsTaskIDsByPriority[i],
135                   &maTsTaskIDsByPriority[i + 1],
136                   (NumberOfElements(maTsTaskIDsByPriority) - i - 1) * sizeofTaskId);
137 
138       /* Note that exactly one entry was removed. */
139       maTsTaskIDsByPriority[NumberOfElements(maTsTaskIDsByPriority) - 1] = gTsInvalidTaskID_c;
140       break;
141     }
142   }
143 
144   return;
145 }                                       /* TS_DestroyTask() */
146 
147 // 查找是否有信号事件
148 bool_t TS_PendingEvents(void) {
149   index_t i;
150 
151   for (i = 0; i < NumberOfElements(maTsTaskTable); ++i) {
152     if (( maTsTaskTable[i].priority != gTsInvalidTaskPriority_c)
153         && maTsTaskTable[i].events) {
154       return TRUE;
155     }
156   }
157 
158   return FALSE;
159 }
160 // 发送信号事件
161 /* Send events to a task. */
162 void TS_SendEvent(tsTaskID_t taskID,event_t events)
163 {
164   _Interrupt_disable();   // 关中断
165   maTsTaskTable[taskID].events |= events;
166   _Interrupt_enable();    //开中断
167 }                                       /* TS_SendEvent() */
168 
169 // 任务轮询函数,在主循环中调用 其他任务没有事件发生时 就执行空闲任务
170 void TS_Scheduler(void) 
171     {
172     index_t activeTask;
173     event_t events;
174     index_t i;
175     index_t taskID;
176 
177   /* maTsTaskIDsByPriority[] is maintained in task priority order. If there */
178   /* are fewer than the maximum number of tasks, the first gInvalidTaskID_c */
179   /* marks the end of the table. */
180   for (;;) {
181     /* Look for the highest priority task that has an event flag set. */
182     activeTask = gTsIdleTaskID_c;                   // 如果未找到有效的信号事件,则调用空闲函数
183     for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); ++i) 
184       {
185       taskID = maTsTaskIDsByPriority[i];
186       if (taskID == gTsInvalidTaskID_c) {
187         break;
188       }
189 
190       if (maTsTaskTable[taskID].events) {
191         activeTask = taskID;                          // 找到有信号事件的任务ID
192         break;
193       }
194     }
195 
196     /* If there are no outstanding events, call the idle task. */
197     _Interrupt_disable();                              // 关中断
198     events = maTsTaskTable[activeTask].events;        // 取出信号
199     maTsTaskTable[activeTask].events = 0;             // 清空原始信号
200     _Interrupt_enable();    //开中断
201 
202     (*maTsTaskTable[activeTask].pfTaskEventHandler)(events); // 调用对用的事件函数
203   }                                                         /* for (;;) */
204 }                                                            /* TS_Scheduler() */
205 
206 /*
207 空闲任务 
  函数功能:统计空闲任务被执行的次数
208 */ 209 void IdleTask(event_t events) 210 { 211 static u16 count = 0; 212 delay_us(100); 213 count++; 214 if(10000 == count) 215 { 216 count = 0; 217 printf("Idle has ran 10000 times\r\n"); 218 } 219 }

测试函数:test_printf 和 LED_Flash

代码如下:

enum TASK_ID //任务优先级枚举
 { 
  IDLE_TASK_PRIORITY   = 0,     
  PRINTF_TASK_PRIORITY = 1,
  LED_FLASH_PRIORITY   = 2,
      
 };    

  /*
 打印测试程序
  */
  void test_printf(event_t events)
  {
      printf("hello world ...%02d\r\n",events); //打印事件
  }
  /*
 LED灯闪烁
 */
 void LED_Flash(event_t events)
 {
    LED0 = !LED0;  //灯闪烁
 }

//定时器3 1秒钟 中断服务程序     
void TIM3_IRQHandler(void)
{      
    static u8 count = 0;
    if(TIM3->SR&0X0001)//溢出中断
    {       
        LED1=!LED1;    
          TS_SendEvent( LED_FLASH_PRIORITY,0x01); //发送事件到制定的任务
         count++;
         if(count%2)
         {
             
          TS_SendEvent(PRINTF_TASK_PRIORITY,count); //发送事件到制定的任务
         
         }            
    }                   
    TIM3->SR&=~(1<<0);//清除中断标志位         
}

在主函数初始化区域执行TS_Init();在while循环调用 TS_Scheduler();就可以了

附上时间事件,类似于操作系统中的定时任务:

timer_event.h

 1 #ifndef _TIMER_EVENT_H_
 2 #define _TIMER_EVENT_H_
 3 #include "sys.h"
 4 #include "interface.h"
 5 
 6 #define     MAX_TIMER_EVENT_Q       5
 7 
 8 #define     CYCLE_EVENT             1L
 9 #define     COMMON_EVENT            0L
10 
11 typedef struct
12 {
13      u8 type;           // 事件类别,循环事件还是延时事件
14      u16 id;            // 定时器编号
15      u16 timer;         // 延时或周期时间计数器
16      u16 timerBackup;   // 用于周期事件的时间计数备份
17      pfTimerEventHandler_t pfTimerEventHandler; //时间事件处理函数 尽量简短
18      
19 }timerEventType;
20 
21 
22 void SysTickHandler(void);    //系统滴答时钟处理函数
23 void addTimerEvent(u8 type, u16 id, u16 timer,pfTimerEventHandler_t fun);//添加时间事件
24 void delTimerEvent(u16 id);      //删除时间事件
25 
26 #endif

实现过程,使用时在丹皮阿尼中添加一个1ms或者10ms的时间片的定时器任务,用来驱动时间事件:

#include "timer_event.h"
#include "event.h"


static u8 _timerEventTail = 0;  //记录当前队列中时间事件的个数
static timerEventType _timerEvent[MAX_TIMER_EVENT_Q];
/* 
 函数描述:系统时间片处理函数
 输入参数; 无
 输出参数:无
 返回值:  无
*/

void SysTickHandler(void) 
 {
    u8 i = 0;
     for(i=0; i<_timerEventTail; i++)
     {
         _timerEvent[i].timer--;
         if(_timerEvent[i].timer == 0)
         {
             _timerEvent[i].pfTimerEventHandler(_timerEvent[i].id);// 事件触发处理函数
 
           if(_timerEvent[i].type == CYCLE_EVENT)
             {
                // 循环事件,重新计数
                 _timerEvent[i].timer = _timerEvent[i].timerBackup;
             }
             else
             {
                 // 延时事件,触发后删除
                 delTimerEvent(_timerEvent[i].id);
             }
         }
     }
 }
 /*
 函数描述:添加定时器事件
 输入参数:
         type:定时器类型 
         id:定时器ID 
         timer:定时时间 
         fun:回调函数
 输出参数:无
 返回值:无
 */
 void addTimerEvent(u8 type, u16 id, u16 timer,pfTimerEventHandler_t fun)
{
     _timerEvent[_timerEventTail].type = type;            //事件类型
     _timerEvent[_timerEventTail].id = id;          //时间事件编号
     _timerEvent[_timerEventTail].timer = timer;          // 时间单位是系统Tick间隔时间
     _timerEvent[_timerEventTail].timerBackup = timer;    // 延时事件并不使用
      _timerEvent[_timerEventTail].pfTimerEventHandler = fun;    // 延时事件并不使用
     _timerEventTail++;
}
/*
函数描述:删除定时器任务
输入参数:定时器ID
输出参数: 无
返回值:无
*/
void delTimerEvent(u16 id)
{
    u8 i = 0,j; 
    for(i=0; i<_timerEventTail; i++)
    {
        if(_timerEvent[i].id == id)
        {
            for(j=i; j<_timerEventTail; j++)
            {
                _timerEvent[j] = _timerEvent[j+1];
            }
            _timerEventTail--;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/zhihong/p/9048471.html