STM32第二十一课:FreeRTOS事件组&软件定时器

目录


一、事件组

本质上是任务同步,但比二值信号量优秀的是可以一对多。

我的理解:事件组就是标志位的集合,将多个标志位放到一个集合里。

事件组中的事件位数(或标志数)的多少取决于 configUSE_16_BIT_TICKS or configTICK_TYPE_WIDTH_IN_BITS 是否 用于控制 TickType_t 的类型:

如果 configUSE_16_BIT_TICKS 设置为 1,则事件组内实现的位数(或标志数)为 8; 如果 configUSE_16_BIT_TICKS 设置为 0,则为 24。

如果 configTICK_TYPE_WIDTH_IN_BITS 设置为 TICK_TYPE_WIDTH_16_BITS,则事件组内实现的位数(或标志数)为 8; 如果 configTICK_TYPE_WIDTH_IN_BITS 设置为 TICK_TYPE_WIDTH_32_BITS,则为 24 ;如果 configTICK_TYPE_WIDTH_IN_BITS 设置为 TICK_TYPE_WIDTH_64_BITS,则为 56。

STM32中通常设置24个时间位即可。

1.事件组创建

先添加头文件

c 复制代码
#include "event_groups.h"

创建一个时间组句柄

c 复制代码
/********************事件组句柄***********************/
EventGroupHandle_t Event;

最后用上面创建的句柄进行承接创建。

c 复制代码
Event = xEventGroupCreate();

此时,我们就获得了一个具有24事件位的事件组。

创建完成时,事件组的每位都为0。

2.事件组置位

当发生特殊事件(数据传输完成,解析完成等。。),此时我们就可以使用事件组。让时间组的一位进行置位。

事件组置位函数有两个:

使用环境 置位函数
中断函数中 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
中断函数中 xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken )

参数1:想要置位的事件组是哪个。

参数2:想要置的是哪一位,比如想要置第2位就填0x04(100)

虽然函数不同,但参数基本是一样的。只不过在中断中多一个参数3,参数3填 pdTRUE会开启高优先级事件触发提醒。一般我们不需要,直接填NULL即可。

3.事件组等待

EventBits_t xEventGroupWaitBits(

    const EventGroupHandle_t xEventGroup, /* 事件标志组句柄 */
    const EventBits_t uxBitsToWaitFor, /* 等待被设置的事件标志位 */
    const BaseType_t xClearOnExit, /* 选择是否清零被置位的事件标志位 */
    const BaseType_t xWaitForAllBits, /* 选择是否等待所有标
    TickType_t xTicksToWait ); /* 设置等待时间 */
    )

若设置超时时间:在超时时间中会阻塞等待,超时时会返回当前事件组的值,但不会清0标志位(无论是否设置清0标志位)

设置清0标志位,成功获取时会清0标志位。

若设置超时时间为:portMAX_DELAY,此时该函数就会死等,成功时返回。通常都是portMAX_DELAY

参数4,有pdTRUE和pdFALSE两种状态。

如果这个参数设置为 pdTRUE,要等待第 2 个参数 uxBitsToWaitFor 所指定的标志位全部被置 1,函数才可以返回。当然,超出了在参数xTicksToWait 设置的溢出时间也是会返回的。

如果这个参数设置为 pdFALSE,第 2 个参数uxBitsToWaitFor 所指定的任何标志位被置 1,函数都会返回,超出溢出时间也会返回,

c 复制代码
Ret = xEventGroupWaitBits(Event,0x07,pdTRUE,pdFALSE,portMAX_DELAY);

二、软件定时器

软件定时器(或者只是"定时器" )能够让函数在 未来的设定时间执行。 由定时器执行的函数称为定时器的回调函数 。 从定时器启动到其回调函数执行之间的时间被称为定时器的周期。 简而言之, 当定时器的周期到期时,定时器的回调函数会被执行。

其实软件定时器就是设置了一个周期,周期结束了就会调用回调函数。

注意:回调函数中不要有阻塞

1.软件定时器创建

添加头文件

c 复制代码
#include "times.h"

创建句柄

