STM32 CubeMX中使用FreeRTOS任务通信的方法详解
STM32 CubeMX
STM32 CubeMX ____Freertos任务通信:队列、信号量、互斥量,事件组,任务通知
学习使用Freertos第二步
在 FreeRTOS 中,任务通信可以通过以下函数来实现:
xQueueCreate()
:用于创建一个消息队列。可以设置队列长度和每个消息的大小。
xQueueSend()
:将一条消息发送到队列中。可以选择阻塞或非阻塞发送。
xQueueReceive()
:从队列中接收一条消息。可以选择阻塞或非阻塞接收。
xQueuePeek():
查看队列中的下一条消息,但不将其移除。
xQueueReset()
:清空队列中的所有消息。
2. xQueueSemaphoreTake()
和xQueueSemaphoreGive()
:用于实现二值信号量,控制任务之间的互斥访问。
3. xSemaphoreCreateMutex()
:创建一个互斥信号量,用于实现任务之间的互斥访问。
4. xTaskNotify()
和ulTaskNotifyTake()
:用于任务间的通知机制,一个任务可以通知另一个任务进行某种操作。
5. xEventGroupCreate()、xEventGroupSetBits()和xEventGroupWaitBits()
:用于创建、设置和等待事件标志组。
一、STM32 CubeMX设置
时钟配置
HAL时基选择TIM1(不要选择滴答定时器;滴答定时器留给OS系统做时基)
使用STM32 CubeMX 库,配置Freertos
选择CMISS_V1接口就可以满足Freertos接口;且代码量比CMISS_V2小(CMISS_V2支持更多的RTOS接口,所以代码量比CMISS_V1多)
二、实验一:消息队列
消息队列是什么?适用于什么地方?
FreeRTOS 消息队列和数组 的几个区别:
创建消息队列
创建任务
代码部分
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
xsatus=xQueueSendToBack(myQueue01Handle,&buff,0);
if( xsatus!=pdPASS)
{
printf("输入失败\r\n"); // printf输出字符串
}
else
{
printf("成功写入%d\r\n", buff); // printf输出字符串
}
osDelay(1000);
}
/* USER CODE END sendTask1 */
}
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
xsatus=xQueueReceive(myQueue01Handle,&buff,0);
if( xsatus!=pdPASS)
{
printf("读取失败\r\n"); // printf输出字符串
}
else
{
printf("成功读取%d\r\n", buff); // printf输出字符串
}
osDelay(3000);
}
/* USER CODE END readTask3 */
}
实验现象
xsatus=xQueueSendToBack(myQueue01Handle,&buff,portMAX_DELAY);//一直等待
if( xsatus!=pdPASS)
{
printf("输入失败\r\n"); // printf输出字符串
}
else
{
printf("成功写入%d\r\n", buff); // printf输出字符串
}
还一种方式:读取不会删除信息(偷窥信息)
三,实验二:信号量
信号量是什么?适用于什么地方?
FreeRTOS中的信号量是一种用于任务间同步和资源共享的机制。它可以用来实现任务之间的互斥访问共享资源,或者在某个任务等待某个事件发生时进行阻塞。
FreeRTOS提供了两种类型的信号量:二进制信号量(Binary Semaphore)和计数信号量(Counting Semaphore)。
二进制信号量是一种简单的信号量,只有两种状态:空闲和占用。当一个任务获取到二进制信号量时,它就可以继续执行,而其他任务则会被阻塞。当任务释放二进制信号量时,其他任务可以获取到它并继续执行。
计数信号量是一种更复杂的信号量,它可以有多个资源可供获取。计数信号量可以用来实现资源池的管理,例如限制同时访问某个资源的任务数量。
在FreeRTOS中,可以使用以下函数来创建和操作信号量:
需要注意的是,使用信号量时要确保正确的获取和释放顺序,以避免出现死锁或资源竞争的问题。
二值信号量
创建信号量
代码部分
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY)!=pdPASS)
{
printf("刷新失败#信号量获取失败\r\n"); // printf输出字符串
}
else
{
printf("成功刷新#信号量获取成功\r\n"); // printf输出字符串
}
osDelay(2000);
}
/* USER CODE END sendTask1 */
}
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
if( xSemaphoreGive(myBinarySem01Handle)!=pdPASS)
{
printf("读取失败#信号量不能释放\r\n"); // printf输出字符串
}
else
{
printf("成功读取#信号量已经释放\r\n"); // printf输出字符串
}
osDelay(1000);
}
/* USER CODE END readTask3 */
}
实验现象
计数信号量
创建计数信号量
代码部分
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
if( xSemaphoreGive(myCountingSem01Handle)!=pdTRUE)
{
printf("停车已满\r\n"); // printf输出字符串
}
else
{
printf("停车成功\r\n"); // printf输出字符串
}
osDelay(2000);
}
/* USER CODE END sendTask1 */
}
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake(myCountingSem01Handle,0)!=pdTRUE)
{
printf("无车\r\n"); // printf输出字符串
}
else
{
printf("取走车\r\n"); // printf输出字符串
}
osDelay(1000);
}
/* USER CODE END readTask3 */
}
实验现象
四,实验三:互斥量
互斥量是什么?适用于什么地方?
FreeRTOS中的互斥量(Mutex)是一种用于保护共享资源的同步机制。它可以确保在任何给定时刻只有一个任务可以访问被保护资源,以避免竞争条件和数据损坏。
在FreeRTOS中,互斥量通过以下API函数进行创建、获取和释放:
xSemaphoreCreateMutex()
:用于创建一个互斥量,并返回一个指向该互斥量的句柄。xSemaphoreTake()
:用于获取(锁定)互斥量。如果互斥量当前未被锁定,则任务可以 获取互斥量并继续执行;否则,任务将被阻塞,直到互斥量可用。xSemaphoreGive()
:用于释放(解锁)互斥量。一旦任务完成了对共享资源的访问,应该调用此函数来释放互斥量,以允许其他任务获取它。创建互斥量

