结合时间触发+消息+protothread思想+支持优先级的非抢占调度器

2019-12-13 18:20发布

本帖最后由 summarize 于 2013-5-19 14:47 编辑

废话少说,先上stm8s103 IAR库工程代码压缩包。
Schedule-IAR-STM8S103.rar (416.35 KB, 下载次数: 538) 2013-5-19 14:15 上传 点击文件名下载附件

工程是在stm8s103f3单片机上调度通过,已经用消息实现了 UART1_TX模块的共享,即UART1_RX接收到的数据+0x11后再通过UART_TX模块发送回去,同时ADC1 通道3的转换结果也通过UART1_TX模块发送出去.见下图

1.ADC1转换结果每1秒上传一次到PC。测试式给ADC1通道3供的是5V电,所以结果是0x03ff.即1023.

共享时接收到的数据.png (61.3 KB, 下载次数: 0) 下载附件 2013-5-19 14:16 上传

3.支持非抢占式优先级调度,优先级顺序就是创建任务时的顺序,由高到底。其实现思想是,每一个任务运行结束后,都重新回到第一个创建的任务处按顺序查找某个任务是否满足运行条件,所以先创建的任务会先被“发现”其满足运行条件并运行之,核心代码如下

a.任务控制块数据结构
  1. struct SchTcb
  2. {
  3. #if SCH_CFG_Q_EN > 0u
  4.   void          *pData;       //消息指针
  5.   SCH_UINT8 Size;         //消息大小
  6. #endif

  7.   SCH_DLY_TYPE        TimeCounter;  //定时计数器,时基为 "SCH_SYS_TICKS_MS"
  8.   void          (*pTask)();   //任务指针
  9.   struct SchTcb *pNextTCB;    //下一个任务控制块指针
  10. };
复制代码b.调度核心
  1. void SCHTaskSchedStart(void)
  2. {
  3. SCHED_SART:
  4.        
  5.   pCurTCB = pFirstTCB;                        //指向第一个创建的任务,之后按创建时的顺序执行下去

  6.   while (1)                                 
  7.   {
  8.     SCHTimeTick();                            //如果任务Tick满足条件,则将其置于可执行状态

  9.     if (SCH_TASK_RUN == pCurTCB->TimeCounter) //任务处于可执行状态
  10.     {
  11.       pCurTCB->TimeCounter = SCH_TASK_PEND;   //设置为挂起状态,保证任务只执行一次

  12.       pCurTCB->pTask();                       //执行当前任务控制块指向的任务

  13.       goto SCHED_SART;                        //每执行完一个任务,都重新查找一次可执行最高优先级任务
  14.     }

  15.     pCurTCB = pCurTCB->pNextTCB;              //指向下一个任务控制块,查找下个任务是否可执行
  16.   }
  17. }
复制代码“schedule.c”和"schedule.h"已经设置为只读属性,无特殊情况不建议修改,"sch_cfg.h"则为开放给用户的接口,可定义数据类型、调度器节拍和配置是否使用消息。

本人水平有限,欢迎大家测试、指正不足。

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
101条回答
aming2046
1楼-- · 2019-12-25 15:17
那你的意思是
switch(*)
{
case 0: ...

case SCH_CURR_LINE: ...

case SCH_CURR_LINE: ...
}
等价于switch(*)
{
case 0: while{case SCH_CURR_LINE: ...

case SCH_CURR_LINE: ...}


}
summarize
2楼-- · 2019-12-25 16:34
aming2046 发表于 2013-12-17 22:43
那你的意思是
switch(*)
{

是的.         
aming2046
3楼-- · 2019-12-25 21:56
楼主能否帮我看看这段语句是什么意思
for (i = 0; i < TaskNumberSum; i++)
    {
      if ((pTCB->TimeCounter != SCH_TASK_PEND)
          && (pTCB->TimeCounter > 0))
      {
        pTCB->TimeCounter--;
      }

      pTCB = pTCB->pNextTCB;
    }
summarize
4楼-- · 2019-12-26 01:16
 精彩回答 2  元偷偷看……
aming2046
5楼-- · 2019-12-26 01:48
多谢楼主啊,对了楼主能否将你的这个程序的执行流程说明一下啊?呵呵,我的理解是:首先创建一个循环链表,然后将循环链表里面的6个成员分别指向6个任务,然后用定时器来轮询这个链表来调度任务,任务与任务之间,中断与任务之间还可以通过发送消息来判断任务是否处于可执行状态。
summarize
6楼-- · 2019-12-26 02:47
aming2046 发表于 2013-12-21 17:30
多谢楼主啊,对了楼主能否将你的这个程序的执行流程说明一下啊?呵呵,我的理解是:首先创建一个循环链表, ...

你的理解基本正确,看下任务控制块结构体:

struct SchTcb
{
#if SCH_CFG_Q_EN > 0u
  void                        *pData;       //消息指针
  SCH_UINT8                 Size;          //消息的大小
#endif

  SCH_DLY_TYPE                TimeCounter;  //定时计数器,时基为 "SCH_SYS_TICKS_MS"
  void                         (*pTask)();    //任务指针
  struct SchTcb *pNextTCB;              //下一个任务控制块指针
};

1.对每个任务都有一个任务控制块(SchTcb).

2.然后让这些任务控制块首尾相连构成循环链表(pNextTCB 来实现).

3.任务控制块的任务指针指向该任务(pTask 指向任务).

4.任务调度:
    A.每间隔特定时间对TimeCounter进行自减,自减条件是TimeCounter大于0且不等于0xffff(些值表示任务挂起),当TimeCounter为0进会被执行,且每执行完一个任务后就会重新从头查找一遍哪个任务满足执行条件,这样即实现了创建任务的顺序即任务的优先级顺序(最先创建的任务优先级最高),在每个任务执行后重新设置TimeCounter为某个固定值即可实现任务定时运行.

   B.任务与任务之间,中断与任务之间,可通过设置TimeCounter的值为0xffff来挂起任务,或设置TimeCounter的值为0来恢复任务.

   C.消息实现:如"B"中所述通过设置TimeCounter的不同值来实现任务的挂起或运行,再配合pData和Size来携带消息内容及数据长度.即实现了任务的消息等待(任务挂起),和任务的消息发送(恢复某个任务同时携带有数据).



一周热门 更多>