1、简介

这里先介绍下软件定时器和硬件定时器的区别

硬件定时器

CPU内部自带的定时器模块,通过初始化、配置可以实现定时,定时时间到以后就会执行相应的定时器中断处理函数。硬件定时器一般都带有其它功能,比如PWM输出、输入捕获等等功能。但是缺点是硬件定时器数量少!!

软件定时器

软件定时器允许设置一段时间,当设置的时间到达之后就执行指定的功能函数,被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了以后就会执行回调函数。

在FreeRTOS中有专门的软件定时器功能,我们可以在MCU中简单的是实现“软件定时器”如下:

void timer_1000ms(void)
{printf("timer_1000ms\r\n");
}
/*systick_ms在硬件定时器中每1ms加1*/
int main(void)
{static timer_tick = 0;timer_tick = systick_ms;while(){if((systick_ms-timer_tick)>1000){timer_tick = systick_ms;timer_1000ms();}}
}

这就是简单的软件定时器,是的,这就是特别简洁版本的软件定时器。当然它是有缺点的,比如systick_ms每1ms加1,所以软件定时器的精度是ms为单位的,并且如果while(1)中有其他代码阻塞,软件定时器也会跟着阻塞的。

这个简单的软件定时器毕竟很"简陋",大家可以自行封装丰富一下,或者参考已经有的开源方案:MultiTimer,一款可无限扩展的软件定时器。

MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。

开源地址:GitHub - 0x1abin/MultiTimer: Software timers extend module for embedded

2、MultiTimer

MultiTimer的设计比较简洁,只有2个文件,并且只有4个函数,总共82行代码,稍微花一点功夫就可以理解明白。

移植步骤

  • 配置系统时间基准接口,安装定时器驱动
uint64_t PlatformTicksGetFunc(void)
{/* Platform implementation */
}
MultiTimerInstall(PlatformTicksGetFunc);
  • 实例化一个定时器对象

MultiTimer timer1;
  • 设置定时时间,超时回调处理函数, 用户上下指针,启动定时器
int MultiTimerStart(&timer1, uint64_t timing, MultiTimerCallback_t callback, void* userData);
  • 在主循环调用定时器后台处理函数
int main(int argc, char *argv[])
{...while (1) {...MultiTimerYield();}
}

具体就不做手把手教程如何移植了,在STM32F207移植好的工程开源地址:

开源地址:STM32F207VCT6/23-Timer-MultiTimer at master · strongercjd/STM32F207VCT6 · GitHub

下面分析一下MultiTimer在移植的第一步,配置系统时间基准接口,安装定时器驱动

uint64_t PlatformTicksGetFunc(void)
{/* Platform implementation */
}
MultiTimerInstall(PlatformTicksGetFunc);

看一下MultiTimerInstall函数原型

typedef uint64_t (*PlatformTicksFunction_t)(void);
static PlatformTicksFunction_t platformTicksFunction = NULL;
int MultiTimerInstall(PlatformTicksFunction_t ticksFunc)
{platformTicksFunction = ticksFunc;return 0;
}

这其实就是函数指针实现的回调函数,具体详解看之前的文章《回调函数》,其实就是给MultiTimer提供一个计数器。

除去回调函数,该开源项目还是单链表的很好的示例,学习数据结构是比较乏味的,这个开源项目是单链表很好的应用落地,不太懂的同学可以学习下。

下面摘取一下部分代码

链表的删除

for (; *nextTimer; nextTimer = &(*nextTimer)->next) {if (timer == *nextTimer) {*nextTimer = timer->next; /* remove from list */break;}
}

插入链表

for (nextTimer = &timerList;; nextTimer = &(*nextTimer)->next) {if (!*nextTimer) {timer->next = NULL;*nextTimer = timer;break;}if (timer->deadline < (*nextTimer)->deadline) {timer->next = *nextTimer;*nextTimer = timer;break;}
}

遍历链表

MultiTimer* entry = timerList;
for (; entry; entry = entry->next) {/* Sorted list, just process with the front part. */if (platformTicksFunction() < entry->deadline) {return (int)(entry->deadline - platformTicksFunction());}/* remove expired timer from list */timerList = entry->next;/* call callback */if (entry->callback) {entry->callback(entry, entry->userData);}
}

这篇文章不会详细讲解链表的操作,不懂的同学可以看之前文章《链表在STM32中的应用》。

当然MultiTimer也是有缺点的,比如一个定时器是1000ms,另一个定时器是500ms,调度时就会冲突,也没有定时器调度抢占,会随着其他代码的阻塞而阻塞。这种类似的问题不再详述,大家使用的时候多测测就好。

3、任务调度

看了上面的操作,如果我们不叫软件定时器,叫它“任务”,是不是和FreeRTOS任务类似,感觉高端一些,甚至这篇文章标题可以修改为《一篇文章教你实现操作系统》,开个欢笑,不做标题党。

有些项目实时性要求高,需要任务抢占,所以需要使用FreeRTOS这样的操作系统,但它资源占用比例过大,不利于项目开发,在一般的小项目中也用不到RTOS的太多功能,使用上面的思路,你可以把每个任务设置不同的间隔时间周期性调用,如果有实时性要求很高的事件,就通过中断处理。

当然也可以使用开头的粗糙方法

if((systick_ms-timer_tick)>1000)
{timer_tick = systick_ms;timer_1000ms();
}

这样功能是可以实现的,但没有模块化,不利于代码的维护。我们可以借鉴MultiTimer思路封装一下软件接口。

