STM32---FreeRTOS任务通知

一、简介

1、任务通知简介

任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值。

使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!

使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"

2、任务通知值的更新方式

不覆盖接受任务的通知值

覆盖接受任务的通知值

更新接受任务通知值的一个或多个bit

增加接受任务的通知值

只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!

3、任务通知的优势和劣势

4、任务通知值和通知状态

任务都有一个结构体:任务控制块TCB,它里边有两个结构体成员变量:

一个是 uint32_t 类型:用来表示通知值

一个是 uint8_t 类型:用来表示通知状态

1、任务通知值的更新方式有多种类型:

2、任务通知状态:

二、任务通知相关API函数介绍

三、实验

1、模拟二值信号量

main.c

cs 复制代码
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "freertos_demo.h"
#include "Delay.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "Key.h"

 
 int main(void)
 {	
	 
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4 
	 uart_init(115200);	 
	 delay_init();
	 Key_Init();
	 LED_Init();
	 
	    // 创建任务
   FrrrRTOS_Demo();
		 	  
}

freertos_demo.c

cs 复制代码
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"

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


//任务优先级
#define TASK1_PRIO							2
//任务堆栈大小	
#define TASK1_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
 
//任务优先级
#define TASK2_PRIO							3
//任务堆栈大小	
#define TASK2_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);







/******************************************************************任务函数****************************************************/



void FrrrRTOS_Demo(void)
{
			 //创建开始任务
		xTaskCreate((TaskFunction_t )start_task,            			//任务函数
                ( char*         )"start_task",          			//任务名称
                (uint16_t       )START_TASK_STACK_SIZE, 			//任务堆栈大小
                (void*          )NULL,                  			//传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       			//任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   			//任务句柄 
	  // 启动任务调度
		vTaskStartScheduler();
	 
}


 void start_task(void *pvParameters)
{
	  taskENTER_CRITICAL();           //进入临界区
	


    //创建1任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STACK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler); 
    //创建2任务
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STACK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler);    
								
  
		
    vTaskDelete(NULL); 							//删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


//1 发送任务通知值
void task1(void *pvParameters)
{
	uint8_t				key = 0;
	
	while(1)
	{

		key = Key_GetNum();
		if(key == 2)
		{
			printf("任务通知模拟二值信号释放\r\n");
			xTaskNotifyGive(Task2_Handler);
		}
		
		vTaskDelay(10);
	}
}


// 任务2 接受任务通知值
void task2(void *pvParameters)
{
		uint32_t				rev = 0;
	
    // 任务主循环
    while (1)
    {
			rev = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
			if(rev != 0)
			{
				printf("接受任务通知成功,模拟获取二值信号量\r\n");
			}
			
		}
}

key.c

cs 复制代码
#include "stm32f10x.h"                  // Device header
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "Delay.h"
 
/**
  * 函    数:按键初始化
  * 参    数:无
  * 返 回 值:无
	* 按键:PB4/PB12/PB14
  */
void Key_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
 
	/*GPIO初始化*/
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_4 | GPIO_Pin_12 | GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						
}
 
 
/**
  * 函    数:按键获取键码
  * 参    数:无
  * 返 回 值:按下按键的键码值,范围:0~3,返回0代表没有按键按下
  * 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
  */
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;																				//定义变量,默认键码值为0
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0)			  //读PB4输入寄存器的状态,如果为0,则代表按键1按下
	{
		KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4);
		delay_xms(20);																					//延时消抖
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0);	//等待按键松手
		delay_xms(20);																					//延时消抖
		KeyNum = 1;																							//置键码为1
	}
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)			
	{
		KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
		delay_xms(20);											
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0);	
		delay_xms(20);									
		KeyNum = 2;											
	}
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)			
	{
		KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
		delay_xms(20);											
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0);	
		delay_xms(20);									
		KeyNum = 3;											
	}
	
	return KeyNum;																						//返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
 
 
 
 
 

1、实验解析

按下按键,模拟二值信号量的释放和接受;

2、模拟计算型信号量

freertos_demo.c

cs 复制代码
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"

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


//任务优先级
#define TASK1_PRIO							2
//任务堆栈大小	
#define TASK1_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
 
//任务优先级
#define TASK2_PRIO							3
//任务堆栈大小	
#define TASK2_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);







/******************************************************************任务函数****************************************************/



