搜索
bottom↓
回复: 64

开源个我的极简定时调度器

  [复制链接]

出0入137汤圆

发表于 2019-11-28 21:37:19 | 显示全部楼层 |阅读模式
就俩文件,五个api:
ztask.h:
  1. #ifndef _ZTASK_H
  2. #define _ZTASK_H

  3. #define ZT_MAX_TASKS 4

  4. typedef void (*zt_func_t)(void);

  5. // should be called in main loop
  6. void zt_poll(void);

  7. // timeout: repeat inteval;   en: start immediately or not
  8. int zt_bind(zt_func_t func, int repeat, int en);

  9. // should be called in systick_irqhandler
  10. void zt_tick(void);

  11. void zt_start(int id);
  12. void zt_stop(int id);

  13. #endif
复制代码


ztask.c:
  1. #include "ztask.h"

  2. typedef struct {
  3.     zt_func_t func;
  4.     unsigned long timeout, repeat;
  5.     int en;
  6. } zt_task_t;

  7. static struct {
  8.     unsigned long ticks;
  9.     int num_tasks;
  10.     zt_task_t tasks[ZT_MAX_TASKS];
  11. } g;

  12. void zt_tick(void)
  13. {
  14.     // overflow not handled. for 1ms tick, it could run 2^32 * 1ms = ~50 days.
  15.     g.ticks++;
  16. }

  17. void zt_poll(void)
  18. {
  19.     int i;
  20.     for(i = 0; i < g.num_tasks; i++) {
  21.         if(g.ticks >= g.tasks[i].timeout) {
  22.             g.tasks[i].timeout = g.ticks + g.tasks[i].repeat;
  23.             if(g.tasks[i].en)
  24.                 g.tasks[i].func();
  25.         }
  26.     }
  27. }

  28. void zt_stop(int id)
  29. {
  30.     if(id < ZT_MAX_TASKS)
  31.         g.tasks[id].en = 0;
  32. }

  33. void zt_start(int id)
  34. {
  35.     if(id < ZT_MAX_TASKS)
  36.         g.tasks[id].en = 1;
  37. }

  38. int zt_bind(zt_func_t func, int repeat, int en)
  39. {
  40.     if(g.num_tasks < ZT_MAX_TASKS) {
  41.         g.tasks[g.num_tasks].func = func;
  42.         g.tasks[g.num_tasks].repeat = repeat;
  43.         g.tasks[g.num_tasks].timeout = 0;
  44.         g.tasks[g.num_tasks].en = en;
  45.         return g.num_tasks++;
  46.     }
  47.     else
  48.         return -1;
  49. }
复制代码

使用方法:
定义两个任务函数:
  1. void blink(void)
  2. {
  3.     GPIOA->ODR |= GPIO_PIN_1;
  4.     _delay_us(10);
  5.     GPIOA->ODR &= ~GPIO_PIN_1;
  6. }

  7. void hello(void)
  8. {
  9.     printf("Hello, world.\n");
  10. }
复制代码


在进入主循环前:

  1.    zt_bind(blink, 100, 1);      // 每100ms执行一次
  2.    zt_bind(hello, 500, 1);     // 每500ms执行一次
复制代码


最后在主循环里调用 zt_poll(), 在systick中断里调用zt_tick(), 就行了。

如果需要控制任务启动/停止, 需要用一个变量保存zt_bind的返回值,然后执行zt_start和zt_stop即可。

出0入0汤圆

发表于 2019-11-28 21:42:40 | 显示全部楼层
谢谢,感谢开源,学习了

出0入0汤圆

发表于 2019-11-28 21:59:18 | 显示全部楼层
有空研究一番,感谢分享,开源必顶。

出0入0汤圆

发表于 2019-11-28 22:06:32 来自手机 | 显示全部楼层
非常小巧,谢谢

出0入0汤圆

发表于 2019-11-28 22:09:21 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2019-11-28 22:09:41 | 显示全部楼层
感谢楼主的奉献啊

出0入0汤圆

发表于 2019-11-28 22:24:00 来自手机 | 显示全部楼层
非常好,感谢开源,有空自己写一遍学习

