STM32-FreeRTOS操作系统-软件定时器

引言

在嵌入式系统开发中,STM32微控制器与FreeRTOS操作系统的结合应用极为广泛。其中,件定时器作为FreeRTOS的重要功能模块,为实现精准任务调度与时间管理提供了有力支持,本文将对其作简要介绍。

软件定时器定义

软件定时器是 FreeRTOS 提供的一种功能模块,它允许用户在指定的时间间隔后执行特定的回调函数。与任务不同,软件定时器不具有独立的执行上下文,也不占用系统资源来维持运行状态。任务是 FreeRTOS 的核心调度单元,具有独立的栈空间和优先级,可以主动运行和被调度。而软件定时器仅在设定的时间点触发回调,依赖任务或其他机制来执行实际操作,更适合用于简单的定时需求,如周期性检查或延迟操作,相比任务更加轻量级。

简单来说软件定时器就是一个简单的定时任务,而且不需要占用大量内存。设置的优先级通常比较低,这样才不会打断正在运行的任务。

软件定时器

首先是定义软件定时器的句柄,并给其赋初值为NULL。这里我创建两个软件定时器。

TimerHandle_t Timer1_Handle =NULL; //软件定时器句柄1

TimerHandle_t Timer2_Handle =NULL; //软件定时器句柄2

xTimerCreate函数

该函数的原型为:

TimerHandle_t xTimerCreate(

const char * const pcTimerName, // 定时器名称(调试用)

const TickType_t xTimerPeriod, // 定时器周期(以 tick 为单位)

const UBaseType_t uxAutoReload, // 是否自动重载(pdTRUE/pdFALSE)

void * const pvTimerID, // 定时器 ID(回调函数中识别用)

TimerCallbackFunction_t pxCallbackFunction // 回调函数

);

可以看见,该函数是一个含参数且有返回值的函数。下面分析一下各个参数的作用:

pcTimerName:顾名思义,定时器名称,前面是const char*,表示常量字符串指针。

xTimerPeriod:定时周期,一般情况下都是以Tick系统节拍为单位。

uxAutoReload:是否自动重载,pdFALSE(0)表示的是单次定时器,到期后自动停止,不再触发,pdTRUE(1)表示的是周期定时器,到期后自动重置,持续触发。

pvTimerID:顾名思义,定时器ID,可自定义,主要是用来区分多个定时器

pxCallbackFunction:定时器到期是调用的函数。必要时应提前声明!

使用xTimerCreate函数

然后在临界区内创建软件定时器,并将创建返回的句柄赋值给刚刚创建的空句柄。

//创建定时器1

Timer1_Handle=xTimerCreate("AutoReloadTimer",1000,pdTRUE,(void*)1,Timer1_Callback);

//创建定时器2

Timer2_Handle=xTimerCreate("OneShotTimer",5000,pdFALSE,(void*)2,Timer2_Callback);

接着开启定时器:

if(Timer1_Handle != NULL)

{

xTimerStart(Timer1_Handle,0); //开启定时器1

}

if(Timer2_Handle != NULL)

{

xTimerStart(Timer2_Handle,0); //开启定时器2

}

实现回调函数

前面也说过了,必要时最好先声明该回调函数。

//定时器1回调函数

//软件定时器不要调用阻塞函数,也不要进行死循环,应快进快出

void Timer1_Callback(void* parameter)

{

LED=!LED;

}

//定时器2回调函数

//软件定时器不要调用阻塞函数,也不要进行死循环,应快进快出

void Timer2_Callback(void* parameter)

{

// LED=!LED;

}

当然,我这个是单独给每个定时器创建的函数,就用不到刚刚的定时器ID标识符了。如果需要更简便一点可以只用一个回调函数,然后在里面根据不同的ID标识符设置相应的逻辑。

void vUnifiedCallback(TimerHandle_t xTimer)

{

uint32_t id = (uint32_t)pvTimerGetTimerID(xTimer);

switch(id)

{

//在switch语句中根据不同的ID标识符做出对应的逻辑

}

}

示例代码

cs 复制代码
#include "myfreertos.h"
#include "FreeRTOS.h"
#include "event_groups.h"
#include "Timers.h"
#include "semphr.h"
#include "Timers.h"
#include "queue.h"
#include "Usart.h"
#include "Task.h"
#include "led.h"
#include "key.h"


TaskHandle_t MyTaskHandler;//主任务句柄

