搜索

自创flow库,让你写代码的时候像flow(流水)一样丝滑

[复制链接]
203|5
 楼主 | 2021-1-11 22:13 | 显示全部楼层 |阅读模式
本帖最后由 791314247 于 2021-1-12 09:43 编辑

#技术资源# #每日话题# #有奖活动# #申请原创#

flow_lib

一,介绍:
适用于嵌入式单片机的裸机程序微库,只占用你的rom 6个字节,是的,6个字节。颠覆式的设计思维,让你写代码的时候像flow(流水)一样丝滑,让你永远不用在为delay时cpu空转而烦恼,附加的超轻便的软件定时器让你轻松实现各种定时需求,另还有信号量的配方,让你任务间的同步像诗一样写意,并且能让你裸机程序效率提升百倍以上。


你的start就是对我最大的支持,谢谢。
Gitee开源:https://gitee.com/qq791314247/flow_lib
Github开源:https://github.com/791314247/flow_lib
CSDN博客:https://blog.csdn.net/qq_35333978/article/details/112428159

二,移植说明:
移植特别简单,flow_def.h有一个全局变量:
  1. extern unsigned long flow_tick;
复制代码

把这个变量放在你的某个硬件中断里去,这个硬件中断一定要是一直运行的,推荐RTC半秒中断,或者systick中断都可以。

然后在flow.h里的第一行有个宏
  1. #define FL_HARD_TICK        (500)                 /* 系统硬件中断一次所需要的时间,单位ms */
复制代码

把这里的值改成你的硬件中断一次所需的时间,单位是毫秒,比如你的flow_tick放在了一个500ms中断一次的rtc里,那么这里的宏FL_HARD_TICK的值就是500,具体中断设为多少取决于你的系统最短一次的延时的时间。

假如我的最短延时需求是100ms,那么我就得给个100ms中断一次的硬件中断源,宏FL_HARD_TICK的值就是100,我就可以这样使用:
  1. FL_LOCK_DELAY(fl, FL_CLOCK_SEC /10);
复制代码
来延时100ms。

