【FreeRTOS】【STM32】08 FreeRTOS message queue

simply put

Message queue is a data structure

Basic description of task operation queue

1. If 队列未满 or 允许覆盖入队, FreeRTOS will add the message that the task needs to send to 队列尾.
2. If 队列满, the task will be blocked (waiting).
3. Users can specify the waiting time.
4. When other tasks read data from the queue they are waiting for (the queue is not full at this time)
5. The task (waiting to send data Tasks to the queue) will automatically move from the blocking state to the ready state.
6. After the waiting time is exceeded, even if the queue does not allow access, the task will automatically transfer from the blocking state to the ready state. At this time, the task or interrupt program that sends the message will receive an error code. errQUEUE_FULL.

Things to note when using message queues

1. Before sending or receiving messages, you need to define a message queue and operate according to the queue handle
2. The queue reading adopts the first-in-first-out (FIFO) mode. Read the data first stored in the queue. Of course, FreeRTOS also supports last-in-first-out (LIFO) mode.
3. The read buffer needs to be defined before reading data.
4. Whether sending or receiving messages is done by copying. If the message is too large, the address of the message can be sent and received as a message.
5. The queue is a kernel object with its own independent permissions and does not belong to any task. All tasks can write to and read from the same queue. It is common for a queue to be written by multiple tasks or interrupts, but it is rarely used for reading from multiple tasks.

Message queue creation function xQueueCreate()

1.xQueueCreateThe function is created based on 2. When using xQueueCreate() to create a queue, use is dynamic memory allocation, so if you want to use this function, you must define configSUPPORT_DYNAMIC_ALLOCATION as 1 in FreeRTOSConfig.h to enable it. The macro definition in FreeRTOSConfig.h defaults to 1. 3. The message volume API function is also created based on xQueueGenericCreate

xQueueGenericCreate

 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 #define xQueueCreate( uxQueueLength, uxItemSize ) \ 
						 xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) 
 #endif

function prototype

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
							 UBaseType_t uxItemSize );

Parameters:
uxQueueLength: The maximum number of message units that the queue can store, that is, the queue length.
uxItemSize: The size of the message unit in the queue, in bytes.
Returns a handle. The handle is a pointer to the queue data structure type. The function in RTOS And the operations of data structures are all through handles.

Usage example:

 QueueHandle_t Test_Queue =NULL;//队列句柄

#define QUEUE_LEN 4 /* 队列的长度,最大可包含多少个消息 */
#define QUEUE_SIZE 4 /* 队列中每个消息大小(字节) */

BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */

 taskENTER_CRITICAL(); //进入临界区
 /* 创建 Test_Queue */ 
Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息队列的长度 */ 
							(UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */ 
 if (NULL != Test_Queue) 
	 printf("创建 Test_Queue 消息队列成功!\r\n");
	 
 taskEXIT_CRITICAL(); //退出临界区

Message queue static creation function xQueueCreateStatic()

Like statically creating tasks, statically creating message queues also requires customizing a piece of memory.

function prototype

QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,
								 UBaseType_t uxItemSize,
								 uint8_t *pucQueueStorageBuffer,
								 StaticQueue_t *pxQueueBuffer );

Parameters
uxQueueLength: The maximum number of units that the queue can store, that is, queue depth
uxItemSize: The length of the data unit in the queue, in bytes.
pucQueueStorageBuffer: Pointer, pointing to an array of type uint8_t, the size of the array is at least uxQueueLength* uxItemSize bytes. When uxItemSize is 0, pucQueueStorageBuffer can be NULL.
pxQueueBuffer: Pointer, pointing to a variable of type StaticQueue_t, which is used to store the data structure of the queue.

If the creation is successful, a queue handle is returned for accessing the created queue. If the creation is unsuccessful, NULL is returned. The possible reason is that the RAM required to create the queue cannot be allocated successfully.

Usage example

/* 创建一个可以最多可以存储 10 个 64 位变量的队列 */
#define QUEUE_LENGTH 10
#define ITEM_SIZE sizeof(uint64_t)

/* 该变量用于存储队列的数据结构 */
static StaticQueue_t xStaticQueue;