void FrrrRTOS_Demo(void)
{
			 //创建开始任务
		xTaskCreate((TaskFunction_t )start_task,            			//任务函数
                ( char*         )"start_task",          			//任务名称
                (uint16_t       )START_TASK_STACK_SIZE, 			//任务堆栈大小
                (void*          )NULL,                  			//传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       			//任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   			//任务句柄 
	  // 启动任务调度
		vTaskStartScheduler();
	 
}


 void start_task(void *pvParameters)
{
	  taskENTER_CRITICAL();           //进入临界区
	


    //创建1任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STACK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler); 
    //创建2任务
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STACK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler);    
								
  
		
    vTaskDelete(NULL); 							//删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


//1 发送任务通知值
void task1(void *pvParameters)
{
	uint8_t				key = 0;
	
	while(1)
	{

		key = Key_GetNum();
		if(key == 2)
		{
			printf("任务通知模拟二值信号释放\r\n");
			xTaskNotifyGive(Task2_Handler);
		}
		vTaskDelay(10);
	}
}


// 任务2 接受任务通知值
void task2(void *pvParameters)
{
		uint32_t				rev = 0;
	
    // 任务主循环
    while (1)
    {
			rev = ulTaskNotifyTake(pdFALSE,portMAX_DELAY);
			if(rev != 0)
			{
				printf("rev:%d\r\n",rev);
			}
			vTaskDelay(1000);
		}
}

1、实验解析

快速点击按键,模拟计数型信号量的接受和释放;

3、模拟信号邮箱实验

freertos_demo.c

cs 复制代码
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"

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


//任务优先级
#define TASK1_PRIO							2
//任务堆栈大小	
#define TASK1_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
 
//任务优先级
#define TASK2_PRIO							3
//任务堆栈大小	
#define TASK2_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);







/******************************************************************任务函数****************************************************/



void FrrrRTOS_Demo(void)
{
			 //创建开始任务
		xTaskCreate((TaskFunction_t )start_task,            			//任务函数
                ( char*         )"start_task",          			//任务名称
                (uint16_t       )START_TASK_STACK_SIZE, 			//任务堆栈大小
                (void*          )NULL,                  			//传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       			//任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   			//任务句柄 
	  // 启动任务调度
		vTaskStartScheduler();
	 
}


 void start_task(void *pvParameters)
{
	  taskENTER_CRITICAL();           //进入临界区
	


    //创建1任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STACK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler); 
    //创建2任务
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STACK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler);    
								
  
		
    vTaskDelete(NULL); 							//删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


//1 发送任务通知值
void task1(void *pvParameters)
{
	uint8_t				key = 0;
	
	while(1)
	{
		key = Key_GetNum();
		if((key != 0) && (Task2_Handler != NULL))
		{
				printf("任务通知模拟消息邮箱发送,发送的键值为:%d\r\n",key);
				xTaskNotify( Task2_Handler, key, eSetValueWithOverwrite );
				// 发送任务通知给任务2,使用 eSetValueWithOverwrite 模式
				// Task2_Handler: 任务2的句柄
				// key: 发送的值
				// eSetValueWithOverwrite: 覆盖模式,新的值会覆盖旧的值
		}
		vTaskDelay(10);
	}
}


// 任务2 接受任务通知值
void task2(void *pvParameters)
{
		uint32_t				rev = 0;
	
    // 任务主循环
    while (1)
    {
			xTaskNotifyWait(0,0xFFFFFFFF,&rev,portMAX_DELAY );
				// 等待任务通知,portMAX_DELAY 表示无限等待
        // 0: 不清除任何通知位
        // 0xFFFFFFFF: 接收所有通知值
        // &rev: 存储接收到的通知值
        // portMAX_DELAY: 无限等待,直到收到通知
			switch(rev){
				case 2:
				{
					printf("接收到的任务通知值为:%d\r\n",rev);
					LED1_Turn();
					break;
				}
				case 3:
				{
					printf("接收到的任务通知值为:%d\r\n",rev);
					LED2_Turn();
					break;
				}

			};
		}
}

1、实验解析

4、模拟时间标志组

freertosc_demo.c

cs 复制代码
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"

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


//任务优先级
#define TASK1_PRIO							2
//任务堆栈大小	
#define TASK1_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
 
//任务优先级
#define TASK2_PRIO							3
//任务堆栈大小	
#define TASK2_STACK_SIZE 				128  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);



 
#define		EVENTBIT0 	(1<<0)
#define		EVENTBIT1 	(1<<1)




/******************************************************************任务函数****************************************************/



void FrrrRTOS_Demo(void)
{
			 //创建开始任务
		xTaskCreate((TaskFunction_t )start_task,            			//任务函数
                ( char*         )"start_task",          			//任务名称
                (uint16_t       )START_TASK_STACK_SIZE, 			//任务堆栈大小
                (void*          )NULL,                  			//传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       			//任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   			//任务句柄 
	  // 启动任务调度
		vTaskStartScheduler();
	 
}


 void start_task(void *pvParameters)
{
	  taskENTER_CRITICAL();           //进入临界区
	


    //创建1任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STACK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler); 
    //创建2任务
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STACK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler);    
								
  
		
    vTaskDelete(NULL); 							//删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


//1 发送任务通知值
void task1(void *pvParameters)
{
	uint8_t				key = 0;
	
	while(1)
	{
		key = Key_GetNum();
		if(key ==2)
		{
			printf("更新bit0位,将其置1\r\n");
			xTaskNotify(Task2_Handler,EVENTBIT0,eSetBits);
		}else if(key ==3){
			printf("更新bit1位,将其置1\r\n");
			xTaskNotify(Task2_Handler,EVENTBIT1,eSetBits);		
		}
		vTaskDelay(10);
	}
}


// 任务2 接受任务通知值
void task2(void *pvParameters)
{
		uint32_t				rev = 0;
		uint32_t				bit = 0;
	
    // 任务主循环
    while (1)
    {
			 xTaskNotifyWait(0,0xFFFFFFFF,&rev,portMAX_DELAY );
				// 等待任务通知,portMAX_DELAY 表示无限等待
        // 0: 不清除任何通知位
        // 0xFFFFFFFF: 接收所有通知值
        // &rev: 存储接收到的通知值
        // portMAX_DELAY: 无限等待,直到收到通知
			if(rev&EVENTBIT0)
			{
				bit|= EVENTBIT0;
			}
			if(rev&EVENTBIT1)
			{
				bit|= EVENTBIT1;
			}
			if(bit == (EVENTBIT0|EVENTBIT1))
			{
				printf("任务通知模拟事件标志组接收成功\r\n");
				bit = 0;
			}			

		}
}

1、实验解析

相关推荐
HQB20262 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science4 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn4 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天4 小时前
can总线
stm32
桀人5 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯6 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C6 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路6 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc7 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院7 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法