出5入8汤圆

发表于 2019-11-28 22:31:26 | 显示全部楼层
学习下   谢谢分享

出0入0汤圆

发表于 2019-11-28 22:34:28 来自手机 | 显示全部楼层
学习 谢谢分享

出0入0汤圆

发表于 2019-11-28 22:47:02 | 显示全部楼层
提2个意见:
1. z_bind和z_start好象重复了,好象前者已经暗含后者的功能了,
2. 看注释 z_bind可以决定功能函数执行几次,是不是应该有一个 .en--,这个自减减动作呢。。。当减到0就不运行了。。


出0入137汤圆

 楼主| 发表于 2019-11-28 22:51:50 | 显示全部楼层
kinsno 发表于 2019-11-28 22:47
提2个意见:
1. z_bind和z_start好象重复了,好象前者已经暗含后者的功能了,
2. 看注释 z_bind可以决定功 ...

不是, en就是当布尔量用的,我不想让它依赖stdbool之类c99的库。
zt_bind时如果en参数为0,就是不让它立刻开始自动执行,而是需要时才用zt_start启动。

出0入0汤圆

发表于 2019-11-28 22:53:47 | 显示全部楼层
tomzbj 发表于 2019-11-28 22:51
不是, en就是当布尔量用的,我不想让它依赖stdbool之类c99的库。
zt_bind时如果en参数为0,就是不让它立 ...

那你这个就是永久启动的,并没有执行多少次的功能,是吧。。en也只是个使能,并不是number

出0入0汤圆

发表于 2019-11-28 22:56:46 来自手机 | 显示全部楼层
假如任务超级费时的,怎么办?

出0入137汤圆

 楼主| 发表于 2019-11-28 23:06:45 | 显示全部楼层
kinsno 发表于 2019-11-28 22:53
那你这个就是永久启动的,并没有执行多少次的功能,是吧。。en也只是个使能,并不是number

...

对,没有设计按次数执行。需要的话加一个也容易呀~

出0入137汤圆

 楼主| 发表于 2019-11-28 23:07:08 | 显示全部楼层
hnlg 发表于 2019-11-28 22:56
假如任务超级费时的,怎么办?

交给用户自己考虑吧, hehe

出0入0汤圆

发表于 2019-11-28 23:23:30 | 显示全部楼层
代码这么简短,学习学习

出0入42汤圆

发表于 2019-11-29 08:19:34 | 显示全部楼层
感谢楼主分享,学习一下

出0入0汤圆

发表于 2019-11-29 08:51:50 | 显示全部楼层

感谢楼主分享,学习一下

出0入0汤圆

发表于 2019-11-29 09:06:30 | 显示全部楼层
感谢楼主分享,收藏。

出0入0汤圆

发表于 2019-11-29 09:10:01 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2019-11-29 09:19:06 | 显示全部楼层
非常感谢lz的开源,支持开源精神!
两点建议:
1、timeout 的callback支持参数会更灵活;
2、bind接口,可增加是否初始化timeout变量,满足不需要一启动就马上timeout的情景;

出0入0汤圆

发表于 2019-11-29 09:25:21 | 显示全部楼层
感谢楼主分享,学习一下

出0入0汤圆

发表于 2019-11-29 09:52:54 来自手机 | 显示全部楼层
对单个任务的执行时间有限制吗?超过一个时间片会打断吗

出0入0汤圆

发表于 2019-11-29 10:02:13 | 显示全部楼层
子任务是轮询,不会打断,单个长时间任务最好通过状态机进行任务分割

出0入0汤圆

发表于 2019-11-29 10:11:08 | 显示全部楼层
简单程序的用状态机机制就可以

出0入0汤圆

发表于 2019-11-29 10:23:19 | 显示全部楼层
这个就是轮询任务函数,坛子里其他调度器

出0入0汤圆

发表于 2019-11-29 10:30:47 | 显示全部楼层
不错,有点像“时间触发嵌入式系统......”

出235入222汤圆

