结合时间触发+消息+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条回答
kinsno
1楼-- · 2019-12-21 13:35
本帖最后由 kinsno 于 2013-9-17 13:45 编辑
summarize 发表于 2013-9-9 07:21
突然发现自己还可以管理帖子,故将整个过程的重要事件推荐到的LZ位,这样就不用全部看完帖子就能了解整个过 ...


最新版本的升级呢? 还有吗?是否用在量产的产品上了啊?
1、应该写出你这个类OS,如果要使用,要注意一些什么点,比如延时,比如程序的写法?比如变量的定义。这些我觉得出也得出一个文档,这样避免很多人中招。
summarize
2楼-- · 2019-12-21 18:24
kinsno 发表于 2013-9-17 13:42
最新版本的升级呢? 还有吗?是否用在量产的产品上了啊?
1、应该写出你这个类OS,如果要使用,要注意一 ...

最新版本在 48楼,简约版本在公司内部推广中(目前这个版本比较完善,不少人理解接受有困难,特别是老员工).使用说明在47楼,已经说明了使用中要注意的大部分问题.具体还有哪些要注意的问题请指出,后续加入完善.
二进制
3楼-- · 2019-12-21 22:11
 精彩回答 2  元偷偷看……
kinsno
4楼-- · 2019-12-22 03:59
summarize 发表于 2013-9-17 13:52
最新版本在 48楼,简约版本在公司内部推广中(目前这个版本比较完善,不少人理解接受有困难,特别是老员工). ...


#define SCH_CURR_LINE                (SCH_UINT8)(__LINE__+(!__LINE__))         ->这个定义是不是有问题,应该是只获取当前的行号“__LINE__”,在后面又加上一个!是什么意思呢?

没写出应该程序架构里面应该避免啥东西的?原protolthread应该是不能在程序内部使用SWITCH了。你这个呢?
summarize
5楼-- · 2019-12-22 08:59
本帖最后由 summarize 于 2013-9-22 21:10 编辑
kinsno 发表于 2013-9-22 14:59
#define SCH_CURR_LINE                (SCH_UINT8)(__LINE__+(!__LINE__))         ->这个定义是不是有问题,应该是只 ...


#define SCH_CURR_LINE                (SCH_UINT8)(__LINE__+(!__LINE__))         ->这个定义是不是有问题,应该是只获取当前的行号“__LINE__”,在后面又加上一个!是什么意思呢?
------------------------------------------------------------------------------
多谢提醒,我实际测试了一下,与  #define SCH_CURR_LINE                (SCH_UINT8)(__LINE__)  相比,加上 +(!__LINE__)) 后 ,它只能解决0x00与0x0100行不会冲突(转成8位后同时为0,编译会提示出错)。0x00行计算结果为0x01。0x0100行计算结果为0x00。但它并不能解决如0x01行与0x0101行的冲突,因为这两个行的计算结果都是0x01。所以这个算法基本没什么意义了,或者编译提示重复定义出错时,加个回车键是最简单有效的办法。


没写出应该程序架构里面应该避免啥东西的?原protolthread应该是不能在程序内部使用SWITCH了。你这个呢?
------------------------------------------------------------------------------
如果我没记错 protolthread 应该是有用switch实现跳转的版本和用goto代替switch来实现的版本。如果是switch版本,则也不能在程序内部使用switch了。如果是goto版本,则程序内部可以用switch。因为本调度器是用switch实现跳转,所以程序内部也不能用switch了。但是准确来说,应该是这个程序内因为使用了“SCHTaskBegin() ”(内含switch),所以不能再次使用switch了,但其所调用的子函数,如果没有使用SCHTaskBegin() ,则也是可以使用swithc的。这点注意事项已经在使用说明中的例子里的注释中说明了。

“while(1)  //每个任务内都要有一个死循环。同时还要有一个挂起任务的操
//如延时或等待消息。同时注意不能使用switch语句,但可在调用函数内使用”      详见47楼。

或者,以后可以出一个goto版本的,让它在程序内部也可以用swithc。
zhwm3064
6楼-- · 2019-12-22 12:04
目前我还看不懂楼主的内容
不过楼主说的“而且此间隔在任务执行过程中是可以修改的。”这一条好象不太好,是不是会造成调度器时标的改变,影响计时的准确性?

一周热门 更多>