c 复制代码
TimerHandle_t Timer1;//软件定时器

定时器任务创建

c 复制代码
	Timer1 = xTimerCreate("Timer1",1000,pdTRUE,(void *)1,vTimerCallback);

参数1:pcTimerName:定时器名字

参数2:xTimerPeriodInTicks:定时周期

参数3:uxAutoReload:

pdTRUE:周期模式

pdFALSE:单次模式

参数4:pvTimerID:定时器ID,用于多个定时器共用同一个回调函数,判断那个定时器超时。

2.软件定时器执行

调用函数:

c 复制代码
void vTimerCallback(TimerHandle_t xTimer)
{
	printf("定时器ID:%d\r\n",(u8)pvTimerGetTimerID(xTimer));
	Led_Waterfall();
}

定时器开始执行

c 复制代码
	xTimerStart(Timer1,1);

参数1:表示要启动的定时器的句柄。

参数2:表示在启动定时器之前等待的节拍数。如果希望在启动定时器之前有一个延迟,可以设置一个等待时间。

3.例程代码

main.c

c 复制代码
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "delay.h"
#include "string.h"
#include "pwm.h"
#include "adc.h"
#include "su03t.h"
#include "dht11.h"
#include "kqm.h"
#include "usart.h"
#include "key.h"
//使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h"
#include "FreeRtos.h"
#include "task.h"
#include "semphr.h"
#include "event_groups.h"
#include "queue.h"
#include "time.h"
EventGroupHandle_t Events;
char D_time[20];
TaskHandle_t liushui_Task;
TimerHandle_t Timer1;//软件定时器

void liu_Task(void *p)
{
	Led_Waterfall();
}
void vTimerCallback(TimerHandle_t xTimer)
{
	printf("定时器ID:%d\r\n",(u8)pvTimerGetTimerID(xTimer));
	Led_Waterfall();
}
int main()
{
	Led_Init();
	Usart1_Config();//初始化串口1
	BaseType_t Ret = pdPASS;
//	Ret = xTaskCreate(liu_Task, //创建任务的任务函数名
//                    "liu_Task",//任务名字
//                    100,//任务栈深度。32位单片机*4
//                    NULL,//创建任务时传递参数,没有就给NULL
//                    1,//任务优先级
//										&liushui_Task);//任务的句柄,用于后边删除,挂起任务
//	if(Ret == pdPASS){
//		printf("流水灯任务创建完成\r\n");
//	}
	Timer1 = xTimerCreate("Timer1",1000,pdTRUE,(void *)1,vTimerCallback);
	xTimerStart(Timer1,1);
	printf("开始调度!\r\n");
	vTaskStartScheduler();
	while(1)
	{
		
	}
}

void vApplicationStackOverflowHook( TaskHandle_t xTask,char *pcTaskName )
{
	printf("任务:%s->栈溢出\r\n",pcTaskName);
	printf("任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(xTask));
	while(1)//栈溢出时卡死到钩子函数中
	{}
}
相关推荐
陌小呆^O^8 分钟前
Cmakelist.txt之Linux-redis配置
linux·运维·redis
张彦峰ZYF16 分钟前
接口性能优化宝典:解决性能瓶颈的策略与实践
java·redis·分布式·后端·算法·性能优化·架构
没有余地 EliasJie42 分钟前
深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录
人工智能·嵌入式硬件·深度学习
冧轩在努力1 小时前
【redis】哈希类型详解
数据库·redis·哈希算法
嵌入式大圣1 小时前
单片机在电路板中的应用
单片机·嵌入式硬件
小A1593 小时前
STM32完全学习——使用标准库完成PWM输出
stm32·单片机·学习
小A1593 小时前
STM32完全学习——使用标准库完成定时器中断
stm32·单片机·学习
美式小田3 小时前
单片机学习笔记 10. 中断系统(理论)
笔记·单片机·嵌入式硬件·学习
我不是码农 嘤嘤嘤3 小时前
单片机GPIO的8种工作模式
单片机·嵌入式硬件
相醉为友4 小时前
006 单片机嵌入式中的C语言与代码风格规范——常识
c语言·单片机·嵌入式硬件