打印

FreeRTOS 软定时器实现

[复制链接]
994|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2021-11-16 15:12 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 keer_zu 于 2021-11-16 15:15 编辑

简述考虑平台硬件定时器个数限制的, FreeRTOS 通过一个 Daemon 任务(启动调度器时自动创建)管理软定时器, 满足用户定时需求. Daemon 任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数。
对于硬件定时器的中断服务程序, 我们知道不应该在里面执行复杂,可能导致阻塞的工作,相应的, 虽然软定时器实际是在定时Daemon 任务中执行,但是阻塞的话会导致其他定时器调用被延时, 所以实际使用也应该避免。
软定时器是通过一个任务来辅助实现,该功能是可裁剪的 , 只有设置 FreeRTOSConfig.h 中configUSE_TIMERS == 1 将相关代码编译进来, 才能正常使用相关功能。
分析的源码版本是 v9.0.0





使用特权

评论回复

相关帖子

沙发
keer_zu|  楼主 | 2021-11-16 15:15 | 只看该作者
使用定时器开始先介绍下如何在自己的工程中使用 FreeRTOS 的软件定时器。
配置定时器服务任务程序中需要使用到软件定时器, 需要先在 FreeRTOSConfig.h 中正确配置如下宏 :
  • configUSE_TIMERS
    是否编译定时器相关代码, 如需要使用定时器, 设置为 1
  • configTIMER_TASK_PRIORITY
    设置定时器Daemon 任务优先级, 如果优先级太低, 可能导致定时器无法及时执行
  • configTIMER_QUEUE_LENGTH
    设置定时器Daemon 任务的命令队列深度, 设置定时器都是通过发送消息到该队列实现的。
  • configTIMER_TASK_STACK_DEPTH
    设置定时器Daemon 任务的栈大小





使用特权

评论回复
板凳
keer_zu|  楼主 | 2021-11-16 15:16 | 只看该作者
创建 启动 停止定时器
如下示例代码所示

TimerHandle_t xTimerUser; // 定义句柄

// 定时器回调函数格式
void vTimerCallback( TimerHandle_t xTimer )
{
    // do something no block
    // 获取溢出次数
    static uin32_t ulCount = ( uint32_t ) pvTimerGetTimerID( xTimer );
    // 累积溢出次数
    ++ulCount;
    // 更新溢出次数
    vTimerSetTimerID( xTimer, ( void * ) ulCount );
   
    if (ulCount == 10) {
        // 停止定时器
        xTimerStop( xTimer, 0 );
    }
}

void fun()
{
    // 申请定时器, 配置
    xTimerUser = xTimerCreate
                   /*调试用, 系统不用*/
                   ("Timer's name",
                   /*定时溢出周期, 单位是任务节拍数*/
                   100,   
                   /*是否自动重载, 此处设置周期性执行*/
                   pdTRUE,
                   /*记录定时器溢出次数, 初始化零, 用户自己设置*/
                  ( void * ) 0,
                   /*回调函数*/
                  vTimerCallback);
                  
     if( xTimerUser != NULL ) {
        // 启动定时器, 0 表示不阻塞
        xTimerStart( xTimerUser, 0 );
    }
}


使用特权

评论回复
地板
keer_zu|  楼主 | 2021-11-16 15:17 | 只看该作者
如上所示, 调用函数 xTimerCreate申请,配置定时器, 通过 xTimerStart 启动定时器, 当定时器计数溢出时, 系统回调注册的函数。
定时器可以设置为一次性 One-shot 或者自动重载 Auto-reload 两种, 第一种溢出后停止定时器, 第二种溢出后会再次启动定时器。




使用特权

评论回复
5
keer_zu|  楼主 | 2021-11-16 15:18 | 只看该作者
修改定时器
在申请定时器的时候设置的定时器周期, 可以通过函数 xTimerChangePeriod 修改, 如下示例 :

 void vAFunction_2( TimerHandle_t xTimer )
{
     // 判断定时器是否处于运行状态
     if( xTimerIsTimerActive( xTimer ) != pdFALSE )
     {
         /* xTimer is active, do something. */
     }
     else
     {
         // 处于这个状态的定时器, 可能由于 :
         // 1 定时器 create 后没有start
         // 2 一次性定时器执行溢出后
         
         // 修改定时器周期
         if( xTimerChangePeriod( xTimer,
                /*修改定时周期*/
                500 / portTICK_PERIOD_MS,
            /*允许阻塞最大时间 100 ticks*/
            100 ) == pdPASS )
         {
             // update fail
             // 阻塞 100 tick 仍然无法发送命令
            
             // 删除定时器 释放对应内存!
             xTimerDelete( xTimer );
         }
         else
         {
             // 定时器配置更新成功, 并已经启动 !!
         }
    }
}
如上, 该函数会修改定时器并使定时器 开始运行!!!

使用特权

评论回复
6
keer_zu|  楼主 | 2021-11-16 15:22 | 只看该作者
另外, 可以通过函数 xTimerReset 重启定时器, 如果已经启动计数, 重新开始计数; 如果没有启动,启动定时器。
定时器使用系统提供 API,涉及 Queue 操作, 如果是在中断程序中调用,需要调用对应带 FromISR的接口。


使用特权

评论回复
7
keer_zu|  楼主 | 2021-11-16 15:23 | 只看该作者
获取定时器状态
其他获取定时器信息的函数
// 获取名称 , 申请是设置的字符串
pcTimerGetName()
// 定时器溢出周期
xTimerGetPeriod()
// 返回定时器溢出的时间点 (--> xTaskGetTickCount())
xTimerGetExpiryTime()


使用特权

评论回复
8
keer_zu|  楼主 | 2021-11-16 15:24 | 只看该作者
定时器的实现参考:
定时器

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1352

主题

12436

帖子

53

粉丝