发表于 2019-11-29 14:20:55 | 显示全部楼层
收藏,谢谢楼主分享

出0入8汤圆

发表于 2019-11-29 18:37:39 来自手机 | 显示全部楼层
加回调,可以在中断中运行

出0入0汤圆

发表于 2019-11-30 08:50:37 | 显示全部楼层
收藏,谢谢楼主分享

出0入0汤圆

发表于 2019-11-30 08:54:17 | 显示全部楼层
赞楼主开源!

出0入0汤圆

发表于 2019-11-30 14:20:21 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2019-11-30 18:04:11 | 显示全部楼层
短小精悍

出0入0汤圆

发表于 2019-11-30 20:11:43 | 显示全部楼层
好精简啊!

出0入134汤圆

发表于 2019-11-30 22:29:01 | 显示全部楼层
短小精悍,收藏研究下

出0入0汤圆

发表于 2019-11-30 22:34:01 | 显示全部楼层
感谢开源

出0入0汤圆

发表于 2019-12-1 07:41:30 | 显示全部楼层
不错、不错,看来还是有一堆人没玩过 OS 啊!呵呵~

出0入0汤圆

发表于 2019-12-1 09:15:03 | 显示全部楼层

赞楼主开源!

出0入0汤圆

发表于 2019-12-2 22:13:45 | 显示全部楼层
kinsno 发表于 2019-11-28 22:47
提2个意见:
1. z_bind和z_start好象重复了,好象前者已经暗含后者的功能了,
2. 看注释 z_bind可以决定功 ...

z_bind没有运行次数的限定,repeat作为时间在用。只能手动修改en进行开启或者停止。

好像前面有说了,回调加入参数就更好了。其实与其说是时间调度,还不如说是软件定时器。

出0入0汤圆

发表于 2019-12-2 23:15:43 | 显示全部楼层
謝謝分享,有機會使用一下,但目前用的編譯器都不支持函數指針,咋整?

出0入137汤圆

 楼主| 发表于 2019-12-2 23:22:19 | 显示全部楼层
lzm2010 发表于 2019-12-2 23:15
謝謝分享,有機會使用一下,但目前用的編譯器都不支持函數指針,咋整? ...

不是吧, 什么编译器? 符合ansi标准的c编译器就应该支持啊

出0入0汤圆

发表于 2019-12-3 05:59:56 | 显示全部楼层
tomzbj 发表于 2019-12-2 23:22
不是吧, 什么编译器? 符合ansi标准的c编译器就应该支持啊

HOLTEK的編譯器不支持函數指針

出0入137汤圆

 楼主| 发表于 2019-12-3 08:19:45 | 显示全部楼层
lzm2010 发表于 2019-12-3 05:59
HOLTEK的編譯器不支持函數指針

标准库的qsort都用不了啊……

出0入0汤圆

发表于 2019-12-3 08:55:40 | 显示全部楼层
不错, 还蛮简单实用

出0入0汤圆

发表于 2019-12-3 11:06:40 | 显示全部楼层
STOP的时候是不是需要清一下计数器

出0入0汤圆

发表于 2019-12-3 14:06:14 | 显示全部楼层
学习,谢谢!!!!

出0入0汤圆

发表于 2019-12-3 15:14:28 | 显示全部楼层
hnlg 发表于 2019-11-28 22:56
假如任务超级费时的,怎么办?

估计只能用抢占式了

出0入0汤圆

发表于 2019-12-3 20:12:45 | 显示全部楼层
收下了,谢谢分享

出0入0汤圆

发表于 2019-12-4 16:10:10 | 显示全部楼层
hnlg 发表于 2019-11-28 22:56
假如任务超级费时的,怎么办?

任务超过时间的话问题不大,就是其他任务的执行的时间点会延后一点而已,但是如果有些任务的执行频率十分高的话,会出现部分轮空的情况。

出0入0汤圆

发表于 2019-12-4 16:12:32 | 显示全部楼层
程序还没有来的及看, 先研究了一下你的头像

出0入0汤圆

发表于 2021-1-7 14:02:59 | 显示全部楼层
这软件是不是有这样一个BUG,如果,1ms定时,连续运行超过50天,就运行不了了

