极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 73449|回复: 27

[Arduino库]又一个任务调度器,更好地处理多任务

[复制链接]
发表于 2013-7-28 00:05:19 | 显示全部楼层 |阅读模式
本帖最后由 Blanboom 于 2015-2-8 23:09 编辑

论坛里也有人写过类似的库,看样子更简洁一些,占用资源应该会更小:http://www.geek-workshop.com/thread-4852-1-1.html
而我写的就复杂了点,不过功能多了点,例如支持抢占式任务,错误报告,以及自动进入空闲模式。
可根据实际情况选择使用哪个库。

[2015 年 2 月 8 日更新]:由于此类任务调度器不能主动结束掉任务,所以在使用时,需要尽可能降低各个任务在每次执行时消耗的时间。这个帖子介绍了一种方法:http://www.geek-workshop.com/thread-12693-1-1.html

下载地址:https://github.com/blanboom/Arduino-Task-Scheduler
我的博客中的介绍:http://blanboom.org/arduino-task-scheduler-library.html

一般情况下,处理 Arduino 的多个任务,是把所有任务放在 void loop() 里,然后用 delay() 控制时间。不过,任务一多,这种方法方便了。
最近刚刚看了一本书:《时间触发嵌入式系统模式设计》,里面介绍的调度器,可以以特定的周期执行特定的任务,值得在 Arduinio 项目中借鉴。我也刚刚把这个调度器移植到 Arduino 中:https://github.com/blanboom/Arduino-Task-Scheduler

基本使用方法
这是一个使用调度器的例子,各个函数的功能都已在注释中标出:
  1. // Arduino 任务调度器 演示程序
  2. // Created by Blanboom
  3. // 2013.7.27
  4. // [url=http://blanboom.org]http://blanboom.org[/url]

  5. #include "TaskScheduler.h"  //包含此头文件,才能使用调度器

  6. // 用于储存 LED 状态
  7. boolean g_led1State=1;
  8. boolean g_led2State=0;

  9. void setup()
  10. {
  11.     // 第12、13脚接有 LED
  12.     pinMode(13,OUTPUT);
  13.     pinMode(12,OUTPUT);

  14.     Sch.init(); //初始化调度器

  15.     //向调度器中添加任务
  16.     //第一个参数为要添加任务的函数名
  17.     //第二个参数为任务第一次执行的时间,
  18.     //    合理设置有利于防止任务重叠,有利以提高任务执行的精度
  19.     //第三个参数是任务执行的周期
  20.     //第二、三个参数的单位均为毫秒,也可配置定时器修改其单位
  21.     //第四个参数代表任务是合作式还是抢占式
  22.     //    一般取1就可以,更多用法请参考下文
  23.     Sch.addTask(led1Update,0,1000,1);  //从第 0 毫秒开始闪烁 LED,每隔 1s, LED 状态改变一次
  24.     Sch.addTask(led2Update,20,500,1);  //从第 20 毫秒开始闪烁 LED,每隔 0.5s, LED 状态改变一次

  25.     Sch.start();//启动调度器
  26. }

  27. void loop()
  28. {
  29.     Sch.dispatchTasks();  // 执行被调度的任务,用调度器时放上这一句即可
  30. }

  31. // 把要调度的任务函数放下面

  32. // 闪烁第 13 脚的 LED
  33. void led1Update()
  34. {
  35.     if(g_led1State==0)
  36.     {
  37.         g_led1State=1;
  38.         digitalWrite(13,HIGH);
  39.     }
  40.     else
  41.     {
  42.         g_led1State=0;
  43.         digitalWrite(13,LOW);
  44.     }
  45. }

  46. // 闪烁第 12 脚的 LED
  47. void led2Update()
  48. {
  49.     if(g_led2State==0)
  50.     {
  51.         g_led2State=1;
  52.         digitalWrite(12,HIGH);
  53.     }
  54.     else
  55.     {
  56.         g_led2State=0;
  57.         digitalWrite(12,LOW);
  58.     }
  59. }
复制代码

程序执行后,两个 LED 分别会以程序中指定的周期和时间闪烁。

