[FREERTOS]队列
1.什么是队列
队列也称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务之间,中断和任务之间传递信息
2.传递信息为什么不用全局变量呢?
确实全局变量依然可以传递信息,但是如果全局变量改变的很频繁,某一任务处理数据比较缓慢,某一任务在处理数据的过程中改变了全局变量的值,就可能会导致某一任务获取的数据不正确,消息队列就像一条生产线似的,将数据放入队列中,任务从队列中读取数据,这样的话就算改变了数据的值,任务根据队列中的值来获取数据也能获取到正确的值
3.队列的几个名词
队列项目:队列中每一个数据
队列长度:队列能够存储项目(数据)的最大数量(创建队列时需要指定队列长度和队列项目大小)
队列的特点
1.数据的出入方式:
通常采用先入先出的数据缓冲方式(FIFO)也可以配置成后入先出的方式(LIFO)
2.数据的传输方式
通常采用实际值传递,也就是将数据拷贝到队列中传递,也可以通过指针,通常传递较大的数据时采用指针传递
3.多任务访问
队列不属于任何一个任务,任何中断和任务都可以向队列发送/接收数据
4.出队/入队阻塞
当任务向队列中发送数据时,如果队列已满,可以指定一个堵塞时间:
0:不堵塞直接返回
0----port_MAX_Delay:等待设定的时间,如果超时还未能入队,就返回
port_MAX_Delay:死等,一直等到能够入队为止
与队列相关的API函数
1.创建队列
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize);
参数1:UBaseType_t uxQueueLength:队列中最大可存放的项目数
参数2:UBaseType_t uxItemSize:每个项目的大小
返回值如果创建成功就返回创建队列的句柄,如果创建队列所需内存无法分配就返回NULL
在cubeMX中配置好后会自动封装新的函数创建队列
声明定义两个任务和一个队列的句柄
2.写队列
xQueueSend();往队列尾部写入消息
xQueueSendToBack();与xQueueSend()效果相同
xQueueSendToFront();往队列头部写入消息
xQueueOverwrite();覆
写队列消息,只用于队列长度为1时
xQueueSendFromISR();往中断队列尾部写入消息
xQueueSendToBackFromISR();与xQueueSendFromISR();效果相同
xQueueSendToFrontFromISR()往中断队列头部写入消息
xQueueOverwriteFromISR();在中断中覆写队列消息,只用于队列长度为1时
BaseType_t xQueueSend{
QueueHandle_t xQueue,
const void* pvItemToQueue,
TickType_t xTicksToWait
};
xQueue:队列的句柄,将数据项发到此队列
pvItemToQueue:待写入的数据
xTickToWait:阻塞超时时间
成功写入的话返回pdTRUE,否则返回errQUEUE_FULL
4.读队列
xQueueReceive();//从队列头部读取消息并删除此消息
xQueuePeek();//从队列头部读取消息但不删除此消息
xQueueReceiveFromISR();//在中断中从队列头部读取消息,并删除消息
xQueueRPeekFromISR();在中断中从队列头部读取消息,不删除消息
BaseType_t xQueueReceive{
QueueHandle_t xQueue,
const void* pvBuffer,
TickType_t xTicksToWait
};
xQueue:待读取的队列
pvItemToQueue:数据读取缓存区
xTickToWait:阻塞超时时间
成功写入的话返回pdTRUE,否则返回pdFALSE
按键key1发送数据给队列,按键key2接收队列数据
freertos.c
/*cubeMX配置的代码------------------------------↓*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables *//* USER CODE END Variables */
osThreadId taskSendHandle;
osThreadId taskReceiveHandle;
osMessageQId myQueueHandle;/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *//* USER CODE END FunctionPrototypes */void StartTaskSend(void const * argument);
void StartTaskReceive(void const * argument);void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{*ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;*ppxIdleTaskStackBuffer = &xIdleStack[0];*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;/* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY *//*** @brief FreeRTOS initialization* @param None* @retval None*/
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* Create the queue(s) *//* definition and creation of myQueue */osMessageQDef(myQueue, 16, uint16_t);myQueueHandle = osMessageCreate(osMessageQ(myQueue), NULL);/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of taskSend */osThreadDef(taskSend, StartTaskSend, osPriorityNormal, 0, 128);taskSendHandle = osThreadCreate(osThread(taskSend), NULL);/* definition and creation of taskReceive */osThreadDef(taskReceive, StartTaskReceive, osPriorityNormal, 0, 128);taskReceiveHandle = osThreadCreate(osThread(taskReceive), NULL);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... *//* USER CODE END RTOS_THREADS */}
/*cubeMX配置的代码------------------------------↑*//*需要手动敲的代码------------------------------↓*/
void StartTaskSend(void const * argument)
{/* USER CODE BEGIN StartTaskSend */uint16_t buf = 100;BaseType_t status;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)//消抖{status = xQueueSend(myQueueHandle,&buf,0);if(status == pdTRUE)/如果发送成功会返回pdTRUE{printf("send success:%d\\r\\n",buf);}else{printf("send error\\r\\n");}}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskSend */
}/* USER CODE BEGIN Header_StartTaskReceive */
/**
* @brief Function implementing the taskReceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskReceive */
void StartTaskReceive(void const * argument)
{/* USER CODE BEGIN StartTaskReceive */uint16_t buf;BaseType_t status;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)//消抖{status = xQueueReceive(myQueueHandle,&buf,0);if(status == pdTRUE)//如果接收成功会返回pdTRUE{printf("read success:%d\\r\\n",buf);}else{printf("read error\\r\\n");}}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskReceive */
}
/*需要手动敲的代码------------------------------↑*/
uart.c
#include "usart.h"/* USER CODE BEGIN 0 */
#include <string.h>
#include <stdio.h>
int fputc(int ch,FILE*f)//printf重定向
{unsigned char temp[1] = {ch};HAL_UART_Transmit(&huart1,temp,strlen((const char*)temp),0xffff);return ch;
}
重定向一定记住 勾选Use MicroLIB!!!!