你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【开源】软件定时器

[复制链接]
Inc_brza 发布时间:2017-7-20 19:23
本帖最后由 Inc_brza 于 2017-7-20 19:25 编辑

前言:这里不谈RTOS,而是主要针对裸机开发,很多时候,我们发现硬件定时器是不够用的,于是乎,很多时候,
程序员都会利用一个硬件定时器来产生N个软件定时器,误差是肯定有的,但是误差范围是可接受的,这样,
就能解决了很多时候定时器不够用的场合。
当然,楼主也遇到这种时候,所以就临时写了个软件定时器。

主题:这个软甲定时器采用了数组+回调的机制,硬件定时器产生tick,而主循环中获取tick产生计数,计数到达之后
调用定时器对应的回调函数。其中包含删除,注册的功能。

数据结构
  1. typedef struct soft_timer {
  2.     uint32_t timer_count;      //定时器用的计数器
  3.     uint32_t time_out;           //阀值
  4.     void (*time_out_callback)(void *param); //回调函数
  5.     void *param; //回调函数参数
  6.     uint8_t timer_flag; //定时器属性标志
  7. }soft_timer_t;
复制代码
原理很简单,主循环timer_count不断的自减,到0的时候就调用一次函数,不停循环。
  1. <blockquote>/*
复制代码
以上是使用到的api接口,分别是注册,删除,初始化,中断调用,主循环任务函数,
一下是源码:
  1. /*
  2. * !brief include header
  3. */
  4. #include <stdint.h>
  5. #include "soft_timer.h"


  6. #ifndef NULL
  7. #define NULL ((void *)0)
  8. #endif



  9. /*
  10. * !brief
  11. */
  12. static uint8_t exec_run_flag;

  13. /*
  14. * !brief timer_list, you can change the timers num by SOFT_TIMERS_MAX
  15. */
  16. static soft_timer_t timer_list[SOFT_TIMERS_MAX];

  17. /*
  18. * !brief module init, you can run this function in first main
  19. */
  20. void soft_timer_init(void)
  21. {
  22.     uint8_t i;
  23.     for (i = 0; i < SOFT_TIMERS_MAX; i++) {
  24.         timer_list[i].timer_count = 0;
  25.         timer_list[i].timer_flag = 0;
  26.         timer_list[i].time_out = 0;
  27.         timer_list[i].time_out_callback = NULL;
  28.         timer_list[i].param = NULL;
  29.     }
  30. }

  31. /*
  32. * !brief use this function to create a soft_timer
  33. * !param first time the timer count machine's period
  34. * !param every loop cycles
  35. * !param callback run with the time up
  36. * !param callback 's param
  37. * !param 0:periods 1:one shot
  38. * !retval timer handle
  39. */
  40. soft_timer_handle_t soft_timer_registered(uint32_t first_timer_period,
  41.                                           uint32_t period,
  42.                                           timer_out_callback *callback,
  43.                                           void *callback_param,
  44.                                           uint8_t flag)
  45. {
  46.     uint8_t i;
  47.    
  48.     if (callback == NULL) return NULL;
  49.    
  50.     for (i = 0; i < SOFT_TIMERS_MAX; i++) {
  51.         if (timer_list[i].time_out_callback != NULL) continue;
  52.         timer_list[i].timer_count = first_timer_period;
  53.         timer_list[i].time_out = period;
  54.         timer_list[i].time_out_callback = callback;
  55.         timer_list[i].param = callback_param;
  56.         timer_list[i].timer_flag = flag;
  57.         break;
  58.     }
  59.    
  60.     return (soft_timer_handle_t)&timer_list[i];
  61. }

  62. /*
  63. * !brief you can use this function to delete a soft_timer
  64. * !param timer handle
  65. * !retval 0 is successful, 1 is fail
  66. */
  67. int soft_timer_delete(soft_timer_handle_t handle)
  68. {
  69.     soft_timer_t *p = (soft_timer_t *)handle;
  70.    
  71.    
  72.     if (p == NULL) return 1;
  73.     p->time_out_callback = NULL;
  74.    
  75.     return 0;
  76. }

  77. /*
  78. * !brief you should run this function in a hardware timer interrupt
  79. *        it can provide ticks for soft_timer
  80. */
  81. void soft_timer_interrupt(void)
  82. {
  83.     if (exec_run_flag < 100)
  84.         exec_run_flag ++;
  85. }

  86. /*
  87. * !brief you should run this function in main loop
  88. */
  89. void soft_timer_exec(void)
  90. {
  91.     uint8_t i;
  92.    
  93.     if (exec_run_flag == 0) return;
  94.     exec_run_flag --;
  95.     for (i = 0; i < SOFT_TIMERS_MAX; i ++) {
  96.         if (timer_list[i].time_out_callback == NULL) continue;
  97.         if (timer_list[i].timer_count) {
  98.             timer_list[i].timer_count --;
  99.         } else {
  100.             timer_list[i].time_out_callback(timer_list[i].param);
  101.             if (!timer_list[i].timer_flag) {
  102.                 timer_list[i].timer_count = timer_list[i].time_out;
  103.             } else {    //one shot
  104.                 timer_list[i].time_out_callback = NULL;
  105.             }
  106.         }
  107.     }
  108. }
复制代码
总结,虽然误差是肯定有的,但是由于误差可接受,所以用起来还是很方便的,如果哪里写的不好,还请给点意见!

评分

参与人数 1 ST金币 -1 收起 理由
wxl0704010220-3 -1 神马都是浮云

查看全部评分

收藏 7 评论14 发布时间:2017-7-20 19:23

举报

14个回答
斜阳__ 回答时间:2017-7-20 19:54:15
谢谢分享         
creep 回答时间:2017-7-20 21:26:40
感谢分享!
LB_yjy 回答时间:2017-7-21 08:30:55
标记收藏!
MrJiu 回答时间:2017-7-21 10:16:18
总体来说就是时间片!!!!当然了也相当于一个调度系统。。。。只是这里的打断要自己主动让出MCU!!!
Inc_brza 回答时间:2017-7-21 10:38:21
MrJiu 发表于 2017-7-21 10:16
总体来说就是时间片!!!!当然了也相当于一个调度系统。。。。只是这里的打断要自己主动让出MCU!!!; ...

定时器的中断周期一般是1ms,也就是这个软件定时器的误差是毫秒级的,中断的处理很短基本可以忽略,主要其他任务不阻塞,还是很准确的。
Dandjinh 回答时间:2017-7-21 12:09:28
把count--换成直接对比比较好,count--需要读内存,减一,放回内存,比较四步,直接对比只需要读内存,比较两步。直接比较就是当前tick+定时tick而已
Inc_brza 回答时间:2017-7-21 12:27:06
Dandjinh 发表于 2017-7-21 12:09
把count--换成直接对比比较好,count--需要读内存,减一,放回内存,比较四步,直接对比只需要读内存,比较 ...

你的意思是把tick当成所有的计数器?如果这样子,定时器之间就不能相互独立了
Dandjinh 回答时间:2017-7-21 12:40:53
Inc_brza 发表于 2017-7-21 12:27
你的意思是把tick当成所有的计数器?如果这样子,定时器之间就不能相互独立了 ...

定义个全局tick,定时加一,作为标准,定时器触发的标准就是注册时的tick+period
SInzo 回答时间:2017-7-21 15:36:33
感谢分享!
12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版