freeRTOS系统定时器任务:

本文抄录自:以下网页: https://www.jianshu.com/p/ef802b7aea81 作者:Leung_ManWah
链接:https://www.jianshu.com/p/ef802b7aea81 来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、头文件

#include "FreeRTOS.h"
#include "timers.h"

二、软件定时器
2.1 基本概念
软件定时器在被创建之后,当经过设定的时钟计数值后会触发用户定义的回调函数。 定时精度与系统时钟的周期有关。一般系统利用 SysTick 作为软件定时器的基础时钟,软件定时器的回调函数类似硬件的中断服务函数,所以,回调函数也要快进快出,而且回调函数中不能有任何阻塞任务运行的情况(软件定时器回调函数的上下文环境是任务),比如 vTaskDelay() 以及其它能阻塞任务运行的函数,两次触发回调函数的时间间隔 xTimerPeriodInTicks 叫定时器的定时周期。

FreeRTOS 提供的软件定时器支持单次模式和周期模式,单次模式和周期模式的定时时间到之后都会调用软件定时器的回调函数,用户可以在回调函数中加入要执行的工程代码。

单次模式:当用户创建了定时器并启动了定时器后,定时时间到了,只执行一次回调函数之后就将该定时器删除,不再重新执行。
周期模式:这个定时器会按照设置的定时时间循环执行回调函数,直到用户将定时器删除


FreeRTOS 通过一个 prvTimerTask 任务(也叫守护任务 Daemon)管理软定时器,它是在启动调度器时自动创建的,为了满足用户定时需求。prvTimerTask 任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数。只有设置 FreeRTOSConfig.h 中的宏定义configUSE_TIMERS 设置为 1 ,将相关代码编译进来,才能正常使用软件定时器相关功能。

2.2 时间精度
在操作系统中,通常软件定时器以系统节拍周期为计时单位。系统节拍是系统的心跳节拍,表示系统时钟的频率,就类似人的心跳,1s 能跳动多少下,系统节拍配置为 configTICK_RATE_HZ,该宏在 FreeRTOSConfig.h 中有定义,默认是 1000。那么系统的时钟节拍周期就为 1ms(1s 跳动 1000 下,每一下就为 1ms)。软件定时器的所定时数值必须是这个节拍周期的整数倍,例如节拍周期是 10ms,那么上层软件定时器定时数值只能是10ms,20ms,100ms 等,而不能取值为 15ms。由于节拍定义了系统中定时器能够分辨的精确度,系统可以根据实际系统 CPU 的处理能力和实时性需求设置合适的数值,系统节拍周期的值越小,精度越高,但是系统开销也将越大,因为这代表在 1 秒中系统进入时钟中断的次数也就越多。

2.3 注意要点
软件定时器的回调函数中应快进快出,绝对不允许使用任何可能引软件定时器起任务挂起或者阻塞的 API 接口,在回调函数中也绝对不允许出现死循环。
软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级默
认为 configTIMER_TASK_PRIORITY,为了更好响应,该优先级应设置为所有任务中最高的优先级。
创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。
定时器任务的堆栈大小默认为 configTIMER_TASK_STACK_DEPTH 个字节。

三、相关API说明
3.1 xTimerCreate
创建一个软件定时器,并返回一个句柄。

函数

