13.STM32freeRTOS---软件定时器


前言

定时器可以说是每个MCU都有的外设,除了有最基础的定时的功能,还有些很强大的功能–PWM,输出捕获等功能。MCU自带的定时器属于硬件定时器,不同MCU的硬件定时器数量不同。freeRTOS提供了软件定时器,软件定时器精度没有硬件定时器的精度高。但是对于普通的精度要求的周期性处理的任务来说足够了。
当MCU的硬件定时器不够的时候就可以考虑freeRTOS 的软件定时器。


一、软件定时器介绍

软件定时器可以定时一段时间,当定时的时间到达之后就执行指定的功能函数,被定时器调用的这个功能叫做回调函数。回调函数的两次执行间隔就是定时器的定时周期,简单地说,当定时器的定时时间到了以后就会执行回调函数。

关于回调函数的注意事项:
软件定时器的回调函数在定时器服务中执行,所以一定不能在回调函数中调用任何会阻塞任务的API!!!比如,定时器回调函数中绝对不要用 vTaskDelay(),vTaskDelayUntil(),以及一些访问队列或者信号量的非零阻塞时间的API!!

二、定时器服务/Daemon 任务

1. 定时器服务任务 与 队列

在这里插入图片描述
在这里插入图片描述

2. 定时器相关配置

定时器服务任务 与 定时器命令队列
在这里插入图片描述

3. 单次定时器 与 周期定时器

在这里插入图片描述

4. 复位软件定时器

有时候定时器正在运行的时候需要复位软件定时器,复位软件定时器会重新计算走起到达的时间点,这个新的时间点是相对于杜威定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

5. 创建软件定时器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 开启软件定时器

在这里插入图片描述
在这里插入图片描述
中断版本的传参和之前的一样!!!

7. 停止软件定时器

在这里插入图片描述
参数与之前的参数一致!!

8. 实验

#include "sys.h"
#include "usart.h"
#include "led.h"
#include "delay.h"



//#include <string.h>


#include "FreeRTOS.h"
#include "semphr.h"//信号量的头文件
#include "task.h"
#include "timers.h"

/*
	本次实验:学习freeRTOS软件定时器的使用,包含软件定时器的创建,开启和停止
	
	start_task:开始创建任务
	task1:控制两个软件定时器的开启与停止
	
	------------
	
	注意:对于使用软件定时器需要的配置:
	configUSE_TIMERS  1
	configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        //软件定时器优先级,也就是 32-1
	configTIMER_QUEUE_LENGTH		        	5                               //软件定时器队列长度
	configTIMER_TASK_STACK_DEPTH	        (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小
	
	------------
	
	本实验除了创建两个任务,还需要创建两个软件定时器。分别为单次定时器和周期定时器。
	单次定时器的定时周期:2000个时钟周期(2s)
	周期定时器的定时周期:1000个时钟周期(1s)
	
*/
#define start_task_size 52
#define start_task_pro   1
TaskHandle_t startTask_handler;
void start_task(void *pram);

#define task1_size 52
#define task1_pro  2
TaskHandle_t Task1_handler;
void task1(void *pram);


//软件定时器的句柄
TimerHandle_t  autoReloadTimer_handle;//周期定时器句柄
TimerHandle_t  oneReloadTimer_handle;//单次定时器句柄

//定时器的回调函数(注意这里的传参,传的是 定时器句柄 )
void autoReloadCalLback(TimerHandle_t xTimer);//周期定时器回调函数
void oneReloadCallback(TimerHandle_t xTimer);//单次定时器回调函数


int main(void)
{
	
	delay_init();									//延时函数初始化	  
	uart_init(115200);								//初始化串口
	LED_Init(); 									//初始化LED

	xTaskCreate(
						(TaskFunction_t )start_task,
                        (const char * 		) "start_task",     
                        (uint16_t		)start_task_size ,
                        (void *  		)NULL,
                        (UBaseType_t	) start_task_pro,
                        (TaskHandle_t * )startTask_handler );

    vTaskStartScheduler();//开始任务调度

}

