一、消息队列(queue)
队列是一种用于实现任务与任务之间,任务与中断之间消息交流的机制。
注意:1.数据的操作是FIFO模式。
2.队列需要明确数据的大小和队列的长度。
3.写和读都会出现堵塞。
实验:创建一个消息队列,两个发送任务,一个接收任务。
其中任务一任务三的等待时间为0,任务二的等待时间为portMAX_DELAY(死等)。
实现:在前一个项目的基础上进行更改【STM32】利用CubeMX对FreeRTOS用按键控制任务
cpp
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 */
/* Create the semaphores(s) */
/* 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 myQueue01 */
osMessageQDef(myQueue01, 2, uint32_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* definition and creation of Task1 */
osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);
Task1Handle = osThreadCreate(osThread(Task1), NULL);
/* definition and creation of Task2 */
osThreadDef(Task2, StartTask02, osPriorityIdle, 0, 128);
Task2Handle = osThreadCreate(osThread(Task2), NULL);
/* definition and creation of Task3 */
osThreadDef(Task3, StartTask03, osPriorityIdle, 0, 128);
Task3Handle = osThreadCreate(osThread(Task3), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the Task1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
BaseType_t xStatus;
uint32_t Buf=10086;
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
xStatus=xQueueSendToBack(myQueue01Handle,&Buf,0);
if(xStatus!=pdTRUE)
{
printf("NO1\r\n");osDelay(500);
}
else
{
printf("YES1%u\r\n",Buf);osDelay(500);
}
}
}
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
BaseType_t xStatus;
uint32_t Buf=66666;
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
{
xStatus=xQueueSendToBack(myQueue01Handle,&Buf,portMAX_DELAY);
if(xStatus!=pdTRUE)
{
printf("NO2\r\n");osDelay(500);
}
else
{
printf("YES2%u\r\n",Buf);osDelay(500);
}
}
}
}
/* USER CODE END StartTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
//BaseType_t xStatus;
uint32_t Buf=0;
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0)
{
printf("当前%u\r\n",Buf);
//xStatus=xQueueReceive(myQueue01Handle,&Buf,portMAX_DELAY);
if(xQueueReceive(myQueue01Handle,&Buf,portMAX_DELAY)!=pdTRUE)
{
printf("NO3\r\n");
}
else
{
printf("YES3%u\r\n",Buf);
}
}
}
}
/* USER CODE END StartTask03 */
}
现象:队列满了以后,任务一无法发送,任务二会死等,队列空闲以后完成发送。
二、信号量
消息队列用于传输多个数据,占用时间也相对较长,但有时只需要传输状态,因此引入信号量。信号量也是队列的一种。信号量有两种,如果它的量只有0(被拿走的状态)和1(被填入的状态)两种状态,就称为二进制的信号量;当量的状态大于两种,就称为计数型信号量。
1.二值信号量
实验:任务一:按键采集数据;任务二:拿走以后串口发送信息
实现:
cpp
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 */
/* Create the semaphores(s) */
/* definition and creation of myBinarySem01 */
osSemaphoreDef(myBinarySem01);
myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);
/* 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 myQueue01 */
osMessageQDef(myQueue01, 2, uint32_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* definition and creation of Task1 */
osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);
Task1Handle = osThreadCreate(osThread(Task1), NULL);
/* definition and creation of Task2 */
osThreadDef(Task2, StartTask02, osPriorityNormal, 0, 128);
Task2Handle = osThreadCreate(osThread(Task2), NULL);
/* definition and creation of Task3 */
osThreadDef(Task3, StartTask03, osPriorityNormal, 0, 128);
Task3Handle = osThreadCreate(osThread(Task3), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the Task1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
BaseType_t xStatus;
uint32_t Buf=10086;
for(;;)
{
// {
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
// xStatus=xQueueSendToBack(myQueue01Handle,&Buf,0);
if(xSemaphoreGive(myBinarySem01Handle)==pdTRUE)
{
printf("NO1\r\n");
}
else
{
printf("YES1%u\r\n",Buf);
}
}
}
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
uint32_t Buf=0;
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0)
{
if(xSemaphoreTake(myBinarySem01Handle,0)==pdTRUE)
{
printf("YES3\r\n");
}
else
{
printf("NO3%u\r\n",Buf);
}
}
}
}
/* USER CODE END StartTask03 */
}
现象:当按键释放了信号量,串口才能成功发送信息。
2.记数型信号量
实验:任务一 :按键一记录人进来;按键二记录人出去;(最多有10个人)
任务二:串口每隔3S打印人数。
实现:
cpp
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 */
/* Create the semaphores(s) */
/* definition and creation of myBinarySem01 */
osSemaphoreDef(myBinarySem01);
myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);
/* definition and creation of myCountingSem01 */
osSemaphoreDef(myCountingSem01);
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 10);
/* 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 myQueue01 */
osMessageQDef(myQueue01, 2, uint32_t);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* definition and creation of Task1 */
osThreadDef(Task1, StartDefaultTask, osPriorityNormal, 0, 128);
Task1Handle = osThreadCreate(osThread(Task1), NULL);
/* definition and creation of Task2 */
osThreadDef(Task2, StartTask02, osPriorityNormal, 0, 128);
Task2Handle = osThreadCreate(osThread(Task2), NULL);
/* definition and creation of Task3 */
osThreadDef(Task3, StartTask03, osPriorityNormal, 0, 128);
Task3Handle = osThreadCreate(osThread(Task3), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the Task1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
{
if(xSemaphoreGive(myCountingSem01Handle)!=pdTRUE)
{
printf("NO1\r\n");
}
else
{
printf("YES1\r\n");
}
}
}
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
{
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
{
if(xSemaphoreTake(myCountingSem01Handle,0)!=pdTRUE)
{
printf("NO2\r\n");
}
else
{
printf("YES2\r\n");
}
}
}
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
}
/* USER CODE END StartTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for(;;)
{
printf("possess %d people\r\n",(uint16_t)uxSemaphoreGetCount(myCountingSem01Handle));
osDelay(3000);
}
/* USER CODE END StartTask03 */
}
因为用了函数
cpp
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 10);
默认当前计数值为满值。如果设置为0,使用下面的函数:
cpp
myCountingSem01Handle=xSemaphoreCreateCounting(10,0);
现象:通过按键一和二实现记录人数,并串口打印了当前人数。