更多功能
1. 添加抢占式任务
抢占式任务,简单说,就是优先级比正常任务(合作式任务)高的任务。在这个调度器中,抢占式任务可以打断正常任务,优先执行。
对于一些对时间精度要求较高的任务,可以将任务模式改为抢占式。
修改方法:
在添加任务的函数 Sch.addTask(任务名称,开始时间,执行周期,1) 函数中,将最后一个参数由 1 改为 0,即:
Sch.addTask(任务名称,开始时间,执行周期,1)
这样,该任务就成了抢占式任务。
2. 添加单次执行的任务
可以添加只执行一次的任务,在一段时间后执行。
只需把 Sch.addTask(任务名称,开始时间,执行周期,1) 中的执行周期改为 0 即可。
3. 删除任务
使用函数 Sch.addTask(任务名称,开始时间,执行周期,1) 时,会返回这个任务的 ID,将这个 ID 赋给一个变量。需要删除任务时,用删除任务函数 Sch.DeleteTask(任务ID) ,就能把任务删除。
4. 调整被调度的任务数量
打开 Scheduler.h,找到 #define MAX_TASKS   (10) ,将 10 修改为需要被调度的任务的数量。
5. 自动进入空闲模式
这个调度器能在没有任务的情况下自动进入空闲模式,以节省电量。不需要对程序进行其他修改。
6. 错误报告
打开 Scheduler.h,找到
//#define REPORT_ERRORS // Remove “//” to enable error report,
将前面的 // 去掉,打开错误报告功能。
然后,这条语句的下面,定义了相关错误代码,可根据情况修改。
最后,打开 Scheduler.cpp,找到函数 void Schedule::_reportStatus(void),在里面添加合适的错误报告代码即可。


欢迎大家对这个调度器进行测试,找出 bug 和需要优化的地方。

评分

参与人数 1 +3 +5 +10 收起 理由
lawrencedon + 3 + 5 + 10 很给力!

查看全部评分

回复

使用道具 举报

发表于 2013-7-28 01:02:29 | 显示全部楼层
楼主高人  
回复 支持 反对

使用道具 举报

发表于 2013-7-28 10:37:40 | 显示全部楼层
很不错的说.......
回复 支持 反对

使用道具 举报

发表于 2013-7-29 09:23:17 | 显示全部楼层
学习了~~~~
回复 支持 反对

使用道具 举报

发表于 2013-12-11 15:48:09 | 显示全部楼层
学习学习学习
回复 支持 反对

使用道具 举报

发表于 2013-12-13 08:19:46 来自手机 | 显示全部楼层
学习学习………
回复 支持 反对

使用道具 举报

发表于 2013-12-17 22:01:07 | 显示全部楼层
好是好,但是真正的问题是,A任务需要执行80ms,B任务需要执行10ms, A任务占用很长时间,如果按时间片轮转的话, A任务需要打断,切换到B任务, 但是怎么保存切换的上下文,让A任务能够继续运行呢,就好像中断返回一样。
回复 支持 反对

使用道具 举报

发表于 2013-12-23 17:59:28 | 显示全部楼层
能自己写类就是好。LS考虑的对,如何考虑任务本身的时间?要有个策略。
回复 支持 反对

使用道具 举报

发表于 2014-3-20 21:39:03 | 显示全部楼层
本帖最后由 picfan 于 2014-3-20 21:40 编辑

这个库主要是靠timer中断方式写出来的(没仔细看过,但八九不离十)
既然是中断
就还是回归单晶片的观念
"进入中断,执行中断副程式的时间越短越好"
一般使用(特殊例外)上都是查询并记录后即跳出居多
回主程式后再依纪录结果作相对应的处理工作
在中断副程式内使用大量运算甚至使用delay是大忌
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-25 12:04:24 | 显示全部楼层
devgoon 发表于 2013-12-17 22:01
好是好,但是真正的问题是,A任务需要执行80ms,B任务需要执行10ms, A任务占用很长时间,如果按时间片轮转 ...

最近一段时间一直没登录,今天刚看到...

这个库可以添加抢占式任务,抢占式任务直接在中断服务程序中运行,从而实现两个优先级。

不过,因为这只是一个简单的调度器,无法像嵌入式操作系统一样实现时间片轮转法这样的功能。所以使用时,应尽可能将一个耗时比较长的任务分解成多个耗时比较短的子任务。例如读传感器、处理数据这一任务就可以分开进行,如果处理数据耗时过长,还可以再分几步。
回复 支持 反对

使用道具 举报

发表于 2015-1-25 13:03:55 | 显示全部楼层
强大啊,收藏学习了
回复 支持 反对

使用道具 举报

发表于 2015-1-26 23:18:51 来自手机 | 显示全部楼层
果断收藏,(≧▽≦)
回复 支持 反对

使用道具 举报

发表于 2015-1-28 00:23:28 | 显示全部楼层
这个不错,留下记号,以待以后查找方便
回复 支持 反对

使用道具 举报

发表于 2015-2-2 16:08:38 | 显示全部楼层
楼主顺便把TaskScheduler.h也传过来吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-2-2 17:23:59 | 显示全部楼层
太行摄狼 发表于 2015-2-2 16:08
楼主顺便把TaskScheduler.h也传过来吧

下载地址在这里:https://github.com/blanboom/Arduino-Task-Scheduler
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 16:53 , Processed in 0.043971 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表