重点:当串口发送数据同时有几个任务调用时,则出现打印数据混乱,此时就需要使用互斥信号量了,确保只有一个任务在调用串口发送。
数据混乱原因:多个不同优先级任务运行时使用同一个信号量将因为阻塞导致任务执行出现优先级翻转问题;
示例将演示任务优先级翻转问题:
创建3个任务,优先级不同,创建二值信号量并释放信号量。
任务1 优先级低:获取信号量,打印运行信息,任务调度,释放信号量,延时
任务2 优先级中:打印运行信息、延时
任务3 优先级高:获取信号量,打印运行信息,释放信号量,延时
示例代码:
二值信号量演示:
main.c
#include "AppTask.h"
static void BSP_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//优先级0-15
LED_GPIO_Config();
USART_Config();
}
int main(void)
{
BaseType_t xReturn = pdPASS;
BSP_Init();
xReturn = xTaskCreate((TaskFunction_t) (AppCreate_Task),
(const char*) "AppCreate_Task",
(uint16_t) 512,
(void*) NULL,
(UBaseType_t) 1,
(TaskHandle_t) (&AppCreateTask_Handle));
if(xReturn == pdPASS)
{
printf("AppCreate_Task Create Succeed!\r\n");
vTaskStartScheduler();//启动任务调度
}
else{printf("AppCreate_Task Create Fail!\r\n");}
while(1);
}
AppTask.h
#ifndef _AppTask_H_
#define _AppTask_H_
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "bsp_led.h"
#include "bsp_usart.h"
extern TaskHandle_t AppCreateTask_Handle;
extern void AppCreate_Task(void* parameter);
#endif
AppTask.c
#include "AppTask.h"
TaskHandle_t AppCreateTask_Handle = NULL;
static TaskHandle_t LowPriority_Handle = NULL;
static TaskHandle_t MidPriority_Handle = NULL;
static TaskHandle_t HigPriority_Handle = NULL;
SemaphoreHandle_t BinarySem_Handle = NULL;
void LowPriority_Task(void* parameter);
void MidPriority_Task(void* parameter);
void HigPriority_Task(void* parameter);
/**************************************
* function:创建App任务函数
* parameter:void*
* return:void
* date:2022.3.21
* note:
* ***********************************/
void AppCreate_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
taskENTER_CRITICAL();
BinarySem_Handle = xSemaphoreCreateBinary();
if(BinarySem_Handle == NULL){printf("BinarySem_Handle Create Fail!\r\n");}
else{printf("BinarySem_Handle Create Succend!\r\n");}
xReturn = xSemaphoreGive(BinarySem_Handle);
if ( xReturn == pdTRUE )
printf("BinarySem_Handle 二值信号量释放成功!\r\n");
else
printf("BinarySem_Handle 二值信号量释放失败!\r\n");
xReturn = xTaskCreate((TaskFunction_t) LowPriority_Task,\
(const char*) "LowPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 2,\
(TaskHandle_t*) &LowPriority_Handle);
if(xReturn != pdPASS){printf("LowPriority Create Fail!\r\n");}
else{printf("LowPriority Create Succeed!\r\n");}
xReturn = xTaskCreate((TaskFunction_t) MidPriority_Task,\
(const char*) "MidPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 3,\
(TaskHandle_t*) &MidPriority_Handle);
if(xReturn != pdPASS){printf("MidPriority Create Fail!\r\n");}
else{printf("MidPriority Create Succeed!\r\n");}
xReturn = xTaskCreate((TaskFunction_t) HigPriority_Task,\
(const char*) "HigPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 4,\
(TaskHandle_t*) &HigPriority_Handle);
if(xReturn != pdPASS){printf("HigPriority Create Fail!\r\n");}
else{printf("HigPriority Create Succeed!\r\n");}
vTaskDelete(AppCreateTask_Handle);
taskEXIT_CRITICAL();
}
void LowPriority_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
unsigned long int i = 0;
while(1)
{
printf("LowPriority_Task 获取信号量\r\n");
xReturn = xSemaphoreTake(BinarySem_Handle,portMAX_DELAY);
if(xReturn == pdTRUE)
{
printf("LowPriority_Task Run...\r\n");
for(i=0;i < 2000000;i++){taskYIELD();}
printf("LowPriority_Task 释放信号量\r\n");
xReturn = xSemaphoreGive(BinarySem_Handle);
vTaskDelay(1000);
}
else{printf("LowPriority_Task xSemaphoreTake Fail!\r\n");}
}
}
void MidPriority_Task(void* parameter)
{
while(1)
{
LED1_TOGGLE;vTaskDelay(1000); printf("MidPriority_Task Run...\r\n");
}
}
void HigPriority_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
while(1)
{
printf("HigPriority_Task 获取信号量\r\n");
xReturn = xSemaphoreTake(BinarySem_Handle,portMAX_DELAY);
if(xReturn == pdTRUE)
{
printf("HigPriority_Task Run...\r\n");
printf("HigPriority_Task 释放信号量\r\n");
xReturn = xSemaphoreGive(BinarySem_Handle);
vTaskDelay(1000);
}
else{printf("HigPriority_Task xSemaphoreTake Fail!\r\n");}
}
}
示例现象:
注:低优先级任务执行过程中,高优先级任务插队运行没有获取到信号量而阻塞,故低优先级任务继续执行,被中优先级任务抢占执行,导致中间多个中优先级任务执行完后低优先级才能释放信号量,高优先级任务获取到信号而继续执行。
但是高优先级任务被打断占用较多时间,此时程序设计已经出现不想要的结果。
互斥信号量演示:
AppTask.c
#include "AppTask.h"
TaskHandle_t AppCreateTask_Handle = NULL;
static TaskHandle_t LowPriority_Handle = NULL;
static TaskHandle_t MidPriority_Handle = NULL;
static TaskHandle_t HigPriority_Handle = NULL;
SemaphoreHandle_t MutexSem_Handle = NULL;
void LowPriority_Task(void* parameter);
void MidPriority_Task(void* parameter);
void HigPriority_Task(void* parameter);
/**************************************
* function:创建App任务函数
* parameter:void*
* return:void
* date:2022.3.21
* note:
* ***********************************/
void AppCreate_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
taskENTER_CRITICAL();
MutexSem_Handle = xSemaphoreCreateMutex();
if(MutexSem_Handle == NULL){printf("MutexSem_Handle Create Fail!\r\n");}
else{printf("MutexSem_Handle Create Succend!\r\n");}
xReturn = xSemaphoreGive(MutexSem_Handle);
if ( xReturn == pdTRUE )
printf("MutexSem_Handle 二值信号量释放成功!\r\n");
else
printf("MutexSem_Handle 二值信号量释放失败!\r\n");
xReturn = xTaskCreate((TaskFunction_t) LowPriority_Task,\
(const char*) "LowPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 2,\
(TaskHandle_t*) &LowPriority_Handle);
if(xReturn != pdPASS){printf("LowPriority Create Fail!\r\n");}
else{printf("LowPriority Create Succeed!\r\n");}
xReturn = xTaskCreate((TaskFunction_t) MidPriority_Task,\
(const char*) "MidPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 3,\
(TaskHandle_t*) &MidPriority_Handle);
if(xReturn != pdPASS){printf("MidPriority Create Fail!\r\n");}
else{printf("MidPriority Create Succeed!\r\n");}
xReturn = xTaskCreate((TaskFunction_t) HigPriority_Task,\
(const char*) "HigPriority_Task",\
(uint16_t) 128,\
(void*) NULL,\
(UBaseType_t) 4,\
(TaskHandle_t*) &HigPriority_Handle);
if(xReturn != pdPASS){printf("HigPriority Create Fail!\r\n");}
else{printf("HigPriority Create Succeed!\r\n");}
vTaskDelete(AppCreateTask_Handle);
taskEXIT_CRITICAL();
}
void LowPriority_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
unsigned long int i = 0;
while(1)
{
printf("LowPriority_Task 获取信号量\r\n");
xReturn = xSemaphoreTake(MutexSem_Handle,portMAX_DELAY);
if(xReturn == pdTRUE)
{
printf("LowPriority_Task Run...\r\n");
for(i=0;i < 2000000;i++){taskYIELD();}
printf("LowPriority_Task 释放信号量\r\n");
xReturn = xSemaphoreGive(MutexSem_Handle);
vTaskDelay(1000);
}
else{printf("LowPriority_Task xSemaphoreTake Fail!\r\n");}
}
}
void MidPriority_Task(void* parameter)
{
while(1)
{
LED1_TOGGLE;vTaskDelay(1000); printf("MidPriority_Task Run...\r\n");
}
}
void HigPriority_Task(void* parameter)
{
BaseType_t xReturn = pdPASS;
while(1)
{
printf("HigPriority_Task 获取信号量\r\n");
xReturn = xSemaphoreTake(MutexSem_Handle,portMAX_DELAY);
if(xReturn == pdTRUE)
{
printf("HigPriority_Task Run...\r\n");
printf("HigPriority_Task 释放信号量\r\n");
xReturn = xSemaphoreGive(MutexSem_Handle);
vTaskDelay(1000);
}
else{printf("HigPriority_Task xSemaphoreTake Fail!\r\n");}
}
}
演示现象: