【STM32】FreeRTOS消息队列和信号量学习

一、消息队列(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);

现象:通过按键一和二实现记录人数,并串口打印了当前人数。

相关推荐
芊寻(嵌入式)1 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
Qingniu015 分钟前
【青牛科技】应用方案 | RTC实时时钟芯片D8563和D1302
科技·单片机·嵌入式硬件·实时音视频·安防·工控·储能
hong16168838 分钟前
跨模态对齐与跨领域学习
学习
Mortal_hhh1 小时前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
深圳市青牛科技实业有限公司2 小时前
【青牛科技】应用方案|D2587A高压大电流DC-DC
人工智能·科技·单片机·嵌入式硬件·机器人·安防监控
Suckerbin2 小时前
Hms?: 1渗透测试
学习·安全·网络安全
水豚AI课代表2 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc
聪明的墨菲特i2 小时前
Python爬虫学习
爬虫·python·学习
Diamond技术流2 小时前
从0开始学习Linux——网络配置
linux·运维·网络·学习·安全·centos