1互斥信号量的概念
1)互斥信号量:是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!
2)优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
3)互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
4)中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
2 互斥信号量的使用流程
1)使用互斥信号量:首先将宏configUSE_MUTEXES置一
2)使用流程:创建互斥信号量 ->(task)获取信号量 ->(give)释放信号量
3 互斥信号量API函数
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
返回值: NULL 创建失败
其他 返回信号量失败
互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不支持中断中调用
注意:创建互斥信号量时,会主动释放一次信号量
4 互斥信号量实战
实验设计:将优先级翻转所用到的信号量函数,修改成互斥信号量即可,通过串口打印提示信息
4.1 freertos_demo.c
#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
//FreeRTOS配置
//1.任务配置
//1.1 START_TASK 任务 配置
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
//1.2 TASK1 任务 配置
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t lowTask_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
//1.2 TASK2 任务 配置
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t middleTask_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 */
//1.3 TASK3 任务 配置
#define TASK3_PRIO 4 /* 任务优先级 */
#define TASK3_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t highTask_Handler; /* 任务句柄 */
void task3(void *pvParameters); /* 任务函数 */
//1.4 二值信号量句柄定义
SemaphoreHandle_t mutexSemaphore;
//2.在freertos_demo函数中创建start_task任务
void freertos_demo(void)
{
//创建互斥信号量
mutexSemaphore = xSemaphoreCreateMutex(); //互斥型信号量创建成功后会释放一次信号量
if(mutexSemaphore != NULL)
{
printf("二值信号量创建成功!!!\r\n");
}
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
//3.在start_task函数中创建task1、task2任务
void start_task(void *pvParameters)
{
//进入临界区
taskENTER_CRITICAL();
//创建任务1
xTaskCreate((TaskFunction_t )task1, /* 任务函数 */
(const char* )"task1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&lowTask_Handler); /* 任务句柄 */
//创建任务2
xTaskCreate((TaskFunction_t )task2, /* 任务函数 */
(const char* )"task2", /* 任务名称 */
(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK2_PRIO, /* 任务优先级 */
(TaskHandle_t* )&middleTask_Handler); /* 任务句柄*/
//创建任务3
xTaskCreate((TaskFunction_t )task3, /* 任务函数 */
(const char* )"task3", /* 任务名称 */
(uint16_t )TASK3_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK3_PRIO, /* 任务优先级 */
(TaskHandle_t* )&highTask_Handler); /* 任务句柄*/
//删除开始任务
vTaskDelete(StartTask_Handler);
//退出临界区
taskEXIT_CRITICAL();
}
//4.任务一 低优先级任务
void task1(void *pvParameters)
{
while (1)
{
printf("low Task获取信号量\r\n");
xSemaphoreTake(mutexSemaphore, portMAX_DELAY);
printf("low Task正在运行\r\n");
delay_ms(3000);
printf("low Task正在释放信号量\r\n");
xSemaphoreGive(mutexSemaphore);
vTaskDelay(1000);
}
}
//5.任务二 中优先级任务
void task2(void *pvParameters)
{
while(1)
{
printf("middle Task正在释放信号量\r\n");
vTaskDelay(1000);
}
}
//6.任务三 高优先级任务
void task3(void *pvParameters)
{
while(1)
{
printf("high Task获取信号量\r\n");
xSemaphoreTake(mutexSemaphore, portMAX_DELAY);
printf("high Task正在运行\r\n");
delay_ms(1000);
printf("high Task正在释放信号量\r\n");
xSemaphoreGive(mutexSemaphore);
vTaskDelay(1000);
}
}