TimerHandle_t xTimerCreate( const char * const pcTimerName, TickType_t xTimerPeriodInTicks, UBaseType_t uxAutoReload, void * pvTimerID, TimerCallbackFunction_t pxCallbackFunction )
参数
pcTimerName: 软件定时器名字,文本形式,纯粹是为了调试
xTimerPeriodInTicks: 软件定时器的周期,单位为系统节拍周期(即 tick)。使用 pdMS_TO_TICKS() 可以把时间单位从 ms 转换为系统节拍周期。如果软件定时器的周期为 100 个 tick,那么只需要简单的设置 xTimerPeriod 的值为 100 即可。如果软件定时器的周期为 500ms,那么 xTimerPeriod 应设置为 pdMS_TO_TICKS(500)。宏 pdMS_TO_TICKS()只有当 configTICK_RATE_HZ 配置成小于或者等于 1000HZ 时才可以使用
uxAutoReload: 设置为 pdTRUE,那么软件定时器的工作模式就是周期模式, 一直会以用户指定的 xTimerPeriod 周期去执行回调函数。如果 uxAutoReload 设置为 pdFALSE,那么软件定时器就在用户指定的 xTimerPeriod 周期下运行一次后就进入休眠态
pvTimerID: 软件定时器 ID,数字形式。该 ID 典型的用法是当一个回调函数分配给一个或者多个软件定时器时,在回调函数里面根据 ID 号来处理不同的软件定时器
pxCallbackFunction: 软件定时器的回调函数,当定时时间到达的时候就会调用这个函数,该函数需要用户自己实现

返回值 定时器句柄

要想使用该函数必须在 FreeRTOSConfig.h 中把 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1 来使能。


同时把 FreeRTOS/source/timers.c 这个 C 文件添加到工程中。

3.2 xTimerStart(任务)
启动软件定时器。

函数   BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait )参数   xTimer: 要操作的软件定时器句柄
xTicksToWait: 用户指定的超时时间,单位为系统节拍周期(即 tick),如果在 FreeRTOS 调度器开启之前调用 xTimerStart(),该形参将不起作用返回值  如果启动命令无法成功地发送到定时器命令队列则返回 pdFAILE,成功发送则返回 pdPASS。软件定时器成功发送的命令是否真正的被执行也还要看定时器守护任务的优先级,其优先级由宏 configTIMER_TASK_PRIORITY 定义

要想使用该函数必须在 FreeRTOSConfig.h 中把 configUSE_TIMERS 定义为 1 来使能。


3.3 xTimerStartFromISR(中断)
在中断中启动软件定时器。

函数   BaseType_t xTimerStartFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken )参数  xTimer: 要操作的软件定时器句柄
pxHigherPriorityTaskWoken: 定时器守护任务的大部分时间都在阻塞态等待定时器命令队列的命令。调用函数 xTimerStartFromISR() 将会往定时器的命令队列发送一个启动命令,这很有可能会将定时器任务从阻塞态移除。如果调用函数 xTimerStartFromISR() 让定时器任务脱离阻塞态,且定时器守护任务的优先级大于或者等于当前被中断的任务的优先级,那么 pxHigherPriorityTaskWoken 的值会在函数 xTimerStartFromISR() 内部设置为 pdTRUE,然后在中断退出之前执行一次上下文切换返回值    如果启动命令无法成功地发送到定时器命令队列则返回 pdFAILE,成功发送则返回 pdPASS。软件定时器成功发送的命令是否真正的被执行也还要看定时器守护任务的优先级,其优先级由宏 configTIMER_TASK_PRIORITY 定义

要想使用该函数必须在 FreeRTOSConfig.h 中把 configUSE_TIMERS 定义为 1 来使能。


3.4 xTimerStop(任务)
停止一个软件定时器,让其进入休眠态。

函数   BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xBlockTime )参数  xTimer: 要操作的软件定时器句柄
xBlockTime: 用户指定超时时间,单位为系统节拍周期(即 tick)。如果在 FreeRTOS 调度器开启之前调用 xTimerStart(),形参将不起作用返回值 如果停止命令在超时时间之前无法成功地发送到定时器命令队列则返回 pdFAILE,成功发送则返回 pdPASS。软件定时器成功发送的命令是否真正的被执行也还要看定时器守护任务的优先级,其优先级由宏 configTIMER_TASK_PRIORITY 定义

要想使用该函数必须在 FreeRTOSConfig.h 中把 configUSE_TIMERS 定义为 1 来使能。

3.5 xTimerStopFromISR(中断)
在中断中停止一个软件定时器,让其进入休眠态。

函数 BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken )

