基本概念
软件定时器类似于单片机的定时中断,但是精度和优先级不如硬件定时器。支持单次模式(只执行一次)和周期模式。精度为x个tick
注意事项
函数接口讲解
xTimerCreate()?软件定时器创建函数
xTimerStart()软件定时器启动函数
软件定时器在创建完成的时候是处于休眠状态的,需要用 FreeRTOS 的相关函数将软件定时器活动起来,而 xTimerStart()函数就是可以让处于休眠的定时器开始工作。
xTimerStop()软件定时器停止函数 xTimerStop() 用于停止一个已经启动的软件定时器, 该函数的实现也是通过“定时器命令队列”发送一个停止命令给软件定时器任务,从而唤醒软件定时器任务去将定时器停止。
xTimerDelete()?软件定时器删除函数
?xTimerDelete()用于删除一个已经被创建成功的软件定时器, 删除之后就无法使用该定 时器, 并且定时器相应的资源也会被系统回收释放。
软件定时器实验
?软件定时器实验:使用软件定时器设置定时任务,当定时器到了事件就执行回调函数,回调函数相当于定时器中断函数(软件定义,事件没有硬件定时器精确),回调函数中的内容要尽可能精简,不能出现阻塞和死循环。 实验现象:每隔一秒循环执行Swtmr1_Callback() 第五秒执行Swtmr2_Callback(),只执行一次;
main.c 如下
#include "stm32f10x.h"
#include "EXC_Gpio.h"
#include "EXC_Usart.h"
#include "EXC_Led.h"
#include "EXC_Key.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "event_groups.h"
/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为NULL。
*/
/* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle;
/********************************** 内核对象句柄 *********************************/
/*
* 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
* 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
* 们就可以通过这个句柄操作这些内核对象。
*
* 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
* 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
* 来完成的
*
*/
static TimerHandle_t Swtmr1_Handle =NULL;/*软件定时器句柄*/
static TimerHandle_t Swtmr2_Handle =NULL;/*软件定时器句柄*/
/************************** 宏定义 *********************************/
/*
* 当我们在写应用程序的时候,可能需要用到一些宏定义。
*/
/*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */
static void Swtmr1_Callback(void* pvParameters);/*Swtmr1_Task任务实现 */
static void Swtmr2_Callback(void* pvParameters);/* Swtmr1_Task任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 */
/*****************************************************************
* @brief 主函数
* @param 无
* @retval 无
* @note 第一步:开发板硬件初始化
第二步:创建APP应用任务
第三步:启动FreeRTOS,开始多任务调度
****************************************************************/
int main(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
BSP_Init();
/* 创建 AppTaskCreate 任务 */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, //任务函数
(const char* )"AppTaskCreate", //任务名称
(uint32_t )256, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )3, //任务优先级
(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)
{
/***************************************************************
*xTicksTowait:如果在调用xTimerstart()时队列已满,则以tick 为单位指定调
用任务应保持在Blocked(阻塞)状态以等待start命令成功发送到 timer命令队列的时间。
*如果在启动调度程序之前调用xTimerstart(),则忽略xTicksTowait。在这里设置等待时间为0
***************************************************************/
xTimerStart(Swtmr1_Handle,0); //开启周期定时器
}
Swtmr2_Handle=xTimerCreate((const char* ) "AutoReloadTimer",
(TickType_t) 5000,/*定时器周期1000(tick)*/
(UBaseType_t)pdFALSE,/*单次模式*/
(void*)1,/*为每个计时器分配一个索引的唯一ID */
( TimerCallbackFunction_t)Swtmr2_Callback);
if(Swtmr2_Handle != NULL)
{
/***************************************************************
*xTicksTowait:如果在调用xTimerstart()时队列已满,则以tick 为单位指定调
用任务应保持在Blocked(阻塞)状态以等待start命令成功发送到 timer命令队列的时间。
*如果在启动调度程序之前调用xTimerstart(),则忽略xTicksTowait。在这里设置等待时间为0
***************************************************************/
xTimerStart(Swtmr2_Handle,0); //开启周期定时器
}
vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
/**********************************************************************
* @ 函数名 : Swtmr1_Callback
* @ 功能说明: Swtmr1_Callback 任务主体
* @ 参数 :
* @ 返回值 : 无
* @ Note : 定时器回调函数因该尽可能短,不能出现阻塞和死循环
********************************************************************/
static void Swtmr1_Callback(void* parameter)
{
static int TmrCb_Count1;
TickType_t tick_num1;
TmrCb_Count1++; /* 每回调一次加一 */
tick_num1 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */
LED1_TOGGLE;
printf("Swtmr1_Callback 函数执行 %d 次\r\n", TmrCb_Count1);
printf("滴答定时器数值=%d\r\n", tick_num1);
}
/**********************************************************************
* @ 函数名 : Swtmr2_Callback
* @ 功能说明: Swtmr2_Callback 任务主体
* @ 参数 :
* @ 返回值 : 无
* @ Note : 定时器回调函数因该尽可能短,不能出现阻塞和死循环
********************************************************************/
static void Swtmr2_Callback(void* parameter)
{
static int TmrCb_Count2;
TickType_t tick_num1;
TmrCb_Count2++; /* 每回调一次加一 */
tick_num1 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */
LED3Color_Set(LEDRED);
printf("Swtmr2_Callback 函数执行 %d 次\r\n", TmrCb_Count2);
printf("滴答定时器数值=%d\r\n", tick_num1);
}
/***********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void BSP_Init(void)
{
/*
* STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
* 都统一用这个优先级分组,千万不要再分组,切忌。
*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
USART_init(SYSTEM_UART,115200,1);
printf("串口初始化成功\r\n");
/* LED 初始化 */
LED3Color_Init(LEDBLUE);
Key_Init(K1);
Key_Init(K2);
ILI9341_Init();
LCD_SetFont(&Font8x16);
LCD_SetColors(RED,BLACK);
ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
ILI9341_DispString_EN(50,0,"Hello world!");
}
/********************************END OF FILE****************************/
|