代码部分
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
osDelay(20);
if(xSemaphoreTake(myMutex01Handle,portMAX_DELAY)!=pdTRUE)
{
printf("1号:你上完厕所,下一个就轮到我了\r\n"); // printf输出字符串
}
else
{
printf("1号:现在是我在上厕所\r\n"); // printf输出字符串
xSemaphoreGive(myMutex01Handle);
printf("1号:我上完了\r\n"); // printf输出字符串
}
osDelay(2000);
}
/* USER CODE END sendTask1 */
}
/* USER CODE BEGIN Header_sendTask2 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_sendTask2 */
void sendTask2(void const * argument)
{
/* USER CODE BEGIN sendTask2 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
xSemaphoreTake(myMutex01Handle,0);
printf("2号:我在厕所\r\n"); // printf输出字符串
osDelay(3000);
printf("2号:我上完了\r\n"); // printf输出字符串
xSemaphoreGive(myMutex01Handle);
osDelay(2000);
}
/* USER CODE END sendTask2 */
}
/* USER CODE BEGIN Header_readTask3 */
/**
* @brief Function implementing the read thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_readTask3 */
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
if(xSemaphoreTake(myMutex01Handle,0)!=pdTRUE)
{
printf("3号:厕所有人,等一会儿再来\r\n"); // printf输出字符串
}
else
{
printf("3号:到我上小便了\r\n"); // printf输出字符串
printf("3号:我撒完尿了\r\n"); // printf输出字符串
xSemaphoreGive(myMutex01Handle);
}
osDelay(1000);
}
/* USER CODE END readTask3 */
}
实验现象
五,实验四:事件组
互斥量是什么?适用于什么地方?
FreeRTOS事件组是一个用于多任务协调和通信的机制。它允许任务等待多个事件同时发生,并在事件发生后恢复任务的执行。事件组可以用于线程同步、互斥、事件通知等应用场景。
FreeRTOS事件组由32位的二进制位表示,每个事件标志位对应一个事件。任务可以通过等待特定的事件标志位来挂起自己的执行,并在其中一个或多个事件标志位被设置时被唤醒。任务还可以使用事件组的API函数来设置或清除特定的事件标志位。
以下是一些常用的FreeRTOS事件组API函数:
xEventGroupCreate()
:创建一个新的事件组。vEventGroupDelete()
:删除已创建的事件组。xEventGroupSetBits()
:设置一个或多个事件标志位。xEventGroupClearBits()
:清除一个或多个事件标志位。xEventGroupWaitBits()
:等待一个或多个事件标志位被设置。
使用FreeRTOS事件组可以实现任务之间的同步和通信,提高系统的可靠性和效率。
**CMSIS_V1不支持创建事件组,所以手创建 **
EventGroupHandle_t myEvent=NULL;//创建句柄
myEvent = xEventGroupCreate(); //创建事件组
与逻辑,事件组
任务代码:
/* USER CODE END Header_sendTask1 */
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
printf("1号:这个方案我同意了\r\n"); // printf输出字符串
xEventGroupSetBits(myEvent,0x0001);
osDelay(2000);
}
/* USER CODE END sendTask1 */
}
/* USER CODE BEGIN Header_sendTask2 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_sendTask2 */
void sendTask2(void const * argument)
{
/* USER CODE BEGIN sendTask2 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
osDelay(5000);
printf("2号:这个方案我同意了\r\n"); // printf输出字符串
xEventGroupSetBits(myEvent,0x0010);
}
/* USER CODE END sendTask2 */
}
/* USER CODE BEGIN Header_readTask3 */
/**
* @brief Function implementing the read thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_readTask3 */
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
buff=xEventGroupWaitBits(myEvent,0x0011,pdTRUE,pdTRUE,portMAX_DELAY);//1.句柄;2.哪些位;3.读完清零;4.全部有效(与逻辑);5.等待时间
if(buff==0x0011)
{
printf("3号:好这个方案全票同意\r\n"); // printf输出字符串
}
osDelay(10000);
}
/* USER CODE END readTask3 */
}
实验现象
或逻辑,事件组
void sendTask1(void const * argument)
{
/* USER CODE BEGIN sendTask1 */
BaseType_t xsatus;
uint32_t buff=9600;
/* Infinite loop */
for(;;)
{
printf("1号:这个方案我同意了\r\n"); // printf输出字符串
xEventGroupSetBits(myEvent,0x0001);
osDelay(2000);
}
/* USER CODE END sendTask1 */
}
/* USER CODE BEGIN Header_sendTask2 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_sendTask2 */
void sendTask2(void const * argument)
{
/* USER CODE BEGIN sendTask2 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
osDelay(5000);
printf("2号:这个方案我同意了\r\n"); // printf输出字符串
xEventGroupSetBits(myEvent,0x0010);
}
/* USER CODE END sendTask2 */
}
/* USER CODE BEGIN Header_readTask3 */
/**
* @brief Function implementing the read thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_readTask3 */
void readTask3(void const * argument)
{
/* USER CODE BEGIN readTask3 */
BaseType_t xsatus;
uint32_t buff=115200;
/* Infinite loop */
for(;;)
{
buff=xEventGroupWaitBits(myEvent,0x0011,pdTRUE,pdFALSE,portMAX_DELAY);//1.句柄;2.哪些位;3.读完清零;4.全部有效(与逻辑);5.等待时间
if((buff==0x0010)||(buff==0x0001))
{
printf("3号:好方案通过,下一个方案\r\n"); // printf输出字符串
}
}
/* USER CODE END readTask3 */
}