参数 xTimer: 要操作的软件定时器句柄
pxHigherPriorityTaskWoken: 定时器守护任务的大部分时间都在阻塞态等待定时器命令队列的命令。调用函数 xTimerStartFromISR() 将会往定时器的命令队列发送一个启动命令,这很有可能会将定时器任务从阻塞态移除。如果调用函数 xTimerStartFromISR() 让定时器任务脱离阻塞态,且定时器守护任务的优先级大于或者等于当前被中断的任务的优先级,那么 pxHigherPriorityTaskWoken 的值会在函数 xTimerStartFromISR() 内部设置为 pdTRUE,然后在中断退出之前执行一次上下文切换

返回值 如果停止命令在超时时间之前无法成功地发送到定时器命令队列则返回 pdFAILE,成功发送则返回 pdPASS。软件定时器成功发送的命令是否真正的被执行也还要看定时器守护任务的优先级,其优先级由宏 configTIMER_TASK_PRIORITY 定义

要想使用该函数必须在 FreeRTOSConfig.h 中把 configUSE_TIMERS 定义为 1 来使能。

3.6 xTimerDelete
用于删除一个已经被创建成功的软件定时器,删除之后就无法使用该定时器,并且定时器相应的资源也会被系统回收释放。

函数 BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait )

参数 xTimer: 要操作的软件定时器句柄
xTicksToWait: 用户指定的超时时间,单位为系统节拍周期(即 tick),如果在 FreeRTOS 调度器开启之前调用 xTimerStart(),该形参将不起作用

返回值 如果删除命令在超时时间之前无法成功地发送到定时器命令队列则返回 pdFAILE,成功发送则返回 pdPASS

要想使用该函数必须在 FreeRTOSConfig.h 中把 configUSE_TIMERS 定义为 1 来使能。

四、示例

4.1 任务式

/* FreeRTOS 头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
/* 开发板硬件 bsp 头文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_key.h"
/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为 NULL。
*/
static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 *//***************************** 内核对象句柄 *****************************/
/*
* 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
* 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
* 们就可以通过这个句柄操作这些内核对象。
*
* 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
* 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
* 来完成的
*
*/
static TimerHandle_t Swtmr1_Handle = NULL; /* 软件定时器句柄 */
static TimerHandle_t Swtmr2_Handle = NULL; /* 软件定时器句柄 */
/************************* 全局变量声明 *********************************/
/*
* 当我们在写应用程序的时候,可能需要用到一些全局变量。
*/
static uint32_t TmrCb_Count1 = 0; /* 记录软件定时器 1 回调函数执行次数 */
static uint32_t TmrCb_Count2 = 0; /* 记录软件定时器 2 回调函数执行次数 *//*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */static void Swtmr1_Callback(void* parameter);
static void Swtmr2_Callback(void* parameter); static void BSP_Init(void);/* 用于初始化板载相关资源 */int main(void)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS *//* 开发板硬件初始化 */BSP_Init();/* 创建 AppTaskCreate 任务 */xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,/* 任务入口函数 */(const char* )"AppTaskCreate",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )1, /* 任务的优先级 */(TaskHandle_t*)&AppTaskCreate_Handle);/* 任务控制块指针 *//* 启动任务调度 */if (pdPASS == xReturn){vTaskStartScheduler(); /* 启动任务,开启调度 */}else{return -1;}while (1); /* 正常不会执行到这里 */
}/***********************************************************************
* @ 函数名 : AppTaskCreate
* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
* @ 参数 : 无
* @ 返回值 : 无
******************************************************************/
static void AppTaskCreate(void)
{taskENTER_CRITICAL(); //进入临界区Swtmr1_Handle=xTimerCreate((const char*)"AutoReloadTimer", (TickType_t)1000,/*定时器周期 1000(tick) */ (UBaseType_t)pdTRUE,/* 周期模式 */ (void*)1,/*为每个计时器分配一个索引的唯一 ID */ (TimerCallbackFunction_t)Swtmr1_Callback); if (Swtmr1_Handle != NULL) { xTimerStart(Swtmr1_Handle,0); //开启周期定时器 }Swtmr2_Handle=xTimerCreate((const char* )"OneShotTimer", (TickType_t)5000,/*定时器周期 5000(tick) */ (UBaseType_t )pdFALSE,/* 单次模式 */ (void*)2,/*为每个计时器分配一个索引的唯一 ID */ (TimerCallbackFunction_t)Swtmr2_Callback); if (Swtmr2_Handle != NULL) {xTimerStart(Swtmr2_Handle,0); //开启周期定时器 } vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务taskEXIT_CRITICAL(); //退出临界区
}/***********************************************************************
* @ 函数名 : Swtmr1_Callback
* @ 功能说明: 软件定时器 1 回调函数,打印回调函数信息&当前系统时间
* 软件定时器请不要调用阻塞函数,也不要进行死循环,应快进快出
* @ 参数 : 无
* @ 返回值 : 无
********************************************************/
static void Swtmr1_Callback(void* parameter)
{ TickType_t tick_num1; TmrCb_Count1++; /* 每回调一次加一 */ tick_num1 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */ LED1_TOGGLE; printf("swtmr1_callback 函数执行 %d 次\n", TmrCb_Count1); printf("滴答定时器数值=%d\n", tick_num1); } /***********************************************************************
* @ 函数名 : Swtmr2_Callback
* @ 功能说明: 软件定时器 2 回调函数,打印回调函数信息&当前系统时间
* 软件定时器请不要调用阻塞函数,也不要进行死循环,应快进快出
* @ 参数 : 无
* @ 返回值 : 无
********************************************************/
static void Swtmr2_Callback(void* parameter)
{ TickType_t tick_num2; TmrCb_Count2++; /* 每回调一次加一 */ tick_num2 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */ printf("swtmr2_callback 函数执行 %d 次\n", TmrCb_Count2); printf("滴答定时器数值=%d\n", tick_num2);
} /***********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void BSP_Init(void)
{/** STM32 中断优先级分组为 4,即 4bit 都用来表示抢占优先级,范围为:0~15* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,* 都统一用这个优先级分组,千万不要再分组,切忌。*/NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );/* LED 初始化 */LED_GPIO_Config();/* 串口初始化 */USART_Config();/* 按键初始化 */Key_GPIO_Config();
}