三,使用说明:
核心文件时flow.h,看这里的注释基本就会使用大部分功能。


  1. /*
  2. * Copyright (c) 2006-2018
  3. *
  4. * SPDX-License-Identifier:
  5. *
  6. * Change Logs:
  7. * Date           Author       Notes
  8. * 2020           wangrui
  9. */

  10. #ifndef __FLOW_
  11. #define __FLOW_

  12. #include <flow_def.h>
  13. #include <flow_core.h>
  14. #include <flow_sem.h>

  15. #define FL_HARD_TICK        (500)                 /* 系统硬件中断一次所需要的时间,单位ms */
  16. #define FL_CLOCK_SEC        (1000/FL_HARD_TICK)   /* 一秒钟需要的tick,可以除也可以自行添加其它宏 */

  17. /**
  18. * 初始化一个flow进程
  19. */
  20. #define FL_INIT(fl)                                     FLOW_INIT(fl)

  21. /**
  22. * flow头,必须放在函数内的最前面
  23. */
  24. #define FL_HEAD(fl)                                     FLOW_HEAD(fl)

  25. /**
  26. * flow尾,必须放在函数内的最后面
  27. */
  28. #define FL_TAIL(fl)                                     FLOW_TAIL(fl)

  29. /**
  30. * 给进程加锁,直到judge为真,加锁期间一直放开cpu给其他进程使用
  31. */
  32. #define FL_LOCK_WAIT(fl, judge)                         FLOW_LOCK_WAIT(fl, judge)

  33. /**
  34. * 如果judge为真,就一直给进程加锁,加锁期间一直放开cpu给其他进程使用
  35. */
  36. #define FL_LOCK_WHILE(fl, judge)                        FLOW_LOCK_WHILE(fl, judge)

  37. /**
  38. * 退出该进程
  39. */
  40. #define FL_EXIT(fl)                                     FLOW_EXIT(fl)

  41. /**
  42. * 无条件锁住进程一次,下次进来再接着往下运行
  43. */
  44. #define FL_LOCK_ONCE(fl)                                FLOW_LOCK_ONCE(fl)

  45. /**
  46. * 等待一个flow进程结束
  47. */
  48. #define FL_WAIT_PROCESS_END(fl, process)                FLOW_WAIT_PROCESS_END(fl, process)

  49. /**
  50. * 等待一个flow子进程结束
  51. */
  52. #define FL_WAIT_CHILD(fl, cfl, process)                 FLOW_WAIT_CHILD_PROCESS_END(fl, cfl, process)

  53. /**
  54. * 给进程加锁,时长为time,加锁期间一直放开cpu给其他进程使用,time如果用FL_CLOCK_SEC来乘,那么time的单位就是s
  55. * 此处time必须是常数
  56. */
  57. #define FL_LOCK_DELAY(fl,time)                          FLOW_LOCK_DELAY(fl,time)

  58. /**
  59. * 给进程加锁,时长为time,延时期间如果judge为真,就直接解锁进程
  60. * 此处time必须是常数
  61. */
  62. #define FL_LOCK_DELAY_OR_WAIT(fl,judge,time)            FLOW_LOCK_DELAY_OR_WAIT(fl,judge,time)

  63. /**
  64. * 初始化一个信号量
  65. */
  66. #define FL_SEM_INIT(sem, count)                         FLOW_SEM_INIT(sem, count)

  67. /**
  68. * 给进程加锁,直到有信号释放
  69. */
  70. #define FL_LOCK_WAIT_SEM(f, sem)                        FLOW_LOCK_WAIT_SEM(f, sem)

  71. /**
  72. * 给进程加锁,直到有信号或者超时,此处time可以为变量,其他的接口处time必须是常数
  73. */
  74. #define FL_LOCK_WAIT_SEM_OR_TIMEOUT(fl, sem, time)      FLOW_LOCK_WAIT_SEM_OR_TIMEOUT(fl, sem, time)

  75. /**
  76. * 释放一个信号量
  77. */
  78. #define FL_SEM_RELEASE(sem)                             FLOW_SEM_RELEASE(sem)

  79. /**
  80. * 初始化一个软件定时器
  81. */
  82. void fl_timer_set(struct flow_timer *t, unsigned long interval);

  83. /**
  84. * 复位一个软件定时器
  85. */
  86. void fl_timer_reset(struct flow_timer *t);

  87. /**
  88. * 重启一个软件定时器
  89. */
  90. void fl_timer_restart(struct flow_timer *t);

  91. /**
  92. * 检测一个软件定时器是否超时,0为不超时,1为超时
  93. */
  94. char fl_timer_timeout(struct flow_timer *t);

  95. /**
  96. * 检测一个软件定时器还剩多少时间超时,单位为硬件tick,比如硬件tick 500ms中断一次,那么
  97. * 返回的时间单位就是500ms
  98. */
  99. unsigned long fl_hour_much_time(struct flow_timer *t);

  100. #endif /* __FLOW_ */
复制代码
简单举个例子,先从需求说起,假如说你现在需要一个函数,这个函数的功能是每隔1s让你的led亮一次,正常设计的要么起个软件定时器或者硬件定时器,甚至状态机可以实现需求,但是都太low了,让我们看一下如何用flow库来实现这个函数。

该函数格式如下:
  1. char led_flash(struct flow *fl)
  2. {}
复制代码
其中char、struct flow *fl是必备的。

再来看看函数里面的内容格式:
  1. char led_flash(struct flow *fl)
  2. {
  3.     FL_HEAD(fl);
  4.     FL_TAIL(fl);
  5. }
复制代码
函数里面的FL_HEAD和FL_TAIL是使用flow库的所必须的宏,FL_HEAD(fl)放到函数的最前面,如果你的函数内部有变量定义的话放在变量定义的后面。而FL_TAIL(fl)是放在函数最后面一行的。

