0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何实现一个软件定时器?

工程师进阶笔记 来源:csdn 2024-04-29 11:00 次阅读

有时候,我们在进行产品开发的时候,由于选用的处理器芯片资源有限的原因,没有更多的硬件定时器外设提供给我们使用,但我们的程序设计又需要定时器进行各种延时或者定时任务处理,这个时候,软件定时器就应运而生。

1.什么是软件定时器

软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。

但由于软件定时器是通过程序实现的,其运行和维护都需要耗费一定的CPU资源,同时精度也相对硬件定时器要差一些。

2.软件定时器的实现原理

Linux,uC/OS,FreeRTOS操作系统中,都带有软件定时器,原理大同小异。典型的实现方法是:通过一个硬件定时器产生固定的时钟节拍,每次硬件定时器中断到,就对一个全局的时间标记加一,每个软件定时器都保存着到期时间。

程序需要定期扫描所有运行中的软件定时器,将各个到期时间与全局时钟标记做比较,以判断对应软件定时器是否到期,到期则执行相应的回调函数,并关闭该定时器。

以上是单次定时器的实现,若要实现周期定时器,即到期后接着重新定时,只需要在执行完回调函数后,获取当前时间标记的值,加上延时时间作为下一次到期时间,继续运行软件定时器即可。

3.基于STM32的软件定时器

3.1 时钟节拍

软件定时器需要一个硬件时钟源作为基准,这个时钟源有一个固定的节拍(可以理解为秒针的每次滴答),用一个32位的全局变量tickCnt来记录这个节拍的变化:

staticvolatileuint32_ttickCnt=0;//软件定时器时钟节拍

每来一个节拍就对tickCnt加一(记录滴答了多少下):

/*需在定时器中断内执行*/
voidtickCnt_Update(void)
{
tickCnt++;
}

一旦开始运行,tickCnt将不停地加一,而每个软件定时器都记录着一个到期时间,只要tickCnt大于该到期时间,就代表定时器到期了。

3.2 数据结构

软件定时器的数据结构决定了其执行的性能和功能,一般可分为两种:数组结构和链表结构。什么意思呢?这是(多个)软件定时器在内存中的存储方式,可以用数组来存,也可以用链表来存。

两者的优劣之分就是两种数据结构的特性之分:数组方式的定时器查找较快,但数量固定,无法动态变化,数组大了容易浪费内存,数组小了又可能不够用,适用于定时事件明确且固定的系统;链表方式的定时器数量可动态增减,易造成内存碎片(如果没有内存管理),查找的时间开销相对数组大,适用于通用性强的系统,Linux,uC/OS,FreeRTOS等操作系统用的都是链表式的软件定时器。

本文使用数组结构:

staticsoftTimertimer[TIMER_NUM];//软件定时器数组

数组和链表是软件定时器整体的数据结构,当具体到单个定时器时,就涉及软件定时器结构体的定义,软件定时器所具有的功能与其结构体定义密切相关,以下是本文中软件定时器的结构体定义

typedefstructsoftTimer{
uint8_tstate;//状态
uint8_tmode;//模式
uint32_tmatch;//到期时间
uint32_tperiod;//定时周期
callback*cb;//回调函数指针
void*argv;//参数指针
uint16_targc;//参数个数
}softTimer;

定时器的状态共有三种,默认是停止,启动后为运行,到期后为超时。

typedefenumtmrState{
SOFT_TIMER_STOPPED=0,//停止
SOFT_TIMER_RUNNING,//运行
SOFT_TIMER_TIMEOUT//超时
}tmrState;

模式有两种:到期后就停止的是单次模式,到期后重新定时的是周期模式。

typedefenumtmrMode{
MODE_ONE_SHOT=0,//单次模式
MODE_PERIODIC,//周期模式
}tmrMode;

不管哪种模式,定时器到期后,都将执行回调函数,以下是该函数的定义,参数指针argv为void指针类型,便于传入不同类型的参数。

typedefvoidcallback(void*argv,uint16_targc);

上述结构体中的模式state和回调函数指针cb是可选的功能,如果系统不需要周期执行的定时器,或者不需要到期后自动执行某个函数,可删除此二者定义。