出0入0汤圆

发表于 2021-1-7 14:11:30 | 显示全部楼层

收下了,谢谢分享

出0入0汤圆

发表于 2021-1-7 22:26:48 | 显示全部楼层
本帖最后由 chinaboy25 于 2021-1-8 00:27 编辑

修改一下,用到我工程上了
/*--------------------------------------------------------------------------*/
//
//
//
/*--------------------------------------------------------------------------*/
void sm_poll_loop(void)
{
        for(g.run_id = 0; g.run_id < g.num_tasks; g.run_id++){
                if(g.tick >= g.tasks[g.run_id].timeout) {
                        g.tasks[g.run_id].timeout = g.tick+ g.tasks[g.run_id].repeat;
                        if(g.tasks[g.run_id].en){
                                g.tasks[g.run_id].func();
                        }       
                }
        }
  
        if(g.tick&0x80000000){
                int i;
                for(i = 0; i < g.num_tasks; i++){
                        if(g.tasks.timeout >= g.tick){
                                g.tasks.timeout = g.tasks.repeat - (g.tasks.timeout - g.tick);
                        }else{
                                g.tasks.timeout = g.tasks.repeat;
                        }
                }
                g.tick = 0;
        }
}



/*--------------------------------------------------------------------------*/
//只能任务内运行,
//函数运行完后挂起设置时间后再次唤醒
//
//
/*--------------------------------------------------------------------------*/
void sm_suspend_me(unsigned long time)
{
                g.tasks[g.run_id].timeout = g.tick+ time;
}




出0入0汤圆

发表于 2021-1-14 09:04:23 | 显示全部楼层
感谢楼主分享,收藏。

出0入0汤圆

发表于 2021-1-14 10:29:08 来自手机 | 显示全部楼层
开源代码,支持分享

出0入0汤圆

发表于 2021-1-15 00:11:38 | 显示全部楼层
哪里进行了任务切换的现场保存和恢复操作 ?

出0入137汤圆

 楼主| 发表于 2021-1-15 10:22:20 | 显示全部楼层
qq335702318 发表于 2021-1-15 00:11
哪里进行了任务切换的现场保存和恢复操作 ?

不是操作系统, 不需要这些
调度器而已啊...

出0入0汤圆

发表于 2021-1-15 22:50:54 | 显示全部楼层
tomzbj 发表于 2021-1-15 10:22
不是操作系统, 不需要这些
调度器而已啊...

如果没有现场保护和恢复,就连"调度"都算不上吧
只能说是软件定时器

出0入0汤圆

发表于 2021-1-16 06:01:58 | 显示全部楼层
学习,谢谢!!!!

出0入0汤圆

发表于 2021-2-27 10:45:45 | 显示全部楼层
谢谢,了

出0入0汤圆

发表于 2021-2-27 11:55:16 来自手机 | 显示全部楼层
建议加入带执行次数的api

出0入137汤圆

 楼主| 发表于 2021-2-27 16:39:02 | 显示全部楼层
Kengcc 发表于 2021-2-27 11:55
建议加入带执行次数的api

zt_bind的返回值是任务id, 可以把你需要计数执行的任务的id记录下来

任务函数里加个计数器, 计到次数了把自己stop了呗~

出0入0汤圆

发表于 2021-2-28 05:55:23 | 显示全部楼层
如果有一个极简单的无汇编代码的抢占式的就好了,就抢占功能

出0入17汤圆

发表于 2021-3-1 10:24:23 | 显示全部楼层
1) tick 溢出的处理
2)某个任务长时间运行怎么办

出0入137汤圆

 楼主| 发表于 2021-3-1 11:06:39 | 显示全部楼层
think_a_second 发表于 2021-3-1 10:24
1) tick 溢出的处理
2)某个任务长时间运行怎么办

tick溢出, 前面某个回复里似乎有人解决了
长时间运行这个得自己想办法避免, 这毕竟不是os
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 -- 东莞阿莫电子网站 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2022-11-30 07:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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