基本格式有了,再来看下如何实现延时一秒呢?其实只用一个语句就OK。
  1. char led_flash(struct flow *fl)
  2. {
  3.     FL_HEAD(fl);
  4.     FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  5.     led_open();
  6.     FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  7.     led_close();
  8.     FL_TAIL(fl);
  9. }
复制代码
是的,你没看错,仅仅只需要FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1)这一个语句就OK,当执行到这个语句的时候该函数就会让出CPU权限,当延时时间到了之后,就会回来接着执行FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1)下面的语句。一直到FL_TAIL(fl),该函数就会结束任务,再也不会执行了,那么如果我们想让它一直循环执行呢?看下面:
  1. char led_flash(struct flow *fl)
  2. {
  3.     FL_HEAD(fl);
  4.     while(1)
  5.     {
  6.         FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  7.         led_open();
  8.         FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  9.         led_close();
  10.     }
  11.     FL_TAIL(fl);
  12. }
复制代码

看起来像不像个进程?其实也有点操作系统的样子了。。。

光有这个函数也不行,还得进行一些额外的操作

比如:

  1. static struct flow fl_led; /* 1,定义一个struct flow变量给这个函数使用 */

  2. static char led_flash(struct flow *fl)
  3. {
  4.     FL_HEAD(fl);
  5.     /* 这里还能解决你的初始化问题,这里的函数只会在开机时或者说进程第一次进来时运行一次,以后将永远不会运行。注意:如果放在FL_HEAD(fl)前面,那么就是每次轮到这个进程运行的时侯就会运行一次,总之很灵活 */
  6.     led_init();
  7.     while(1)
  8.     {
  9.         FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  10.         led_open();
  11.         FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
  12.         led_close();
  13.     }
  14.     FL_TAIL(fl);
  15. }

  16. int main(void)
  17. {
  18.     FL_INIT(&fl_led);  /* 2,初始化struct flow变量 */
  19.     while(1)
  20.     {
  21.         led_flash(&fl_led); /* 3,把led_flash进程放在main函数的while循环里 */
  22.         ...
  23.     }
  24.     return 0;
  25. }
复制代码


经过以上3步,就可以实现进程之间的切换啦。然后想根据某个条件来锁住线程释放CPU的话,可以把里面的
  1. FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
复制代码
换成
  1. FL_LOCK_WAIT(fl, judge);
复制代码
当里面的judge为假时线程就一直锁住在这一行语句,当judge为真时就可以往下执行啦。同理可以完成很多其他的神奇功能,让你的cpu再也不空转啦,具体请看flow.h文件。。。。






使用特权

评论回复
| 2021-1-11 22:29 | 显示全部楼层
哈哈,不错,支持一下。

使用特权

评论回复
| 2021-1-13 13:14 | 显示全部楼层
这个其实就是Protothreads的变种,我就在用自己定制的版本,这东西ROM空间和任务切换时间开销很小,不需要自己管理堆栈,不过很多时候变量要使用静态变量,导致RAM空间开销反而会稍稍增大,隔壁论坛几年前有个“小小调度器”,跟这个类似,

这小东西弄得好,可以玩出花来,定时器抢占、信号量、消息队列、任务重入等都可以实现,不比那些成熟的OS差,

使用特权

评论回复
 楼主 | 2021-1-13 13:48 | 显示全部楼层
manbo789 发表于 2021-1-13 13:14
这个其实就是Protothreads的变种,我就在用自己定制的版本,这东西ROM空间和任务切换时间开销很小,不需要 ...

是的,说的没错呢

使用特权

评论回复
| 2021-1-14 03:06 | 显示全部楼层
不错

使用特权

评论回复
| 2021-1-14 09:04 | 显示全部楼层
这个不错,学习下

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

关闭

热门推荐上一条 /6 下一条

在线客服 快速回复 返回顶部 返回列表