3.3 定时器操作

3.3.1 初始化

首先是软件定时器的初始化,对每个定时器结构体的成员赋初值,虽说static变量的初值为0,但个人觉得还是有必要保持初始化变量的习惯,避免出现一些奇奇怪怪的BUG。

voidsoftTimer_Init(void)
{
uint16_ti;
for(i=0;i

3.3.2 启动

启动一个软件定时器不仅要改变其状态为运行状态,同时还要告诉定时器什么时候到期(当前tickCnt值加上延时时间即为到期时间),单次定时还是周期定时,到期后执行哪个函数,函数的参数是什么,交代好这些就可以开跑了。

voidsoftTimer_Start(uint16_tid,tmrModemode,uint32_tdelay,callback*cb,void*argv,uint16_targc)
{
assert_param(id< TIMER_NUM);
 assert_param(mode == MODE_ONE_SHOT || mode == MODE_PERIODIC);
 
 timer[id].match = tickCnt_Get() + delay;
 timer[id].period = delay;
 timer[id].state = SOFT_TIMER_RUNNING;
 timer[id].mode = mode;
 timer[id].cb = cb;
 timer[id].argv = argv;
 timer[id].argc = argc;
}

上面函数中的assert_param()用于参数检查,类似于库函数assert()。

3.3.3 更新

本文中软件定时器有三种状态:停止,运行和超时,不同的状态做不同的事情。停止状态最简单,啥事都不做;运行状态需要不停地检查有没有到期,到期就执行回调函数并进入超时状态;超时状态判断定时器的模式,如果是周期模式就更新到期时间,继续运行,如果是单次模式就停止定时器。

这些操作都由一个更新函数来实现:

voidsoftTimer_Update(void)
{
uint16_ti;

for(i=0;i

3.3.4 停止

如果定时器跑到一半,想把它停掉,就需要一个停止函数,操作很简单,改变目标定时器的状态为停止即可:

voidsoftTimer_Stop(uint16_tid)
{
assert_param(id< TIMER_NUM);
 timer[id].state = SOFT_TIMER_STOPPED;
}

3.3.5 读状态

又如果想知道一个定时器是在跑着呢还是已经停下来?也很简单,返回它的状态:

uint8_tsoftTimer_GetState(uint16_tid)
{
returntimer[id].state;
}

或许这看起来很怪,为什么要返回,而不是直接读?别忘了在前面3.2节中定义的定时器数组是个静态全局变量,该变量只能被当前源文件访问,当外部文件需要访问它的时候只能通过函数返回,这是一种简单的封装,保持程序的模块化。

3.4 测试

最后,当然是来验证一下我们的软件定时器有没达到预想的功能。

定义三个定时器:

定时器TMR_STRING_PRINT只执行一次,1s后在串口1打印一串字符;

定时器TMR_TWINKLING为周期定时器,周期为0.5s,每次到期都将取反LED0的状态,实现LED0的闪烁;

定时器TMR_DELAY_ON执行一次,3s后点亮LED1,跟第一个定时器不同的是,此定时器的回调函数是个空函数nop(),点亮LED1的操作通过主循环中判断定时器的状态来实现,这种方式在某些场合可能会用到。

staticuint8_tdata[]={1,2,3,4,5,6,7,8,9,0};

intmain(void)
{
USART1_Init(115200);
TIM4_Init(TIME_BASE_MS);
TIM4_NVIC_Config();
LED_Init();

printf("Ijustgrabbedaspoon.
");

softTimer_Start(TMR_STRING_PRINT,MODE_ONE_SHOT,1000,stringPrint,data,5);
softTimer_Start(TMR_TWINKLING,MODE_PERIODIC,500,LED0_Twinkling,NULL,0);
softTimer_Start(TMR_DELAY_ON,MODE_ONE_SHOT,3000,nop,NULL,0);

while(1){
softTimer_Update();
if(softTimer_GetState(TMR_DELAY_ON)==SOFT_TIMER_TIMEOUT){
LED1_On();
}
}
}
审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10859

    浏览量

    211687
  • 操作系统
    +关注

    关注

    37

    文章

    6818

    浏览量

    123319
  • 软件定时器
    +关注

    关注

    0

    文章

    18

    浏览量

    6744

原文标题:硬件定时器不够用,如何实现一个软件定时器?

文章出处:【微信号:工程师进阶笔记,微信公众号:工程师进阶笔记】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于STM32的软件定时器设计

    软件定时器是用程序模拟出来的定时器,可以由硬件定时器模拟出成千上万
    发表于 07-03 17:06 1058次阅读
    基于STM32的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>设计

    请问怎么用硬件定时器实现多个不同的软件定时器

    怎样用硬件定时器,来实现多个软件定时器的功能?每个定时器
    发表于 03-13 04:35

    什么是软件定时器软件定时器实现原理是什么?

    什么是软件定时器软件定时器实现原理是什么?
    发表于 11-24 06:43

    什么是软件定时器?基于STM32的软件定时器该怎样去实现

    3.3.5 读状态3.4 测试4.参考链接1.什么是软件定时器软件定时器是用程序模拟出来的定时器,可以由
    发表于 12-22 07:47

    555定时器应用设计软件免费下载

    本文档的主要内容详细介绍的是555定时器应用设计软件免费下载,本软件款555定时器设计软件
    发表于 12-17 08:00 51次下载
    555<b class='flag-5'>定时器</b>应用设计<b class='flag-5'>软件</b>免费下载

    ESP8266的管脚的控制和软件定时器的使用

    先说定时器,ESP8266内部的定时器分为软件定时器和硬件定时器。手册中指出硬件定时器其实就跟单
    的头像 发表于 07-29 14:57 9510次阅读
    ESP8266的管脚的控制和<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>的使用

    设计软件定时器

    在MCU芯片内部,往往硬件定时器的数量是非常有限的,而实际工程中却需要大量的定时器来辅助完成具体的功能,如果函数占用
    发表于 11-05 18:35 2次下载
    设计<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>

    基于硬件定时器软件定时器

    出现使用软件定时器的情况,但是讲定时器需要从硬件定时器开始讲,软件定时器是在其基础之上延伸出来的
    发表于 11-25 09:51 8次下载
    基于硬件<b class='flag-5'>定时器</b>的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>

    STM32开发项目:软件虚拟定时器实现

    ,这主要体现在两方面:其是硬件定时器数量十分有限(般4~8);其二是硬件定时器难以直接产
    发表于 12-24 19:15 1次下载
    STM32开发项目:<b class='flag-5'>软件</b>虚拟<b class='flag-5'>定时器</b>的<b class='flag-5'>实现</b>

    软件定时器简介及程序配置

      软件定时器就是允许函数设置定的等待时间,然后执行。定时器执行的函数被称为定时器的回调函数。定时器
    的头像 发表于 12-06 16:10 3909次阅读
    <b class='flag-5'>软件</b><b class='flag-5'>定时器</b>简介及程序配置

    单片机软件定时器实现方法

    定时器个数般都比较少,在些有多个周期性操作的应用场合就无法满足要求。这时,就可以基于硬件定时器派生出软件
    的头像 发表于 01-17 15:14 4890次阅读
    单片机<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>的<b class='flag-5'>实现</b>方法

    freeRTOS软件定时器的使用

    freeRTOS中加入了软件定时器这个功能组件,是可选的、不属于freeRTOS内核的功能,由定时器服务(其实就是
    的头像 发表于 02-10 13:55 2158次阅读

    Free RTOS的软件定时器

    软件定时器是FreeRTOS中的重要模块,使用软件定时器可以方便的
    的头像 发表于 02-10 15:53 2340次阅读
    Free RTOS的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>

    什么是软件定时器软件定时器实现原理

    软件定时器是用程序模拟出来的定时器,可以由硬件定时器模拟出成千上万
    的头像 发表于 05-23 17:05 2786次阅读

    定时器设计实现

    返回ITimer类型的共享指针。其中ITimer类中定义了start和stop方法,用于启动或停止当前定时器。 TimerManager还有内部类TimerMessageQueue用于实现
    的头像 发表于 11-08 16:50 602次阅读