[代码分享]一个软件定时器模块,简单好用

2019-12-25 18:47发布

本帖最后由 Jmhh247 于 2015-11-10 19:43 编辑

关键字:软件定时器;soft timer; C语言;回调函数;菜单超时;定时应用;stm32


这两天气不好,今天下班后更是下起雨来,下得还不小……利用这段时间整理了一个我常用的软件定时器模块,分享出来,希望对大家有用,同时交流。

关于软件定时器,可能大家实现的代码形式不一样,但是觉得大家应该都是喜欢用的。用过的都知道它的好处是非常多的,用到的场景也很多,比如我常用的是菜单超时啊,
开机两秒后播放个提示音啊,啪啪啪的……用的多了就会想着写自己的模块以复用。


好了,说重点:

首先是功能描述:
略,想必大家都很清楚了。


接着是模块使用:
zl_soft_timer模块.zip (9.47 KB, 下载次数: 138) 2015-11-10 18:45 上传 点击文件名下载附件
模块

模块包含多个文件,解压后你就会发现……其实精简的话,只要一个zl_soft_timer.c 文件和一个zl_soft_timer.h 文件就够了,只不过我写得比较啰嗦……不过表担心,随后我
会给出一个 stm32 平台下的 demo 供参考。


模块的接口函数有五个如下,初始化,用户设置,循环服务等……
  1. /* Exported functions ------------------------------------------------------- */
  2. void zl_soft_timer_set(uint8_t chTimerNum, uint32_t wTime, zlfn_st_t fn_call_back);
  3. void zl_soft_timer_kill(uint8_t chTimerNum);
  4. void zl_soft_timer_init(void);
  5. void zl_soft_timer_loop(void);
  6. void zl_soft_timer_service(void);
复制代码

模块的使用很简单,首先把模块文件添加到你的工程中,然后调用接口函数即可……关于接口调用,还是有一些要求的,但也很简单的。要注意的就是三个固定接口函数的调用
位置,如下:
首先调用的就是初始化了,都懂的
  1.     zl_soft_timer_init();
复制代码

其次是
  1.     zl_soft_timer_loop();         
复制代码
这个接口函数必须是在时标中断(心跳)里调用,定时器嘛毕竟是需要时基的。对了,说到时基,这是和定时器时间有关的,都懂的,我的习惯是 1ms……另外,我的编程风
格自己都觉得奇怪,凡是函数名带 loop 的基本都是运行在时标中断里的……凡是带 service 的基本都是运行在超级循环里的……

所以接下来这个接口函数是要放在超级循环里调用的
  1.         zl_soft_timer_service();
复制代码


完成上面三个接口函数的正常调用后,就可以通过配置函数使用软件定时器了

先说下配置定时器函数的使用,它有三个参数,具体见注释
  1. /*   Z L _ S O F T _ T I M E R _ S E T   */
  2. /*-------------------------------------------------------------------------
  3.     * 功能:设置一个定时器。
  4.     * 参数:1.定时器编号,0 至 ZL_SOFT_TIMER_MAX_NUM;
  5.     *       2.定时时间;
  6.     *       3.回调函数。
  7.     * 返回:无
  8.     * 备注:OK.
  9. -------------------------------------------------------------------------*/
  10. void zl_soft_timer_set(uint8_t chTimerNum, uint32_t wTime, zlfn_st_t fn_call_back)
  11. {
  12.     if (!s_wSoftTimerInitOK)
  13.     {
  14.         return;
  15.     }

  16.     if (chTimerNum >= ZL_SOFT_TIMER_MAX_NUM)
  17.     {
  18.         return;                                 /* 超出定时器数量,直接退出 */
  19.     }

  20.     if (0 == wTime)
  21.     {
  22.         return;                                 /* 定时时间为 0 ,直接退出 */
  23.     }


  24.     zl_enter_critical();

  25.     s_tSoftTimer[chTimerNum].wTimer = wTime;

  26.     if (NULL == fn_call_back)
  27.     {
  28.         s_tSoftTimer[chTimerNum].fn_call_back = zl_dummy_func_soft_timer;
  29.     }
  30.     else
  31.     {
  32.         s_tSoftTimer[chTimerNum].fn_call_back = fn_call_back;
  33.     }

  34.     s_tSoftTimer[chTimerNum].hwCtrl = STIMER_START;

  35.     zl_exit_critical();

  36. }
