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

【开源】软件定时器

[复制链接]
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扩展软件包
关注我们
st-img 微信公众号
st-img 手机版