4.2 中断式

/* 这个方案假定软件定时器 xBacklightTimer 已经创建,定时周期为 5s,执行次数为一次,即定时时间到了之后就进入休眠态。程序说明:当按键按下,打开液晶背光,启动软件定时器,5s 时间到,关掉液晶背光
*//* 软件定时器回调函数 */
void vBacklightTimerCallback( TimerHandle_t pxTimer )
{/* 关掉液晶背光 */vSetBacklightState( BACKLIGHT_OFF );
}/* 按键中断服务程序 */
void vKeyPressEventInterruptHandler( void )
{BaseType_t xHigherPriorityTaskWoken = pdFALSE;/* 确保液晶背光已经打开 */vSetBacklightState( BACKLIGHT_ON );/* 启动软件定时器 */if ( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) { /* 软件定时器开启命令没有成功执行 */ } /* ...执行其他的按键相关的功能代码 */if ( xHigherPriorityTaskWoken != pdFALSE ) { /* 执行上下文切换 */ }
}
/* 这个方案假定软件定时器 xTimer 已经创建且启动。当中断发生时,停止软件定时器 *//* 停止软件定时器的中断服务函数*/
void vAnExampleInterruptServiceRoutine( void )
{BaseType_t xHigherPriorityTaskWoken = pdFALSE;if (xTimerStopFromISR(xTimer,&xHigherPriorityTaskWoken)!=pdPASS ) { /* 软件定时器停止命令没有成功执行 */}if ( xHigherPriorityTaskWoken != pdFALSE ) { /* 执行上下文切换 */}
}

