【FreeRtos软件定时器】

本文详细介绍了FreeRTOS软件定时器的原理和使用,包括软件定时器的分类、配置方法及常见API函数的运用。重点阐述了单次和周期定时器的区别,并提供了实验演示,通过四个按键控制定时器的启停,展示了在实际项目中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FreeRtos软件定时器


前言

本次进行分享的是FreeRtos中的软件定时器的使用,通过本次的学习我们可以基本掌握对FreeRtOS中软件定时器的配置以及基础的使用(如何开启和停止)定时器,并且通过定时器来处理相关的问题。


一、定时器简介

1.1 软件定时器概述

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

1.2 回调使用注意事项

软件定时器的回调函数是在定时器服务任务中执行的,所以一定不能在回调函数中调用任何会阻塞任务的 API 函数!比如,定时器回调函数中千万不能调vTaskDelay()、
vTaskDelayUnti(),还有一些访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。

1.3 定时器的分类

软件定时器分两种:单次定时器和周期定时器,单次定时器的话定时器回调函数就执行一次,比如定时 1s,当定时时间到了以后就会执行一次回调函数,然后定时器就会停止运行。对于单次定时器我们可以再次手动重新启动(调用相应的 API 函数即可),但是单次定时器不能自动重启。相反的,周期定时器一旦启动以后就会在执行完回调函数以后自动的重新启动,这样回调函数就会周期性的执行

Timer1单次定时器  Timer2周期定时器

在这里插入图片描述

复位软件定时器
有时候我们可能会在定时器正在运行的时候需要复位软件定时器,复位软件定时器的话会重新计算定时周期到达的时间点,这个新的时间点是相对于复位定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。

在这里插入图片描述

二、定时器配置及相关函数使用

2.1 定时器的配置

关于定时器的配置都在FreeRTOSConfig.h 中。

1、configUSE_TIMERS
如果要使用软件定时器的话宏 configUSE_TIMERS 一定要设置为 1,当设置为 1 的话定时器服务任务就会在启动 FreeRTOS 调度器的时候自动创建。
2、configTIMER_TASK_PRIORITY
设置软件定时器服务任务的任务优先级,可以为 0~( configMAX_PRIORITIES-1)。优先级一定要根据实际的应用要求来设置。如果定时器服务任务的优先级设置的高的话,定时器命令队列中的命令和定时器回调函数就会及时的得到处理。
3、configTIMER_QUEUE_LENGTH
此宏用来设置定时器命令队列的队列长度。
4、configTIMER_TASK_STACK_DEPTH
此宏用来设置定时器服务任务的任务堆栈大小,单位为字,不是字节!,对于 STM32 来说一个字是 4 字节。由于定时器服务任务中会执行定时器的回调函数,因此任务堆栈的大小一定要根据定时器的回调函数来设置。

2.2 定时器相关API函数

1、函数 xTimerReset()

复位一个软件定时器,此函数只能用在任务中,不能用于中断服务函数!此函数是一个宏,真正执行的是函数 xTimerGenericCommand()

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait ) 

参数:
xTimer: 要复位的软件定时器的句柄。
xTicksToWait: 设置阻塞时间,调用函数 xTimerReset ()开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_RESET 命令,既然是向队列发送消息,那
肯定会涉及到入队阻塞时间的设置。
返回值:
pdPASS: 软件定时器复位成功,其实就是命令发送成功。
pdFAIL: 软件定时器复位失败,命令发送失败。

2、函数 xTimerResetFromISR()

此函数是 xTimerReset()的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数 xTimerGenericCommand()

BaseType_t xTimerResetFromISR( TimerHandle_t xTimer, BaseType_t * pxHigherPriorityTaskWoken ); 

参数:
xTimer: 要复位的软件定时器的句柄。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS: 软件定时器复位成功,其实就是命令发送成功。
pdFAIL: 软件定时器复位失败,命令发送失败。

在这里插入图片描述

3、函数 xTimerStart()

启动软件定时器,函数 xTimerStartFromISR()是这个函数的中断版本,可以用在中断服务函数中。如果软件定时器没有运行的话调用函数 xTimerStart()就会计算定时器到期时间,如果软件定时器正在运行的话调用函数 xTimerStart()的结果和 xTimerReset()一样。此函数是个宏,真正执行的是函数 xTimerGenericCommand。

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ) 

参数:
xTimer: 要开启的软件定时器的句柄。
xTicksToWait: 设置阻塞时间,调用函数 xTimerStart()开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_START 命令,既然是向队列发送消息,那肯
定会涉及到入队阻塞时间的设置。
返回值:
pdPASS: 软件定时器开启成功,其实就是命令发送成功。
pdFAIL: 软件定时器开启失败,命令发送失败。

4、函数 xTimerStartFromISR()

此函数是函数 xTimerStart()的中断版本,用在中断服务函数中,此函数是一个宏,真正执行的是函数 xTimerGenericCommand()

BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,  BaseType_t * pxHigherPriorityTaskWoken ); 

参数:
xTimer: 要开启的软件定时器的句柄。
pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS: 软件定时器开启成功,其实就是命令发送成功。
pdFAIL: 软件定时器开启失败,命令发送失败。

在这里插入图片描述

5、函数 xTimerStop()

此函数用于停止一个软件定时器,此函数用于任务中,不能用在中断服务函数中!此函数是一个宏,真正调用的是函数 xTimerGenericCommand()

BaseType_t xTimerStop ( TimerHandle_t xTimer, TickType_t xTicksToWait ) 

参数:
xTimer: 要停止的软件定时器的句柄。
xTicksToWait: 设置阻塞时间,调用函数 xTimerStop()停止软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_STOP 命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。
返回值:
pdPASS: 软件定时器停止成功,其实就是命令发送成功。
pdFAIL: 软件定时器停止失败,命令发送失败

6、函数 xTimerStopFromISR()

此函数是 xTimerStop()的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数 xTimerGenericCommand()。

BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, BaseType_t * pxHigherPriorityTaskWoken ); 

参数:
xTimer: 要停止的软件定时器句柄。
pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS: 软件定时器停止成功,其实就是命令发送成功。
pdFAIL: 软件定时器停止失败,命令发送失败。

三、定时器实验演示

3.1 实验需求

本实验用四个按键进行周期定时器和单次定时器的开启和停止控制

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "semphr.h"
#include "string.h"
#include "timers.h"


//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);





#define TIME_TASK_PRIO		4
//任务堆栈大小	
#define TIME_STK_SIZE 		50  
//任务句柄
TaskHandle_t TIMETask_Handler;
//任务函数
void time_task(void *pvParameters);


TimerHandle_t AutoReloadTimer_Handler;  //周期定时器句柄
TimerHandle_t OneShotTimer_Handler; //单次定时器句柄

void AutoReloadCallback( TimerHandle_t xTimer ); //周期定时器函数调用
void OneShotCallback( TimerHandle_t xTimer );  //单次定时器函数调用


int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_GPIO_INIT();          //按键初始化
	 
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	
	//周期定时器
		AutoReloadTimer_Handler = xTimerCreate( (const char *)  "AutoReloadTime", /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                                    (TickType_t) 1000,
                                    ( UBaseType_t) pdTRUE,  //周期
                                    (void * )1,
                                    (TimerCallbackFunction_t)AutoReloadCallback );
	
	//单次定时器
		OneShotTimer_Handler = xTimerCreate( (const char *)  "OneShotTime", /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                                    (TickType_t) 2000,
                                    ( UBaseType_t) pdFALSE,  //周期
                                    (void * )2,
                                    (TimerCallbackFunction_t)OneShotCallback );
    //定时器控制任务
    xTaskCreate((TaskFunction_t )time_task,     	
                (const char*    )"time_task",   	
                (uint16_t       )TIME_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TIME_TASK_PRIO,	
                (TaskHandle_t*  )&TIMETask_Handler);     	
	
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//定时器控制函数
void time_task(void *pvParameters)
{
	u8 keyvalue = 0;
	BaseType_t err;
	while(1)
    {
      
			keyvalue = KEY_Scan();
			switch(keyvalue)
			{
				case 1:
					err = xTimerStart(AutoReloadTimer_Handler,0);
				  if(err == pdFAIL)
					{
						printf("AutoReloadTimer Start Failed\r\n");
					}
					else
					{
						printf("AutoReloadTimer Start success\r\n");
					}
					break;     //开启周期定时器
				case 2:
					
					err = xTimerStop(AutoReloadTimer_Handler,0);
				  if(err == pdFAIL)
					{
						printf("AutoReloadTimer Stop Failed\r\n");
					}
					else{
						printf("AutoReloadTimer Stop success\r\n");
					}
					break;     //关闭周期定时器
				case 3:
					err = xTimerStart(OneShotTimer_Handler,0);  //开启单次定时器
				  if(err == pdFAIL)
					{
						printf("OneShot Start Failed\r\n");
					}
					else
					{
						printf("OneShot Start success\r\n");
					}
					break;     
				
				    
				case 4:
					err = xTimerStop(OneShotTimer_Handler,0);//关闭单次定时器
				  if(err == pdFAIL)
					{
						printf("OneShot Stop Failed\r\n");
					}
					else{
						printf("OneShot Stop success\r\n");
					}
				
					break;    
			}
      vTaskDelay(10);
			
    }
}   

//周期定时器回调函数
void AutoReloadCallback( TimerHandle_t xTimer )
{
	static u8 count = 0;
	count++;
	printf("AutoReloadTimer running = %d timers\r\n",count);
}


//d单次定时器回调函数
void OneShotCallback( TimerHandle_t xTimer )
{
		static u8 count = 0;
		count++;
	printf("OneShot running = %d timers\r\n",count);
}


实验结果在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值