/* 该数组作为队列的存储区域,大小至少有 uxQueueLength * uxItemSize 个字节 */
uint8_t ucQueueStorageArea[ QUEUE_LENGTH * ITEM_SIZE ]; 
 
 void vATask( void *pvParameters )
 {
    
    
	 QueueHandle_t xQueue;
 
 /* 创建一个队列 */ 
 xQueue = xQueueCreateStatic( QUEUE_LENGTH, /* 队列深度 */ 
							 ITEM_SIZE, /* 队列数据单元的单位 */ 
							 ucQueueStorageArea,/* 队列的存储区域 */ 
							 &xStaticQueue ); /* 队列的数据结构 */ 

 /* 剩下的其他代码 */
 }

Message queue delete function vQueueDelete()

The incoming formal parameter is the queue handle of the message queue.

Usage example

#define QUEUE_LENGTH 5
#define QUEUE_ITEM_SIZE 4

int main( void )
{
    
    
	QueueHandle_t xQueue;
	/* 创建消息队列 */
	xQueue = xQueueCreate( QUEUE_LENGTH, QUEUE_ITEM_SIZE );

	 if ( xQueue == NULL ) {
    
    
	 /* 消息队列创建失败 */
	 } else {
    
    
	 /* 删除已创建的消息队列 */ 
	 vQueueDelete( xQueue ); 
		}
 }

Send message function to message queue

任务Either or中断服务程序 can send messages to the message queue.

All message sending functions are based onxQueueGenericSend.

xQueueSend() and xQueueSendToBack() are used for non-interrupt programs

Function prototype:

BaseType_t xQueueSend(QueueHandle_t xQueue,
					 const void * pvItemToQueue,
					 TickType_t xTicksToWait);

参数:
xQueue: Target queue handle
pvItemToQueue: Pointer pointing to the queue message to be sent to the end of the queue
xTicksToWait: When the queue is full, the maximum timeout period for waiting for the queue to become free. If the queue is full and xTicksToWait is set to 0, the function returns immediately. The unit of the timeout time is the system tick period, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, and the unit is ms. If INCLUDE_vTaskSuspend is set to 1, and specifying a delay of portMAX_DELAY will cause the task to be suspended (without a timeout).
返回值: pdTRUE is returned if the message is sent successfully, otherwise errQUEUE_FULL is returned.

Macro definition

 #define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \
 			xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), \
							 ( xTicksToWait ), queueSEND_TO_BACK )

It can be seen thatxQueueSend() is a macro, and macro expansion is to call a function xQueueGenericSend().

 #define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \
			 xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), \
 								( xTicksToWait ), queueSEND_TO_BACK )

It can be seen that xQueueSendToBack macro expansion calls a function xQueueGenericSend().

xQueueSend() etc.xQueueSendToBack().

xQueueSend() is used to send a queue message to the end of the queue. Messages are enqueued as copies, not as references. This function must not be called in the interrupt service routine. In the interrupt, xQueueSendFromISR() withinterrupt protection function must be used instead.

Usage examples

Send_TaskAs a task function, the function is to send a message to the queue after detecting a key press
This actual task is also a formal parameter of the task. Task creation

static void Send_Task(void* parameter)
{
    
    
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	uint32_t send_data1 = 1;
	uint32_t send_data2 = 2;
	while (1) {
    
    
		if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) {
    
    
				/* K1 被按下 */
				printf("发送消息 send_data1!\n"); 
				 xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ 
										&send_data1,/* 发送的消息内容 */ 
										 0 ); /* 等待时间 0 */ 
				if (pdPASS == xReturn) 
					 printf("消息 send_data1 发送成功!\n\n"); 
			 }

		if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) {
    
    
				 /* K2 被按下 */
				printf("发送消息 send_data2!\n"); 
				xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ 
									&send_data2,/* 发送的消息内容 */ 
									 0 ); /* 等待时间 0 */ 
			 if (pdPASS == xReturn) 
					 printf("消息 send_data2 发送成功!\n\n"); 
			 }
		 vTaskDelay(20);/* 延时 20 个 tick */
	}
 }

Send messages in xQueueSendFromISR() and xQueueSendToBackFromISR() interrupt service functions