并且,如果你的项目中,任务的个数是固定不变的,可以将MultiTimer中的链表拿掉,直接使用全局变量就可以,如果有额外的时间模仿FreeRTOS实现一些信号量,对列等,这就是自己的OS(无抢占)啊。(当然这属于重复造轮子,但对一些公司来讲,有适合自己业务的,最精简的代码框架是很有必要的)。

我简单粗糙的实现了一个,有兴趣的可以看一下

开源地址:STM32F207VCT6/41-SoftwareTask at master · strongercjd/STM32F207VCT6 · GitHub

点击查看点击查看:C语言进阶专辑

关于软件定时器的一些讨论相关推荐

  1. freeRTOS — 软件定时器的使用

    freeRTOS中加入了软件定时器这个功能组件,是一个可选的.不属于freeRTOS内核的功能,由定时器服务(其实就是一个定时器任务)来提供. 软件定时器是当设定一个定时时间,当达到设定的时间之后就会 ...

  2. 高效软件定时器的设计

    摘要 软件定时器在协议栈等很多场景都有广泛的应用,有时候会有大量的定时器同时处于工作状态,它们的超时时间各异,要高效的保证每个定时器都能够较为准确的超时并执行到其回调函数并不是一件易事.本文分析嵌入式 ...

  3. 单片机裸机实用组件--软件定时器、时间戳

    单片机裸机实用组件–软件定时器.时间戳 之前写过一篇关于单片机定时器延时计时功能的博客 ,刚工作的时候搞得现在看来还是比较糙的,是时候整一个新的了. base_timer 单片机裸机适用的定时器小组件 ...

  4. freeRtos学习笔记 (6)软件定时器

    freeRtos学习笔记 freeRtos软件定时器 软件定时器需要注意事项 软件定时器的精度基于时钟节拍,例如系统时钟节拍为10ms, 软件定时器定时时间必须是10ms的整数倍,因此软件定时器一般用 ...

  5. 定时器回调函数怎么写_ESP8266_04管脚控制与软件定时器

    这一节主要有两部分内容:1.管脚的控制:2.软件定时器的使用. 先说定时器,ESP8266内部的定时器分为软件定时器和硬件定时器.手册中指出硬件定时器其实就跟单片机里的timer一样,而软件定时器纯粹 ...

  6. μC/OS-II软件定时器的分析与测试

     引 言 μC/OS-II操作系统是建立在微内核基础上的实时操作系统,抢占式多任务.微内核.移植性好等特点,使其在诸多领域都有较好的应用. 在μC/OS-II 2.83及其以后的版本中,一个较大的 ...

  7. RTX5 | 软件定时器02 - 创建一个软件定时器(连续运行)

    文章目录 一.前言 二.实验目的 三.API 3.1.osTimerNew 3.2.osTimerStart 四.代码 4.1.main.h 4.2.main.c 五.Event Recorder调试 ...

  8. RTX5 | 软件定时器01 - 创建一个软件定时器(单次运行)

    文章目录 一.前言 二.实验目的 三.API 3.1.osTimerNew 3.2.osTimerStart 四.代码 4.1.main.h 4.2.main.c 五.Event Recorder调试 ...

  9. 8.FreeRTOS学习笔记-软件定时器

    基本概念 软件定时器的回调函数类似硬件的中断服务函数,所以,回调函数也要快进快出,而且回调函数中不能有任何阻塞任务运行的情况,例如不可以使用vTaskDelay() FreeRTOS 提供的软件定时器 ...

最新文章

  1. 热电偶校验仪使用说明_热电偶冷端补偿方法
  2. Thinkphp 逻辑与,逻辑或的复合查询
  3. 标签页式样的对话框参考
  4. 今晚直播 | 微软亚洲研究院徐毅恒:预训练时代下的文档智能
  5. C++还是Java常常无法想起数组
  6. mysql innodb引擎数据存储方式和索引的概念
  7. 详解Camtasia的场景转换功能
  8. MFC可编辑CListCtrl
  9. 现代计算机发展各个阶段的主要特点是什么,计算机的发展历史 现代计算机发展的6个阶段...
  10. pe 引导win7镜像 激活
  11. JDK 11 是发布了,但收费吗?
  12. 红黑联盟 php相关资讯
  13. 加拿大康考迪亚计算机工程,加拿大康考迪亚
  14. 卡通渲染的3D电影《苹果核战记》
  15. mysql原理(1) mysql底层数据结构
  16. 地平线机器人上海待遇_目前室内机器人、SLAM现状如何?行业内顶尖技术在哪些高校或企业 ?...
  17. LVS负载均衡环境搭建
  18. 第二章 一种操作系统的诞生
  19. 计算思维导论——第一章:计算机,计算与计算思维
  20. 【在线支付】在线支付代码详解

热门文章

  1. Python的PIL库中的getpixel方法 putpixel方法
  2. 从零开始搭建仿抖音短视频APP-开发用户业务模块(3)
  3. 大豆SNP位点查找V2.0
  4. php语音直播怎么做,语音直播功能实现流程
  5. 位置定位(LocationManager)
  6. 教授专栏11|张处:企业支付政策和信用风险:来自信用违约掉期(CDS)市场的证据
  7. 【计算机毕业设计】267防疫信息登记系统设计与实现
  8. 明天太阳照常升起的概率是多少?
  9. 如何在R中画出高效美观的相关性分析图
  10. IECIE电子烟展——深圳第六届电子烟博览会