搜索
bottom↓
回复: 55

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

  [复制链接]

出0入8汤圆

发表于 2015-11-10 19:43:54 | 显示全部楼层 |阅读模式
本帖最后由 Jmhh247 于 2015-11-10 19:43 编辑

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


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

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


好了,说重点:

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


接着是模块使用:

模块包含多个文件,解压后你就会发现……其实精简的话,只要一个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("\r\n start play audio!\r\n");
  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("\r\n soft timer cnt: %d \r\n", 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, 其实里面还有一些其它的东西,可以无视,我得去吃饭了 ……

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2015-11-10 20:14:38 | 显示全部楼层
非常感谢分享!!!

出0入76汤圆

发表于 2015-11-10 20:29:34 | 显示全部楼层
不错, 看过楼主的帖子, 都是比较用心的, 强烈支持...

出0入0汤圆

发表于 2015-11-10 20:36:00 | 显示全部楼层
楼主的代码好看 赞!

出0入0汤圆

发表于 2015-11-10 21:48:37 | 显示全部楼层
楼主代码写得漂亮!
安富莱代码的软件定时器也不错!

出0入0汤圆

发表于 2015-11-10 22:59:57 | 显示全部楼层
是用Keil 5.0写的? 我的打不开!

出100入85汤圆

发表于 2015-11-11 07:28:59 来自手机 | 显示全部楼层
谢谢分享。不过要能加上定时器暂停和继续就更好了。

出0入0汤圆

发表于 2015-11-11 07:57:43 | 显示全部楼层
谢谢分享,看看

出10入10汤圆

发表于 2015-11-11 08:08:53 | 显示全部楼层
层次分明,学习了

出0入0汤圆

发表于 2015-11-11 08:20:59 | 显示全部楼层
我想对楼主说,我更喜欢的是你那个_printf,这个文件,请问经过时间的考验了吗?  一直想找个非官方的;

出0入0汤圆

发表于 2015-11-11 08:27:47 | 显示全部楼层
多谢,很好的方式

出0入8汤圆

 楼主| 发表于 2015-11-11 11:14:49 | 显示全部楼层
kinsno 发表于 2015-11-11 08:20
我想对楼主说,我更喜欢的是你那个_printf,这个文件,请问经过时间的考验了吗?  一直想找个非官方的; ...

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

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

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

出0入8汤圆

 楼主| 发表于 2015-11-11 11:18:58 | 显示全部楼层
hongguan 发表于 2015-11-10 22:59
是用Keil 5.0写的? 我的打不开!

不好意思,确实是MDK5.0以上的版本……因为之前的5.0以下的版本是不支持 stm32f4 的,没办法,就只好升级了……

你也升下级好了,就是要花点时间

出0入0汤圆

发表于 2015-11-11 13:35:56 | 显示全部楼层
Jmhh247 发表于 2015-11-11 11:18
不好意思,确实是MDK5.0以上的版本……因为之前的5.0以下的版本是不支持 stm32f4 的,没办法,就只好升级 ...

没有吧,我一直用4.72A调试F407啊,毫无压力啊;

出0入8汤圆

 楼主| 发表于 2015-11-11 14:13:01 | 显示全部楼层
kinsno 发表于 2015-11-11 13:35
没有吧,我一直用4.72A调试F407啊,毫无压力啊;

啊啊,不会吧,我之前也是用4.72A的,不知道是什么情况,换成5.0后才能调 F4 的,可能是我人品有问题……

出0入8汤圆

 楼主| 发表于 2015-11-11 14:14:42 | 显示全部楼层
foxpro2005 发表于 2015-11-10 20:29
不错, 看过楼主的帖子, 都是比较用心的, 强烈支持...

谢谢支持!

出0入8汤圆

 楼主| 发表于 2015-11-11 14:16:40 | 显示全部楼层
Shaopus 发表于 2015-11-10 21:48
楼主代码写得漂亮!
安富莱代码的软件定时器也不错!

谢谢……我还没看过,等有时间在坛子里找找,学习下

出0入0汤圆

发表于 2015-11-11 14:38:23 | 显示全部楼层
“这两天气不好”=“这两天”|“天气不好”;楼主好语法

出0入8汤圆

 楼主| 发表于 2015-11-11 16:52:56 | 显示全部楼层
wangyy@dianzi 发表于 2015-11-11 14:38
“这两天气不好”=“这两天”|“天气不好”;楼主好语法

你看的好仔细,这都被你发现了了了……

出0入0汤圆

发表于 2015-11-12 10:10:30 | 显示全部楼层
先收藏一下

出0入0汤圆

发表于 2015-11-12 13:42:04 来自手机 | 显示全部楼层
兄弟,不错!推荐000939给你。自己关注一下。

出0入0汤圆

发表于 2015-11-12 13:53:52 | 显示全部楼层
很好的资料,感谢楼主分享

出0入0汤圆

发表于 2015-11-12 14:42:47 | 显示全部楼层
想问下楼主,如果是闪烁时间不同,比如亮500ms灭300ms
if (s_wFlashFlag)
    {
        bsp_led_ctrl(LED_STA_OFF, LED_Pin_1);
        s_wFlashFlag = 0;
        zl_soft_timer_set(2, 300, st_led_flash);
    }
    else
    {
        bsp_led_ctrl(LED_STA_ON, LED_Pin_1);
        s_wFlashFlag = 1;
       zl_soft_timer_set(2, 500, st_led_flash);
    }
是这样处理么?
还有如果需要定时3s后开始闪动3下再定时2s不运行该如何处理的?

出0入8汤圆

 楼主| 发表于 2015-11-12 16:49:05 | 显示全部楼层
whatcanitbe 发表于 2015-11-11 07:28
谢谢分享。不过要能加上定时器暂停和继续就更好了。

这个功能确实没有,因为我自己没这样的需求……

实现起来应该还是很简单的,你可以自己改下源码。

出0入8汤圆

 楼主| 发表于 2015-11-12 16:54:28 | 显示全部楼层
lzly0302 发表于 2015-11-12 14:42
想问下楼主,如果是闪烁时间不同,比如亮500ms灭300ms
if (s_wFlashFlag)
    {

你说的问题,我一时有点反应不过来啊

建议你看下我之前发的贴子,是一个 LED 模块,下面是链接:
[代码分享]一个LED状态模块,支持亮、灭时间和闪烁次数设定

你先看看能不能满足需求,有问题再交流哈

出0入8汤圆

 楼主| 发表于 2015-11-12 16:58:58 | 显示全部楼层
wangyan915205 发表于 2015-11-12 13:42
兄弟,不错!推荐000939给你。自己关注一下。

哈哈,谢谢大神啊,刚看了下K线,走的不错啊,等有机会买几手玩玩,赚个电路板的打样钱

出0入0汤圆

发表于 2015-11-12 22:06:40 | 显示全部楼层
只要出好贴,我就给你推荐好票票。

出0入0汤圆

发表于 2015-11-12 22:10:08 | 显示全部楼层
只要出好贴,我就给你推荐好票票。

出0入0汤圆

发表于 2015-11-12 22:11:05 | 显示全部楼层
只要出好贴,我就给你推荐好票票。

出0入8汤圆

 楼主| 发表于 2015-11-13 08:49:01 | 显示全部楼层

出0入8汤圆

 楼主| 发表于 2015-11-13 08:49:24 | 显示全部楼层
ziho2005 发表于 2015-11-10 20:36
楼主的代码好看 赞!

出0入8汤圆

 楼主| 发表于 2015-11-13 08:50:33 | 显示全部楼层
wangyan915205 发表于 2015-11-12 22:11
只要出好贴,我就给你推荐好票票。

哈哈,好的,我争取

出0入8汤圆

 楼主| 发表于 2015-11-13 08:51:13 | 显示全部楼层
szxszx 发表于 2015-11-11 08:08
层次分明,学习了

出0入0汤圆

发表于 2015-11-13 13:43:12 | 显示全部楼层
Shaopus 发表于 2015-11-10 21:48
楼主代码写得漂亮!
安富莱代码的软件定时器也不错!

一直用安富莱的SoftTimer,并且添加了回调函数,功能大大增强。

出0入0汤圆

发表于 2015-11-13 13:46:08 | 显示全部楼层
heimareed 发表于 2015-11-13 13:43
一直用安富莱的SoftTimer,并且添加了回调函数,功能大大增强。

分享下你的啊!

出0入0汤圆

发表于 2015-11-13 17:40:33 | 显示全部楼层
非常感谢分享!!!

出0入8汤圆

 楼主| 发表于 2015-11-13 17:47:43 | 显示全部楼层

共同学习!

出0入0汤圆

发表于 2015-11-13 17:51:05 | 显示全部楼层
好贴,顶楼主!!!

出0入0汤圆

发表于 2015-11-13 18:43:42 | 显示全部楼层
mark                  

出0入0汤圆

发表于 2015-11-13 18:47:03 | 显示全部楼层
先顶了,再慢慢看!

出0入4汤圆

发表于 2015-11-13 20:15:11 | 显示全部楼层
谢谢楼主的分享!下载下来学习一下

出0入0汤圆

发表于 2015-11-13 20:28:57 | 显示全部楼层
简单看了一些,比ucos软件定时器效率低。。。。

出0入0汤圆

发表于 2015-11-13 20:57:43 来自手机 | 显示全部楼层
Shaopus 发表于 2015-11-10 21:48
楼主代码写得漂亮!
安富莱代码的软件定时器也不错!

上传安富莱的来看看。

出0入0汤圆

发表于 2015-11-13 21:00:46 来自手机 | 显示全部楼层
Jmhh247 发表于 2015-11-11 14:14
谢谢支持!

回调函数如果能实现传递参数就更方便了

出0入0汤圆

发表于 2015-11-13 21:14:21 | 显示全部楼层

    很好!         

出0入8汤圆

 楼主| 发表于 2015-11-14 19:33:31 | 显示全部楼层
STM32LOU 发表于 2015-11-13 20:28
简单看了一些,比ucos软件定时器效率低。。。。

没那功力……

出0入8汤圆

 楼主| 发表于 2015-11-14 19:34:00 | 显示全部楼层
soos 发表于 2015-11-13 21:00
回调函数如果能实现传递参数就更方便了

不懂,参数有什么用……

出0入8汤圆

 楼主| 发表于 2015-11-14 19:34:40 | 显示全部楼层

出0入0汤圆

发表于 2015-11-14 20:27:22 | 显示全部楼层
mark.thanks!

出0入0汤圆

发表于 2017-5-8 09:40:47 | 显示全部楼层
时间片的轮休!!!!

出0入0汤圆

发表于 2017-5-9 18:32:22 来自手机 | 显示全部楼层
记号!有空再看!

出0入0汤圆

发表于 2017-8-22 17:05:34 | 显示全部楼层
临界区里面的这个s_wState是干嘛的

出0入8汤圆

 楼主| 发表于 2017-8-23 09:03:49 | 显示全部楼层
gujiamao_love 发表于 2017-8-22 17:05
临界区里面的这个s_wState是干嘛的

好尴尬,我没找到 s_wState 在哪出现过?

出0入0汤圆

发表于 2017-8-23 11:23:50 | 显示全部楼层
Jmhh247 发表于 2017-8-23 09:03
好尴尬,我没找到 s_wState 在哪出现过?

在ZYSlib\zlib_critical.c的zl_enter_critical这个函数里面

出0入8汤圆

 楼主| 发表于 2017-8-23 11:42:24 | 显示全部楼层
gujiamao_love 发表于 2017-8-23 11:23
在ZYSlib\zlib_critical.c的zl_enter_critical这个函数里面

哦哦,我以为是在软件定时器模块里

那个是为了保存当前全局中断状态啊


进临界区,先保存状态,然后关中断

离开临界区后,根据保存的状态恢复中断

出0入0汤圆

发表于 2017-8-23 14:36:47 | 显示全部楼层
Jmhh247 发表于 2017-8-23 11:42
哦哦,我以为是在软件定时器模块里

那个是为了保存当前全局中断状态啊


谢谢!从来没有这么做过...
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-24 06:18

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

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