TaskHandle_t LED_TASK_Handler;//LED任务句柄

TaskHandle_t KEY_TASK_Handler;       //LED任务句柄

void MyTask(void *pvParameters);     //声明启动函数

void LED_TASK(void *pvParameters);   //声明LED任务函数

void KEY_TASK(void *pvParameters);   //声明KEY任务函数

TimerHandle_t Timer1_Handle =NULL;   //软件定时器句柄1

TimerHandle_t Timer2_Handle =NULL;   //软件定时器句柄2

static void Timer1_Callback(void* parameter);  //软件定时器1回调函数
static void Timer2_Callback(void* parameter);  //软件定时器2回调函数


void Start_Task(void)
{
	xTaskCreate(MyTask,"MyTask",128,NULL,1,&MyTaskHandler);//动态方法创建任务
	vTaskStartScheduler();//启动任务调动		
}

void MyTask(void *pvParameters)           //开始创建任务函数
{	
	taskENTER_CRITICAL();           //进入临界区
	
	//创建定时器1
	Timer1_Handle=xTimerCreate("AutoReloadTimer",1000,pdTRUE,(void*)1,Timer1_Callback);
	
	//创建定时器2
	Timer2_Handle=xTimerCreate("OneShotTimer",5000,pdFALSE,(void*)2,Timer2_Callback);
	
	xTaskCreate(LED_TASK,"LED_TASK",50,NULL,3,&LED_TASK_Handler);//动态方法创建LED任务
	
	xTaskCreate(KEY_TASK,"KEY_TASK",50,NULL,4,&KEY_TASK_Handler);//动态方法创建LED任务

  vTaskDelete(MyTaskHandler);    //删除开始任务
	
	if(Timer1_Handle != NULL) 
	{
		xTimerStart(Timer1_Handle,0);	//开启定时器1
	}
	
	if(Timer2_Handle != NULL) 
	{
		xTimerStart(Timer2_Handle,0);	//开启定时器2
	}
	
	taskEXIT_CRITICAL();           //退出临界区
}

void LED_TASK(void *pvParameters)
{
	while(1)
	{
			vTaskDelay(200);
	}
	
}

void KEY_TASK(void *pvParameters)
{
	while(1)
	{			
		  vTaskDelay(200);
	}
	
}

//定时器1回调函数
//软件定时器不要调用阻塞函数,也不要进行死循环,应快进快出
void Timer1_Callback(void* parameter)
{		
	LED=!LED;
}

//定时器2回调函数
//软件定时器不要调用阻塞函数,也不要进行死循环,应快进快出
void Timer2_Callback(void* parameter)
{		
//	LED=!LED;
}

这个代码就是创建两个软件定时器和两个任务。然后在任务阻塞的时候调用软件定时器,然后进入定时器的回调函数。

总结

以上仅是本人的观点,如有不足,欢迎指出!

相关推荐
波力海苔夹心脆6752 小时前
C# 序列化与反序列化详解:System.Text.Json、Newtonsoft.Json、XmlSerializer 用法、特性选项与安全实践
经验分享·后端·c#·json·.net
国科安芯2 小时前
断电也隔离、听得真:ASL3159S 单通道 SPDT 模拟开关的“断电保护 + 音频保真“账
单片机·嵌入式硬件·安全·商业航天·抗辐射
自小吃多2 小时前
【Verilog/FPGA】存储器(数组)
嵌入式硬件·fpga开发
szxinmai主板定制专家2 小时前
RK3588+FPGA异构架构|高速数据采集+边缘AI落地应用全解析
人工智能·嵌入式硬件·fpga开发·架构·zynq
jianqiang.xue3 小时前
【CStackGUI 实战】深色主题终端:app.dark 默认深色 + 顶层命名样式表 + 运行时切换
单片机·嵌入式·cstackgui·c语言gui·可视化拖拽
M78佐菲3 小时前
ARM学习笔记(11)
linux·arm开发·笔记·嵌入式硬件·学习
M78佐菲3 小时前
ARM学习笔记(10)
linux·arm开发·笔记·嵌入式硬件·学习
小程序设计3 小时前
基于STM32的智慧厨房多参数安全监测与预警系统设计
stm32·嵌入式硬件·安全
新晨单片机设计3 小时前
S008C-基于STM32单片机无线抢答器【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·无线抢答器
Zw-awa4 小时前
Delay_us 与 Delay_ms:用 SysTick 做一把可靠的时间尺
stm32