FreeRTOS系统定时器任务的实现相关推荐

  1. FreeRTOS软件定时器 | FreeRTOS十三

    目录 说明: 一.定时器简介 1.1.定时器 1.2.软件定时器 1.3.硬件定时器 1.4.FreeRTOS软件定时器 1.5.软件定时器服务任务作用 1.6.软件定时器的命令队列 1.7.软件定时 ...

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

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

  3. FreeRTOS软件定时器 基于STM32

    文章目录 一·.软件定时器的基本概念 二.软件定时器应用场景 三.软件定时器的精度 四.软件定时器的运作机制 五.软件定时器函数接口讲解 1.软件定时器创建函数 xTimerCreate() 2.软件 ...

  4. Esp8266进阶之路14 esp8266的 FreeRtos系统学习的正确姿势,环境配置环境、烧录。(附带demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  5. stm32F103上基于FreeRTOS系统的亮度可调小台灯

    目录 在FreeRTOS系统上做一个亮度可调的小台灯 项目要求 项目拆解 结果展示 使用工具 参考历程 主要代码 在FreeRTOS系统上做一个亮度可调的小台灯 项目要求 1)小台灯可以手动进行点亮和 ...

  6. 嵌入式开发(7)系统定时器(SysTick)之延时函数运用

    目录 一.系统定时器 1. 简介 2.工作原理 3.频率的概念 二.库函数SysTick定时器操作 系统定时器配置 三.寄存器SysTick定时器操作 1.系统定时器的用途 2.寄存器 3.官方示例 ...

  7. FreeRTOS 软件定时器的使用

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

  8. STM32 基础系列教程 5 – 系统定时器

    前言 学习stm32 systime的使用,用基本定时器产生定时1ms定时中断,用于参生1ms系统时钟节拍,并实现将1ms 节拍改成500us 或其它时间功能.并实产生的时间节拍为机基准实现控制LED ...

  9. 嵌入式FreeRTOS系统,在中断中调用FreeRTOS系统的API函数

    作为在中断中调用FreeRTOS系统的API函数的参考,disp_str()是显示屏的显示函数会将传入的字符串进行显示. void TIM5_Int_Init(u16 arr,u16 psc) {TI ...

最新文章

  1. GraphQL入门之graphql-java项目的介绍
  2. Struts2_day01
  3. 狂神说spring笔记
  4. 梯度下降法、最速下降法
  5. PopTheBubble —测量媒体偏差的产品创意
  6. Struts2→MCV、环境搭建第一个样例、工作原理、核心文件、XML中常用元素、通配符、action后缀、action接收参数、result、标签
  7. Django官方文档翻译——Django中的用户身份验证(User authentication in Django)
  8. BZOJ2933 : [Poi1999]地图
  9. latex中输入matlab代码,Latex插入matlab代码
  10. SecureCRT无法使用Zmodem上传下载文件
  11. dbv mysql_mysql数据库版本控制dbv使用 - mysql数据库栏目 - 自
  12. vue获取麦克风_HTML5操作麦克风获取音频数据(WAV)的一些基础技能
  13. 音频压缩编码技术(一)—有损压缩
  14. ERROR 1018 (HY000): Can‘t read dir of ‘.‘ (errno: 13 - Permission denied)
  15. 亿阳信通java开发,北京亿阳信通笔试题java+oracle
  16. python爬虫常见报错_Python爬虫常见异常及解决办法
  17. 【转载】犀利哥:无法犀利的人生
  18. 东北电力大学计算机学院教务处,2020年东北电力大学计算机学院初试
  19. 一天一篇latex刘海洋代码解析:1.2.5 遭遇数学公式
  20. 【实验3】——目标的分辨能力

热门文章

  1. Scala Trait 详解(实例)
  2. PHP trait的使用
  3. 10、zuul 网关配置
  4. ParaView Visualizer 在ubuntu22.04环境下快速开发入门指南
  5. BigDecimal除法后保留两位小数
  6. graphpad做图如何加星号_如何用R画分组柱状图并且添加标准差和显著性标记(星号)?...
  7. 温故而知新CentOS宝塔
  8. HUAWEI华为笔记本电脑MateBook 13(WRTB-WFE9L)原装出厂系统恢复原厂系统
  9. 云IDE:Code-Server:VS Code的开源IDE
  10. 常用插件,网址,收藏夹