[代码分享]一个简单好用的轮询延时器模块

2019-12-16 22:38发布

本帖最后由 Jmhh247 于 2017-5-23 10:08 编辑

关键字:延时器;非阻塞自由延时


在一些按键或其它形式的命令响应中,要求严格的话通常会需要队列缓存命令,以防丢失。

但是我通常还会遇到一些要求非常不严格的场景,这些场景甚至要限制响应的次数或频率(这里指不能响应太快)。
比如(只是个例子),我的产品是一个根据接收到的串口命令来工作的。串口命令发送的速度是不确定的,有时候1秒
会发送10帧命令过来,有的时候1秒确能发送100帧,但是这个产品每秒只打算处理20帧命令。而且由于命令有多个,
对于有些命令码可能每秒响应40帧或30帧等,这种场景用多个延时器就很合适了。


延时器模块的接口函数一共3个,如下:
  1. /* Exported functions ------------------------------------------------------- */
  2. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime);
  3. bool zl_poll_delay_timeout(uint8_t chUserId);
  4. void zl_poll_delay_tick(void);
复制代码

看下接口函数的实现,很简单的
  1. /*   Z L _ P O L L _ D E L A Y _ S E T   */
  2. /*-------------------------------------------------------------------------
  3. 功能描述  : 设定延时时间,同时启动延时。
  4. 输入参数  : uint8_t chUserId  延时器ID
  5.              uint16_t hwTime   延时时间
  6. 输出参数  : 无
  7. 返 回 值  :

  8. 修改历史      
  9.   1.日    期   : 2017年2月6日
  10.     作    者   : zys
  11.     修改内容   : 新生成函数,OK。

  12. -------------------------------------------------------------------------*/
  13. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
  14. {
  15.     if (chUserId >= ZL_POLL_DELAY_NUM) {
  16.         return false;
  17.     }

  18.     if (0 == hwTime) {
  19.         return false;
  20.     }

  21.     s_tPollBuf[chUserId].Time = hwTime;

  22.     return true;

  23. }


  24. /*   Z L _ P O L L _ D E L A Y _ T I M E O U T   */
  25. /*-------------------------------------------------------------------------
  26. 功能描述  : 查询给定ID的延时器是否超时。
  27. 输入参数  : uint8_t chUserId  
  28. 输出参数  : 无
  29. 返 回 值  : true 超时;false 未超时。

  30. 修改历史      
  31.   1.日    期   : 2017年5月22日
  32.     作    者   : zys
  33.     修改内容   : 新生成函数。

  34. -------------------------------------------------------------------------*/
  35. bool zl_poll_delay_timeout(uint8_t chUserId)
  36. {
  37.     if (chUserId >= ZL_POLL_DELAY_NUM) {
  38.         return false;
  39.     }

  40.     if ( !s_tPollBuf[chUserId].Time) {
  41.         return true;
  42.     }

  43.     return false;
  44. }


  45. /*   Z L _ P O L L _ D E L A Y _ T I C K   */
  46. /*-------------------------------------------------------------------------
  47. 功能描述  : 延时模块的驱动任务,在心跳中断里运行。
  48. 输入参数  : void  
  49. 输出参数  : 无
  50. 返 回 值  :

  51. 修改历史      
  52.   1.日    期   : 2017年5月22日
  53.     作    者   : zys
  54.     修改内容   : 新生成函数。

  55. -------------------------------------------------------------------------*/
  56. void zl_poll_delay_tick(void)
  57. {
  58.     uint8_t i;


  59.     for ( i = 0 ; i < ZL_POLL_DELAY_NUM; i++ ) {
  60.         if (s_tPollBuf[i].Time) {
  61.             s_tPollBuf[i].Time--;
  62.         }
  63.     }
  64. }
复制代码

模块的使用
使用很简单,首先把模块源文件添加到工程中,然后把
  1. void zl_poll_delay_tick(void)
复制代码
放到心跳中断里,我一般用1ms的心跳中断。


现在就能使用
  1. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
复制代码
来设置延时器了,入参分别是延时器的ID和延时时间,延时时间单位和心跳中断有关,看自己需求了。。。


然后用
  1. bool zl_poll_delay_timeout(uint8_t chUserId)
复制代码
来查询延时器是否超时,入参是要查询的延时器ID号。


延时器的可用最大数量通过宏定义配置
  1. /* 定义可用的延时数量 */
  2. #define ZL_POLL_DELAY_NUM   5
复制代码



模拟一个应用场景演示代码


  1. /* 定义延时器信息,便于阅读修改 */
  2. #define DELAY_ID0           0
  3. #define DELAY_TIME0         50

  4. #define DELAY_ID1           1
  5. #define DELAY_TIME1         900



  6. /* 模拟一个应用场景 */
  7. void xxx_cmd_process(uint8_t chCmd)
  8. {
  9.     switch (chCmd) {
  10.     case CMD_LEFT:

  11.         /* 该命令执行间隔不能小于50ms */
  12.         if (zl_poll_delay_timeout(DELAY_ID0)) {
  13.             zl_poll_delay_set(DELAY_ID0, DELAY_TIME0);

  14.             cmd_do_left();
  15.         }
  16.         break;

  17.     case CMD_RIGHT:

  18.         /* 该命令执行间隔不能小于900ms */
  19.         if (zl_poll_delay_timeout(DELAY_ID1)) {
  20.             zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);

  21.             cmd_do_left();
  22.         }
  23.         break;

  24.     case CMD_UP:

  25.         /* 该命令无限制,来就执行 */
  26.         cmd_do_up();
  27.         break;

  28.     case CMD_DOWN:
  29.         break;

  30.     default:
  31.         break;
  32.     }
  33. }


  34. /* 在1ms心跳(时基)中断里运行 */
  35. void st_systick_1ms_irq(void)
  36. {
  37.     zl_poll_delay_tick()
  38. }
复制代码


延时器的用处还有很多,可以灵活。。。

zlib poll delay模块源码.rar (2.02 KB, 下载次数: 108) 2017-5-23 10:07 上传 点击文件名下载附件

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
38条回答
Jmhh247
2019-12-18 19:39
miscell 发表于 2017-5-25 22:54
如果没启动,其计数值也为0,不是返回成功的吗

是的,就是这样设计的。因为上电后是第一次执行,所以有没有延时,结果都是一样的。

所以,在我写的用例中,都是先查询,超时后再设定延时的
  1. /* 该命令执行间隔不能小于900ms */
  2.         if (zl_poll_delay_timeout(DELAY_ID1)) {
  3.             zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);

  4.             cmd_do_left();
  5.         }
复制代码



一周热门 更多>