/*88888888888888888888888888888888888888888888888888888888888888888888*/
void start_task(void *pram)
{
	
	taskENTER_CRITICAL();
	//BaseType_t Return;
	
	
	//创建周期定时器,定时周期为1000个时钟周期(1s)
	autoReloadTimer_handle = xTimerCreate( (const char *) "autoReloadTimer", /* 软件定时器名称 */
										   (TickType_t ) 1000,				 /* 软件定时器周期(时钟周期为单位) */
										   (UBaseType_t) pdTRUE,			 /* 周期模式--->pdTRUE,单次模式--->pdFALSE */
										   (void *) 1,						 /* 定时器ID */
										   (TimerCallbackFunction_t) autoReloadCalLback);/* 定时器回调函数 */
	
	//创建单次定时器,定时周期为2000个时钟周期(2s)
	oneReloadTimer_handle = xTimerCreate( (const char *) "oneReloadTimer",   /* 软件定时器名称 */
										   (TickType_t ) 2000,				 /* 软件定时器周期(时钟周期为单位) */
										   (UBaseType_t) pdFALSE,			 /* 周期模式--->pdTRUE,单次模式--->pdFALSE */
										   (void *) 2,						 /* 定时器ID */
										   (TimerCallbackFunction_t) oneReloadCallback);/* 定时器回调函数 */								
	
	
	
	//创建任务1
	xTaskCreate(
						(TaskFunction_t ) task1,
                        (const char * 	) "task1",     
                        (uint16_t		) task1_size ,
                        (void *  		) NULL,
                        (UBaseType_t	) task1_pro,
                        (TaskHandle_t * ) Task1_handler);
						
						
	vTaskDelete(NULL);

	taskEXIT_CRITICAL();

}

//task1:控制两个软件定时器的开启与停止
void task1(void *pram)
{
	
	

}
void autoReloadCalLback(TimerHandle_t xTimer)
{

	/*不要调用任何具有阻塞性质的API*/

}
void oneReloadCallback(TimerHandle_t xTimer)
{

	/*不要调用任何具有阻塞性质的API*/


}


我这里没有把程序写完,对于task1函数,里面就通过一个触发信号
(比如按键)来实现软件定时器的开启与停止。具体可以自己自由发挥。


总结

定时器 定时时间一到就会调用回调函数。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是对这段代码的逐行注释: ``` Swtmr1_Handle = xTimerCreate((const char*)"AutoReloadTimer", (TickType_t)1, /* 定时器周期 1(tick) */ (UBaseType_t)pdTRUE, /* 周期模式 */ (void*)1, /* 为每个计时器分配一个索引的唯一 ID */ (TimerCallbackFunction_t)Swtmr1_Callback); ``` 这段代码创建了一个名称为"AutoReloadTimer"的周期定时器,并将其句柄保存到Swtmr1_Handle变量中。定时器的周期为1个tick,即系统时钟的一个时间单位。pdTRUE表示定时器以周期模式运行,即在定时器到期后会自动重新启动。void*类型的参数1用于为每个计时器分配一个唯一的ID,TimerCallbackFunction_t类型的参数Swtmr1_Callback是定时器到期时的回调函数。 ``` if (Swtmr1_Handle != NULL) { /*************************************************************** * xTicksToWait: 如果在调用 xTimerStart() 时队列已满,则以 tick 为单位指定调用任务应保持 * 在 Blocked(阻塞)状态以等待 start 命令成功发送到 timer 命令队列的时间。 * 如果在启动调度程序之前调用 xTimerStart(),则忽略 xTicksToWait。在这里设置等待时间为 0 ***************************************************************/ xTimerStart(Swtmr1_Handle, 0); // 开启周期定时器 } ``` 如果定时器成功创建,则调用xTimerStart()函数启动定时器。xTicksToWait参数指定任务在定时器命令队列已满时应该等待多长时间。在这里,等待时间设置为0,表示如果队列已满,任务将被立即阻塞,直到定时器命令发送成功为止。 ``` // 删除当前任务 vTaskDelete(StartTask_Handler); // 退出临界状态 taskEXIT_CRITICAL(); ``` 这段代码删除当前任务,并退出临界状态。删除任务会释放任务占用的内存和资源,从而避免内存泄漏和资源浪费。退出临界状态会允许其他任务和中断服务例程访问系统资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值