Function prototype:

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,
							 const void *pvItemToQueue,
							 BaseType_t *pxHigherPriorityTaskWoken);

参数:
xQueue: Target queue handle
pvItemToQueue: Pointer, pointing to the message to be sent to the end of the queue
pxHigherPriorityTaskWoken: If Enqueueing causes a task to be unlocked, and the priority of the unlocked task is higher than the currently interrupted task, then set *pxHigherPriorityTaskWoken to pdTRUE, and then a context switch needs to be performed before interrupting to exit to execute the awakened task with a higher priority. Task. As of FreeRTOS V7.3.0 pxHigherPriorityTaskWoken is an optional parameter and can be set to NULL.

返回值:
Returns pdTRUE if the message is sent successfully, otherwise returns errQUEUE_FULL.

yxQueueSendfunction homology, xQueueSendFromISR()y xQueueSendToBackFromISR()also is Hongsei.
xQueueSendFromISR():

 #define xQueueSendToFrontFromISR(xQueue,pvItemToQueue,pxHigherPriorityTaskWoken) \
				xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ),\
								( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )

xQueueSendToBackFromISR is equivalent to xQueueSendFromISR ().
xQueueSendToBackFromISR():

#define xQueueSendToBackFromISR(xQueue,pvItemToQueue,pxHigherPriorityTaskWoken) \
			 xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), \
						 ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )
Usage examples
void vBufferISR( void )
{
    
    
	char cIn;
	BaseType_t xHigherPriorityTaskWoken; 

	/* 在 ISR 开始的时候,我们并没有唤醒任务 */
	xHigherPriorityTaskWoken = pdFALSE; 

	/* 直到缓冲区为空 */
	 do {
    
    
	 /* 从缓冲区获取一个字节的数据 */
	 cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
 
	 /* 发送这个数据 */ 
	 xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken ); 
 
	 } while ( portINPUT_BYTE( BUFFER_COUNT ) );
 
	 /* 这时候 buffer 已经为空,如果需要则进行上下文切换 */ 
	 if ( xHigherPriorityTaskWoken ) {
    
     
	 /* 上下文切换,这是一个宏,不同的处理器,具体的方法不一样 */ 
	 taskYIELD_FROM_ISR (); 
	 } 
 }

How do I know if there is a wake-up task in the interrupt service function?

Send message to the head of the queue

xQueueSendToFront()

usage is consistent with xQueueSend(). Used for tasks, xQueueSendToFrontFromISR () with interrupt protection is used in interrupts. Similar xQueueSendToFrontFromISR is also a macro definition, based on xQueueGenericSendFromISR.

function prototype

BaseType_t xQueueSendToFront( QueueHandle_t xQueue,
 							const void * pvItemToQueue,
 							TickType_t xTicksToWait );

参数:
xQueue: Queue handle
pvItemToQueue: Pointer to the message to be sent to the head of the queue.
xTicksToWait: When the queue is full, the maximum timeout time for waiting for the queue to be idle. If the queue is full and xTicksToWait is set to 0, the function returns immediately. The unit of the timeout time is the system tick period, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, and the unit is ms. If INCLUDE_vTaskSuspend is set to 1, and specifying a delay of portMAX_DELAY will cause the task to block indefinitely (no timeout).

xQueueSendToFrontFromISR()

function prototype

BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,
							 const void *pvItemToQueue,
							 BaseType_t *pxHigherPriorityTaskWoken);

Parameters:
xQueue: Queue handle
pvItemToQueue: Pointer, pointing to the message to be sent to the head of the queue
pxHigherPriorityTaskWoken: If Enqueuing causes a task to be unlocked, and the unlocked task has a higher priority than the currently interrupted task, then set *pxHigherPriorityTaskWoken to pdTRUE, and then a context switch needs to be performed before the interruption exits to execute the awakened task with a higher priority. . Starting from FreeRTOS V7.3.0, pxHigherPriorityTaskWoken is an optional parameter and can be set to NULL.
Return value: pdTRUE is returned if the queue item is successfully delivered, otherwise errQUEUE_FULL is returned.

Read message function from message queue

xQueueReceive() receives and deletes data from the message queue