复制代码

然后是解除定时器的函数,软件定时器的使用一般是执行一次就自动解除的,这个函数用的会比较少,看需求吧
  1. /*   Z L _ S O F T _ T I M E R _ K I L L   */
  2. /*-------------------------------------------------------------------------
  3.     * 功能:停止指定编号的定时器。
  4.     * 参数:1.定时器编号 0 至 ZL_SOFT_TIMER_MAX_NUM。
  5.     * 返回:无
  6.     * 备注:OK.
  7. -------------------------------------------------------------------------*/
  8. void zl_soft_timer_kill(uint8_t chTimerNum)
  9. {
  10.     if (!s_wSoftTimerInitOK)
  11.     {
  12.         return;
  13.     }

  14.     if (chTimerNum >= ZL_SOFT_TIMER_MAX_NUM)
  15.     {
  16.         return;                                 /* 超出定时器数量,直接退出 */
  17.     }

  18.     zl_enter_critical();

  19.     s_tSoftTimer[chTimerNum].hwCtrl = STIMER_STOP;

  20.     zl_exit_critical();
  21. }
复制代码


接下来给出两个例子

例子1, 是软件定时器用最多的用法,只执行一次回调函数就自动解除了
先是配置软件定时器
  1.     /* 软件定时器测试 */
  2.     zl_soft_timer_set(0, 3000, st_start_play_audio);    /* 开机3秒后播放提示音 */
复制代码

然后是回调函数的原型这样的,这里只是串口输出来模拟一个功能的实现
  1. void st_start_play_audio(void)
  2. {
  3.     zl_printf_string(" start play audio! ");
  4. }
复制代码

例子2,说真的,好饿,我不想写了,我得去吃饭了……这是个能周期运行的
  1.     zl_soft_timer_set(1, 5000, st_soft_timer_test);     /* 5秒输出一次串口数据 */
  2.     zl_soft_timer_set(2, 500, st_led_flash);            /* 500ms 取反一次LED状态 */
复制代码

重点是函数原型,是这样的
  1. void st_soft_timer_test(void)
  2. {
  3.     static uint32_t s_wCnt = 0;


  4.     s_wCnt++;
  5.     zl_printf(" soft timer cnt: %d ", s_wCnt);

  6.     zl_soft_timer_set(1, 5000, st_soft_timer_test);
  7. }
复制代码
  1. void st_led_flash(void)
  2. {
  3.     static uint32_t s_wFlashFlag = 0;


  4.     if (s_wFlashFlag)
  5.     {
  6.         bsp_led_ctrl(LED_STA_OFF, LED_Pin_1);
  7.         s_wFlashFlag = 0;
  8.     }
  9.     else
  10.     {
  11.         bsp_led_ctrl(LED_STA_ON, LED_Pin_1);
  12.         s_wFlashFlag = 1;
  13.     }

  14.     zl_soft_timer_set(2, 500, st_led_flash);
  15. }
复制代码

真的是好饿,不写了,有问题欢迎交流,附件里有一个整理干净的 demo, 其实里面还有一些其它的东西,可以无视,我得去吃饭了 ……

zl_soft_timer_demo.zip (777 KB, 下载次数: 212) 2015-11-10 18:46 上传 点击文件名下载附件
demo
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
56条回答
Jmhh247
2019-12-27 04:40
kinsno 发表于 2015-11-11 08:20
我想对楼主说,我更喜欢的是你那个_printf,这个文件,请问经过时间的考验了吗?  一直想找个非官方的; ...

哈哈,我也不喜欢官方的,所以才有了现在这个 zl_printf 模块……官方的占很多空间,还有些其它
方面让人难以接受。

关于这个模块,我对它的定性只是调试用的,一直没发现问题,串口输出可是调试必备啊……反正
我觉得调试用的话是足够了,你要用作其它方面,我不能保证,得需要你自己测试啦!

另外,需要说明的是这个 zl_printf 的功能是没有官方库强大的,这个模块也不是完全由我自己编写
的,有参考网上的代码,只是我做了一些优化,让它更符合我自己的调试需求。

一周热门 更多>