xQueueReceive() is a macro, and macro expansion calls the function xQueueGenericReceive(). xQueueReceive() is used to receive messages from a queueand delete the messages from the queue.
The received message is in the form of a copy, so we must provide a buffer with sufficient space.
Similar to sending a message to the queue, this function is used for ordinary Tasks. The interrupt service function uses xQueueReceiveFromISR with interrupt protection function.

function prototype

BaseType_t xQueueReceive(QueueHandle_t xQueue,
 								void *pvBuffer,
 						TickType_t xTicksToWait);

Parameters:
xQueue: Queue handle
pvBuffer: Pointer pointing to the received data to be saved: pdTRUE is returned if the queue item is received successfully, otherwise pdFALSE is returned. Return value
xTicksToWait: The maximum blocking timeout when the queue is empty. If this parameter is set to 0, the function returns immediately. The unit of the timeout time is the system tick period, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, and the unit is ms. If INCLUDE_vTaskSuspend is set to 1, and specifying a delay of portMAX_DELAY will cause the task to block indefinitely (no timeout).

xQueueReceive function usage example

Receive_Task is a task function.

static void Receive_Task(void* parameter)
{
    
    
	BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为 pdPASS */
	uint32_t r_queue; /* 定义一个接收消息的变量 */
	while (1) {
    
    
	xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */ 
							&r_queue, /* 接受的数据 */ 
							portMAX_DELAY); /* 等待时间 一直等 */ 
	if (pdTRUE== xReturn) 
		 printf("本次接收到的数据是:%d\n\n",r_queue); 
		 else 
		 printf("数据接收出错,错误代码: 0x%lx\n",xReturn); 
	 }
 }

xQueuePeek() receives but does not delete data from the message queue

The usage method of xQueuePeek is the same as xQueueReceive, but it will not delete data from the message queue.

Receive message versions of xQueueReceiveFromISR() and xQueuePeekFromISR() interrupt service functions

Get the interrupt service function version of the message from the queue.
xQueueReceiveFromISR function prototype

BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue,
									 void *pvBuffer,
				 BaseType_t *pxHigherPriorityTaskWoken);

Parameters:
xQueue: Queue handle
pvBuffer: Pointer, pointing to the buffer to store the received data
pxHigherPriorityTaskWoken: The task is in When posting information to the queue, if the queue is full, the task will be blocked on the queue. If xQueueReceiveFromISR causes a TASK to be awakened, set *pxHigherPriorityTaskWoken to pdTRUE
//------------------------ -------------------------------------------------- -----------------------
pxHigherPriorityTaskWokenFor understanding of this parameter, please contactxQueueReceiveFromISR() The difference between the xQueuePeekFromISR() function is that one function can delete data from the queue, and the other function cannot delete data from the queue. Deleting the data in the queue may cause a task to be awakened, and the interrupt service function interrupts execution in the Task. If another TASK is caused, how to execute these two TASKs next?
//------------------------------------------ -------------------------------------------------- ----------
xQueuePeekFromISR function prototype

BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue,
 									void *pvBuffer);

Parameters:
xQueue: Queue handle.
pvBuffer: Pointer, pointing to the received data to be saved.

xQueueReceiveFromISR usage example
QueueHandle_t xQueue;

/* 创建一个队列,并往队列里面发送一些数据 */
void vAFunction( void *pvParameters )
{
    
    
	char cValueToPost;
	const TickType_t xTicksToWait = ( TickType_t )0xff;

	/* 创建一个可以容纳 10 个字符的队列 */
	 xQueue = xQueueCreate( 10, sizeof( char ) );
	 if ( xQueue == 0 ) {
    
    
 		/* 队列创建失败 */
 		}
 
	 /* ... 任务其他代码 */
	 
	 /* 往队列里面发送两个字符 如果队列满了则等待 xTicksToWait 个系统节拍周期*/
	 cValueToPost = 'a';
	 xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
	 cValueToPost = 'b';
	 xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
	 
	 /* 继续往队列里面发送字符当队列满的时候该任务将被阻塞*/
	 cValueToPost = 'c';
	 xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
 }
 
 
 /* 中断服务程序:输出所有从队列中接收到的字符 */
 void vISR_Routine( void )
 {
    
    
	 BaseType_t xTaskWokenByReceive = pdFALSE;
	 char cRxedChar;
 
 while ( xQueueReceiveFromISR( xQueue, 
						 ( void * ) &cRxedChar, 
						 &xTaskWokenByReceive) )
		 {
    
     
		 /* 接收到一个字符,然后输出这个字符 */
		 vOutputCharacter( cRxedChar );
 
		 /* 如果从队列移除一个字符串后唤醒了向此队列投递字符的任务,
			 那么参数 xTaskWokenByReceive 将会设置成 pdTRUE,这个循环无论重复				多少次,仅会有一个任务被唤醒 */}
 
 if ( xTaskWokenByReceive != pdFALSE ) {
    
     
		 /* 我们应该进行一次上下文切换,当 ISR 返回的时候则执行另外一个任务 */ 
		 /* 这是一个上下文切换的宏,不同的处理器,具体处理的方式不一样 */ 
 				taskYIELD (); 
 			} 
 }

Message queue instance

 /* 
 *************************************************************************
 * 包含的头文件
 *************************************************************************
 */
 /* FreeRTOS 头文件 */
 #include "FreeRTOS.h"
 #include "task.h"
 #include "queue.h"
 /* 开发板硬件 bsp 头文件 */
 #include "bsp_led.h"
 #include "bsp_usart.h"
 #include "bsp_key.h"
 /**************************** 任务句柄 ********************************/
 /*
 * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
 * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
 * 这个句柄可以为 NULL。
 */
 static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
 static TaskHandle_t Receive_Task_Handle = NULL;/* LED 任务句柄 */
 static TaskHandle_t Send_Task_Handle = NULL;/* KEY 任务句柄 */
 
 /***************************** 内核对象句柄 *****************************/
 /*
 * 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
 * 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
 * 们就可以通过这个句柄操作这些内核对象。
 *
 * 
 * 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
 * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
 * 来完成的
 *
 */
 QueueHandle_t Test_Queue =NULL;
 
 /*************************** 全局变量声明 *******************************/
 /*
 * 当我们在写应用程序的时候,可能需要用到一些全局变量。
 */
 /*************************** 宏定义 ************************************/
 /*
 * 当我们在写应用程序的时候,可能需要用到一些宏定义。
 */
 #define QUEUE_LEN 4 /* 队列的长度,最大可包含多少个消息 */ 
 #define QUEUE_SIZE 4 /* 队列中每个消息大小(字节) */ 
 
 /*
 *************************************************************************
 * 函数声明
 *************************************************************************
 */
 static void AppTaskCreate(void);/* 用于创建任务 */
 static void Receive_Task(void* pvParameters);/* Receive_Task 任务实现 */
 static void Send_Task(void* pvParameters);/* Send_Task 任务实现 */
 static void BSP_Init(void);/* 用于初始化板载相关资源 */
 
 /*****************************************************************
 * @brief 主函数
 * @param 无
 * @retval 无
 * @note 第一步:开发板硬件初始化
 第二步:创建 APP 应用任务
 第三步:启动 FreeRTOS,开始多任务调度
 ****************************************************************/
 int main(void)
 {
    
    
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
 
	 /* 开发板硬件初始化 */
	 BSP_Init();
	 printf("按下 KEY1 或者 KEY2 发送队列消息\n");
	 printf("Receive 任务接收到消息在串口回显\n\n");
	 /* 创建 AppTaskCreate 任务 */
 xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
					  (const char* )"AppTaskCreate",/* 任务名字 */
 					  (uint16_t )512, /* 任务栈大小 */
					  (void* )NULL,/* 任务入口函数参数 */
 					  (UBaseType_t )1, /* 任务的优先级 */
     				  (TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指*/
	 /* 启动任务调度 */
	 if (pdPASS == xReturn)
	 			vTaskStartScheduler(); /* 启动任务,开启调度 */
	 else
			 return -1; 
while (1); /* 正常不会执行到这里 */
 }
 
 
 /***********************************************************************
 * @ 函数名 : AppTaskCreate
 * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
 * @ 参数 : 无
 * @ 返回值 : 无
 ********************************************************************/
 static void AppTaskCreate(void)
 {
    
    
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
 
 taskENTER_CRITICAL(); //进入临界区
 
 /* 创建 Test_Queue */ 
 Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息队列的长度 */ 
 							(UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */ 
 if (NULL != Test_Queue) 
 	printf("创建 Test_Queue 消息队列成功!\r\n"); 
 
 /* 创建 Receive_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )Receive_Task,/* 任务入口函数 */
					 (const char* )"Receive_Task",/* 任务名字 */
					 (uint16_t )512, /* 任务栈大小 */
					 (void* )NULL, /* 任务入口函数参数 */
					 (UBaseType_t )2, /* 任务的优先级 */
					 (TaskHandle_t* )&Receive_Task_Handle);/*任务控制块指针*/
 if (pdPASS == xReturn)
 		printf("创建 Receive_Task 任务成功!\r\n");
 
 /* 创建 Send_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )Send_Task, /* 任务入口函数 */
 						 (const char* )"Send_Task",/* 任务名字 */
						 (uint16_t )512, /* 任务栈大小 */
						 (void* )NULL,/* 任务入口函数参数 */
						 (UBaseType_t )3, /* 任务的优先级 */
						 (TaskHandle_t* )&Send_Task_Handle);/*任务控制块指针 */
 if (pdPASS == xReturn)
		 printf("创建 Send_Task 任务成功!\n\n");
 vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务 
 taskEXIT_CRITICAL(); //退出临界区
 }
 
 
 
 /**********************************************************************
 * @ 函数名 : Receive_Task
 * @ 功能说明: Receive_Task 任务主体
 * @ 参数 :
 * @ 返回值 : 无
 ********************************************************************/
 static void Receive_Task(void* parameter) 
 {
    
     
		 BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为 pdTRUE */ 
		 uint32_t r_queue; /* 定义一个接收消息的变量 */ 
	 while (1) {
    
     
		 xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */ 
							 	&r_queue, /* 发送的消息内容 */ 
 								portMAX_DELAY); /* 等待时间 一直等 */ 
 		if (pdTRUE == xReturn) 
		 printf("本次接收到的数据是%d\n\n",r_queue); 
			 else 
 		printf("数据接收出错,错误代码: 0x%lx\n",xReturn); 
			 } 
 } 
 
 /**********************************************************************
 * @ 函数名 : Send_Task
 * @ 功能说明: Send_Task 任务主体
 * @ 参数 :
 * @ 返回值 : 无
 ********************************************************************/
 static void Send_Task(void* parameter) 
 {
    
     
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */ 
	 uint32_t send_data1 = 1; 
	 uint32_t send_data2 = 2; 
 while (1) {
    
     
 	if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) {
    
     
				 /* KEY1 被按下 */ 
			 printf("发送消息 send_data1!\n"); 
 			xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ 
 								&send_data1,/* 发送的消息内容 */ 
								 0 ); /* 等待时间 0 */ 
			 if (pdPASS == xReturn) 
 					printf("消息 send_data1 发送成功!\n\n"); 
 			} 
 if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) {
    
     
 		/* KEY2 被按下 */ 
				 printf("发送消息 send_data2!\n"); 
 				 xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ 
 										&send_data2,/* 发送的消息内容 */ 
 										0 ); /* 等待时间 0 */ 
				 if (pdPASS == xReturn) 
						 printf("消息 send_data2 发送成功!\n\n"); 
 			} 
 	vTaskDelay(20);/* 延时 20 个 tick */ 
		 } 
 } 
 
 /***********************************************************************
 * @ 函数名 : BSP_Init
 * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
 * @ 参数 :
 * @ 返回值 : 无
 *********************************************************************/
 static void BSP_Init(void)
 {
    
    
 /*
 * STM32 中断优先级分组为 4,即 4bit 都用来表示抢占优先级,范围为:0~15
 * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
 * 都统一用这个优先级分组,千万不要再分组,切忌。
 */
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	 /* LED 初始化 */
	 LED_GPIO_Config();
	
	 /* 串口初始化 */
	 USART_Config();
	
	 /* 按键初始化 */
	 Key_GPIO_Config();

 }

 /*******************************END OF FILE****************************/

おすすめ

転載: blog.csdn.net/apythonlearner/article/details/134034838