互斥量又称互斥信号量(本质是信号量),是一种特殊的二值信号量,它和 信号量不同的是,它支持互斥量所有权、递归访问以及防止优先级翻转的特性, 用于实现对临界资源的独占式处理。本章要实现的功能是:创建了 3 个任务与 1 个二值信号量,任务分别是高优先级任务,中优先级任务,低优先级任务,用于 模拟产生优先级翻转。低优先级任务在获取信号量的时候,被中优先级打断,中 优先级的任务执行时间较长,因为低优先级还未释放信号量,那么高优先级任务 就无法取得信号量继续运行,此时就发生了优先级翻转,任务在运行中,使用串 口打印出相关信息。本章分为如下几部分内容: 8.1 互斥量简介 8.2 常用互斥量 API 函数 8.3 硬件设计 8.4 软件设计 8.5 实验现 象
8.1 互斥量简介
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中 (任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于 那些需要互斥访问的应用中。在互斥访问中互斥信号量相当于一个钥匙,当任务 想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个 钥匙,这样其他的任务就可以拿着这个钥匙去使用资源。 互斥信号量使用和二值信号量相同的 API 操作函数,所以互斥信号量也可 以设置阻塞时间,不同于二值信号量的是互斥信号量具有优先级继承的特性。当 一个互斥信号量正在被一个低优先级的任务使用,而此时有个高优先级的任务也 尝试获取这个互斥信号量的话就会被阻塞。不过这个高优先级的任务会将低优先 级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级 继承尽可能的降低了高优先级任务处于阻塞态的时间,并且将已经出现的“优先 级翻转”的影响降到最低。
8.1.1 互斥量的优先级继承机制
在 FreeRTOS 操作系统中为了降低优先级翻转问题利用了优先级继承算法。 优先级继承算法是指,暂时提高某个占有某种资源的低优先级任务的优先级,使 之与在所有等待该资源的任务中优先级最高那个任务的优先级相等,而当这个低 优先级任务执行完毕释放该资源时,优先级重新回到初始设定值。因此,继承优 先级的任务避免了系统资源被任何中间优先级的任务抢占。 互斥量与二值信号量最大的不同是:互斥量具有优先级继承机制,而信号量 没有。也就是说,某个临界资源受到一个互斥量保护,如果这个资源正在被一个 低优先级任务使用,那么此时的互斥量是闭锁状态,也代表了没有任务能申请到 这个互斥量,如果此时一个高优先级任务想要对这个资源进行访问,去申请这个 互斥量,那么高优先级任务会因为申请不到互斥量而进入阻塞态,那么系统会将 现在持有该互斥量的任务的优先级临时提升到与高优先级任务的优先级相同,这 个优先级提升的过程叫做优先级继承。这个优先级继承机制确保高优先级任务进 入阻塞状态的时间尽可能短,以及将已经出现的“优先级翻转”危害降低到最小。 没有理解?没问题,结合过程示意图再说一遍。我们知道任务的优先级在创 建的时候就已经是设置好的,高优先级的任务可以打断低优先级的任务,抢占 CPU 的使用权。但是在很多场合中,某些资源只有一个,当低优先级任务正在占 用该资源的时候,即便高优先级任务也只能乖乖的等待低优先级任务使用完该资 源后释放资源。这里高优先级任务无法运行而低优先级任务可以运行的现象称为 “优先级翻转”。 为什么说优先级翻转在操作系统中是危害很大?因为在我们一开始创造这 个系统的时候,我们就已经设置好了任务的优先级了,越重要的任务优先级越高。 但是发生优先级翻转,对我们操作系统是致命的危害,会导致系统的高优先级任 务阻塞时间过长。 举个例子,现在有 3 个任务分别为 H 任务(High)、M 任务(Middle)、 L 任务(Low),3 个任务的优先级顺序为 H 任务>M 任务>L 任务。正常运行的 时候 H 任务可以打断 M 任务与 L 任务,M 任务可以打断 L 任务,假设系统中 有一个资源被保护了,此时该资源被 L 任务正在使用中,某一刻,H 任务需要 使用该资源,但是 L 任务还没使用完,H 任务则因为申请不到资源而进入阻塞 态,L 任务继续使用该资源,此时已经出现了“优先级翻转”现象,高优先级任 务在等着低优先级的任务执行,如果在 L 任务执行的时候刚好 M 任务被唤醒 了,由于 M 任务优先级比 L 任务优先级高,那么会打断 L 任务,抢占了 CPU 的 使用权,直到 M 任务执行完,再把 CUP 使用权归还给 L 任务,L 任务继续执 行,等到执行完毕之后释放该资源,H 任务此时才从阻塞态解除,使用该资源。 这个过程,本来是最高优先级的 H 任务,在等待了更低优先级的 L 任务与 M 任 务,其阻塞的时间是 M 任务运行时间+L 任务运行时间,这只是只有 3 个任务 的系统,假如很多个这样子的任务打断最低优先级的任务,那这个系统最高优先 级任务岂不是崩溃了,这个现象是绝对不允许出现的,高优先级的任务必须能及 时响应。所以,没有优先级继承的情况下,使用资源保护,其危害极大如下图。
图(1):L 任务正在使用某临界资源, H 任务被唤醒,执行 H 任务。但 L 任 务并未执行完毕,此时临界资源还未释放。 图(2):这个时刻 H 任务也要对该临界资源进行访问,但 L 任务还未释放 资源,由于保护机制,H 任务进入阻塞态,L 任务得以继续运行,此时已经发生 了优先级翻转现象。 图(3):某个时刻 M 任务被唤醒,由于 M 任务的优先级高于 L 任务, M 任 务抢占了 CPU 的使用权,M 任务开始运行,此时 L 任务尚未执行完,临界资源 还没被释放。 图(4):M 任务运行结束,归还 CPU 使用权,L 任务继续运行。 图(5):L 任务运行结束,释放临界资源,H 任务得以对资源进行访问,H 任 务开始运行。 在这过程中,H 任务的等待时间过长,这对系统来说这是很致命的,所以这 种情况不允许出现,而互斥量就是用来降低优先级翻转的产生的危害。 假如有优先级继承呢?那么,在 H 任务申请该资源的时候,由于申请不到 资源会进入阻塞态,那么系统就会把当前正在使用资源的 L 任务的优先级临时 提高到与 H 任务优先级相同,此时 M 任务被唤醒了,因为它的优先级比 H 任 务低,所以无法打断 L 任务,因为此时 L 任务的优先级被临时提升到 H,所以 当 L 任务使用完该资源了,进行释放,那么此时 H 任务优先级最高,将接着抢 占 CPU 的使用权, H 任务的阻塞时间仅仅是 L 任务的执行时间,此时的优先 级的危害降到了最低,看!这就是优先级继承的优势,具体如下图。
图(1):L 任务正在使用某临界资源,L 任务正在使用某临界资源,H 任务被 唤醒,执行 H 任务。但 L 任务并未执行完毕,此时临界资源还未释放。 图(2):某一时刻 H 任务也要对该资源进行访问,由于保护机制,H 任务进 入阻塞态。此时发生优先级继承,系统将 L 任务的优先级暂时提升到与 H 任务 优先级相同,L 任务继续执行。 图(3):在某一时刻 M 任务被唤醒,由于此时 M 任务的优先级暂时低于 L 任务,所以 M 任务仅在就绪态,而无法获得 CPU 使用权。 图(4):L 任务运行完毕,H 任务获得对资源的访问权,H 任务从阻塞态变成 运行态,此时 L 任务的优先级会变回原来的优先级。 图(5):当 H 任务运行完毕,M 任务得到 CPU 使用权,开始执行。 图(6):系统正常运行,按照设定好的优先级运行。 但是使用互斥量的时候一定需要注意:在获得互斥量后,请尽快释放互斥量, 同时需要注意的是在任务持有互斥量的这段时间,不得更改任务的优先级。 FreeRTOS 的优先级继承机制不能解决优先级反转,只能将这种情况的影响降低 到最小,硬实时系统在一开始设计时就要避免优先级反转发生。
8.1.2 互斥量应用场景
互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。 在初始化的时候,互斥量处于开锁的状态,而被任务持有的时候则立刻转为闭锁 的状态。互斥量更适合于: ●可能会引起优先级翻转的情况。 递归互斥量更适用于: ●任务可能会多次获取互斥量的情况下。这样可以避免同一任务多次递归持 有而造成死锁的问题。 多任务环境下往往存在多个任务竞争同一临界资源的应用场景,互斥量可被 用于对临界资源的保护从而实现独占式访问。另外,互斥量可以降低信号量存在 的优先级翻转问题带来的影响。 比如有两个任务需要对串口进行发送数据,其硬件资源只有一个,那么两个 任务肯定不能同时发送啦,不然导致数据错误,那么,就可以用互斥量对串口资 源进行保护,当一个任务正在使用串口的时候,另一个任务则无法使用串口,等 到任务使用串口完毕之后,另外一个任务才能获得串口的使用权。 另外需要注意的是互斥量不能在中断服务函数中使用,因为其特有的优先级 继承机制只在任务起作用,在中断的上下文环境毫无意
8.2 常用互斥量 API 函数
8.2.1 互斥量创建函数 xSemaphoreCreateMutex(
xSemaphoreCreateMutex()用于创建一个互斥量,并返回一个互斥量句柄。 该句柄的原型是一个 void 型的指针,在使用之前必须先由用户定义一个互斥量 句柄。要想使用该函数必须在 FreeRTOSConfig.h 中把宏 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1, 即开启动态内存分配,其实该 宏在 FreeRTOS.h 中默认定义为 1,即所有 FreeRTOS 的对象在创建的时候都默 认使用动态内存分配方案,同时还需在 FreeRTOSConfig.h 中把 configUSE_MUTEXES 宏定义打开,表示使用互斥量。
8.2.2 递归互斥量创建函数 xSemaphoreCreateRecursiveMutex()
xSemaphoreCreateRecursiveMutex()用于创建一个递归互斥量,不是递归的 互斥量由函数 xSemaphoreCreateMutex() 或 xSemaphoreCreateMutexStatic() 创建(我们只讲解动态创建),且只能被同一个任务获取一次,如果同一个任务 想再次获取则会失败。递归信号量则相反,它可以被同一个任务获取很多次,获 取多少次就需要释放多少次。递归信号量与互斥量一样,都实现了优先级继承机 制,可以降低优先级反转的危害。 要想使用该函数必须在 FreeRTOSConfig.h 中把宏 configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_MUTEXES 均定 义为 1。宏 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1 即表示开启动态内 存分配,其实该宏在 FreeRTOS.h 中默认定义为 1,即所有 FreeRTOS 的对象在 创建的时候都默认使用动态内存分配方案。该函数的具体说明如下:
8.2.3 互斥量删除函数 vSemaphoreDelete()
互斥量的本质是信号量,直接调用 vSemaphoreDelete()函数进行删除即可。
8.2.4 互斥量获取函数 xSemaphoreTake()
我们知道,当互斥量处于开锁的状态,任务才能获取互斥量成功,当任务持 有了某个互斥量的时候,其它任务就无法获取这个互斥量,需要等到持有互斥量 的任务进行释放后,其他任务才能获取成功,任务通过互斥量获取函数来获取互 斥量的所有权。任务对互斥量的所有权是独占的,任意时刻互斥量只能被一个任 务持有,如果互斥量处于开锁状态,那么获取该互斥量的任务将成功获得该互斥 量,并拥有互斥量的使用权;如果互斥量处于闭锁状态,获取该互斥量的任务将 无法获得互斥量,任务将被挂起,在任务被挂起之前,会进行优先级继承,如果 当前任务优先级比持有互斥量的任务优先级高,那么将会临时提升持有互斥量任 务的优先级。互斥量的获取函数是一个宏定义,实际调用的函数就是 xQueueGenericReceive(),
8.2.5 递归互斥量获取函数 xSemaphoreTakeRecursive()
xSemaphoreTakeRecursive()是一个用于获取递归互斥量的宏,与互斥量的 获取函数一样,xSemaphoreTakeRecursive()也是一个宏定义,它最终使用现有 的队列机制,实际执行的函数是 xQueueTakeMutexRecursive()。互斥量之前必 须由 xSemaphoreCreateRecursiveMutex()这个函数创建。要注意的是该函数不 能用于获取由函数 xSemaphoreCreateMutex()创建的互斥量。要想使用该函数必 须在头文件 FreeRTOSConfig.h 中把宏 configUSE_RECURSIVE_MUTEXES 定义为 1。该函数的具体说明如下。
8.2.6 互斥量释放函数 xSemaphoreGive()
任务想要访问某个资源的时候,需要先获取互斥量,然后进行资源访问,在 任务使用完该资源的时候,必须要及时归还互斥量,这样别的任务才能对资源进 行访问。在前面的讲解中,我们知道,当互斥量有效的时候,任务才能获取互斥 量,那么,是什么函数使得信号量变得有效呢?FreeRTOS 给我们提供了互斥量 释放函数 xSemaphoreGive(),任务可以调用 xSemaphoreGive()函数进行释放互 斥量,表示我已经用完了,别人可以申请使用,互斥量的释放函数与信号量的释 放函数一致,都是调用 xSemaphoreGive()函数,但是要注意的是,互斥量的释 放只能在任务中,不允许在中断中释放互斥量
8.2.7 递归互斥量释放函数 xSemaphoreGiveRecursive()
xSemaphoreGiveRecursive()是一个用于释放递归互斥量的宏。
8.3整体代码
优先级翻转代码
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "semphr.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 2
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
//任务优先级
#define LowPriority_TASK_PRIO 3
//任务堆栈大小
#define LowPriority_STK_SIZE 512
//任务句柄
TaskHandle_t LowPriority_Task_Handle;
//任务函数
void LowPriority_Task(void *pvParameters);
//任务优先级
#define MidPriority_TASK_PRIO 4
//任务堆栈大小
#define MidPriority_STK_SIZE 512
//任务句柄
TaskHandle_t MidPriority_Task_Handle;
//任务函数
void MidPriority_Task(void *pvParameters);
//任务优先级
#define HighPriority_TASK_PRIO 5
//任务堆栈大小
#define HighPriority_STK_SIZE 512
//任务句柄
TaskHandle_t HighPriority_Task_Handle;
//任务函数
void HighPriority_Task(void *pvParameters);
SemaphoreHandle_t BinarySem_Handle =NULL;
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
LED_Init();
KEY_Init();
USART1_Init(115200);
printf("FreeRTOS优先级翻转实验\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(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
BaseType_t xReturn = pdPASS;
taskENTER_CRITICAL(); //进入临界区
/* 创建 BinarySem */
BinarySem_Handle = xSemaphoreCreateBinary();
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
//创建低优先级任务
xTaskCreate((TaskFunction_t )LowPriority_Task,
(const char* )"LowPriority_Task",
(uint16_t )LowPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )LowPriority_TASK_PRIO,
(TaskHandle_t* )&LowPriority_Task_Handle);
//创建中优先级任务
xTaskCreate((TaskFunction_t )MidPriority_Task,
(const char* )"MidPriority_Task",
(uint16_t )MidPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )MidPriority_TASK_PRIO,
(TaskHandle_t* )&MidPriority_Task_Handle);
//创建高优先级任务
xTaskCreate((TaskFunction_t )HighPriority_Task,
(const char* )"HighPriority_Task",
(uint16_t )HighPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )HighPriority_TASK_PRIO,
(TaskHandle_t* )&HighPriority_Task_Handle);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
//低优先级任务函数
void LowPriority_Task(void *pvParameters)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
static uint32_t i=0;
while(1)
{
printf("LowPriority_Task 获取信号量\n");
//获取二值信号量 xSemaphore,没获取到则一直等待
xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
portMAX_DELAY); /* 等待时间 */
if( xReturn == pdTRUE )
printf("LowPriority_Task Running\n\n");
for(i=0;i<2000000;i++)//模拟低优先级任务占用信号量
{
taskYIELD();//发起任务调度
}
printf("LowPriority_Task 释放信号量!\r\n");
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
LED2=!LED2;
vTaskDelay(500);
}
}
//中优先级任务函数
void MidPriority_Task(void *pvParameters)
{
while(1)
{
printf("MidPriority_Task Running\n");
vTaskDelay(500);
}
}
//高优先级任务函数
void HighPriority_Task(void *pvParameters)
{
BaseType_t xReturn = pdTRUE;
while(1)
{
printf("HighPriority_Task 获取信号量\n");
//获取二值信号量 xSemaphore,没获取到则一直等待
xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
portMAX_DELAY); /* 等待时间 */
if(pdTRUE == xReturn)
printf("HighPriority_Task Running\n");
LED2=!LED2;
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
vTaskDelay(500);
}
}
使用互斥量解决优先级翻转代码
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "semphr.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 2
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
//任务优先级
#define LowPriority_TASK_PRIO 3
//任务堆栈大小
#define LowPriority_STK_SIZE 512
//任务句柄
TaskHandle_t LowPriority_Task_Handle;
//任务函数
void LowPriority_Task(void *pvParameters);
//任务优先级
#define MidPriority_TASK_PRIO 4
//任务堆栈大小
#define MidPriority_STK_SIZE 512
//任务句柄
TaskHandle_t MidPriority_Task_Handle;
//任务函数
void MidPriority_Task(void *pvParameters);
//任务优先级
#define HighPriority_TASK_PRIO 5
//任务堆栈大小
#define HighPriority_STK_SIZE 512
//任务句柄
TaskHandle_t HighPriority_Task_Handle;
//任务函数
void HighPriority_Task(void *pvParameters);
SemaphoreHandle_t MuxSem_Handle =NULL;
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
LED_Init();
KEY_Init();
USART1_Init(115200);
printf("FreeRTOS互斥量实验\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(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
/* 创建MuxSem */
MuxSem_Handle = xSemaphoreCreateMutex();
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
//创建低优先级任务
xTaskCreate((TaskFunction_t )LowPriority_Task,
(const char* )"LowPriority_Task",
(uint16_t )LowPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )LowPriority_TASK_PRIO,
(TaskHandle_t* )&LowPriority_Task_Handle);
//创建中优先级任务
xTaskCreate((TaskFunction_t )MidPriority_Task,
(const char* )"MidPriority_Task",
(uint16_t )MidPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )MidPriority_TASK_PRIO,
(TaskHandle_t* )&MidPriority_Task_Handle);
//创建高优先级任务
xTaskCreate((TaskFunction_t )HighPriority_Task,
(const char* )"HighPriority_Task",
(uint16_t )HighPriority_STK_SIZE,
(void* )NULL,
(UBaseType_t )HighPriority_TASK_PRIO,
(TaskHandle_t* )&HighPriority_Task_Handle);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
//低优先级任务函数
void LowPriority_Task(void *pvParameters)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
static uint32_t i=0;
while(1)
{
printf("LowPriority_Task 获取互斥量\n");
//获取互斥量 MuxSem,没获取到则一直等待
xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
portMAX_DELAY); /* 等待时间 */
if( xReturn == pdTRUE )
printf("LowPriority_Task Running\n\n");
for(i=0;i<2000000;i++)//模拟低优先级任务占用互斥量
{
taskYIELD();//发起任务调度
}
printf("LowPriority_Task 释放互斥量!\r\n");
xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量
LED2=!LED2;
vTaskDelay(500);
}
}
//中优先级任务函数
void MidPriority_Task(void *pvParameters)
{
while(1)
{
printf("MidPriority_Task Running\n");
vTaskDelay(500);
}
}
//高优先级任务函数
void HighPriority_Task(void *pvParameters)
{
BaseType_t xReturn = pdTRUE;
while(1)
{
printf("HighPriority_Task 获取互斥量\n");
//获取互斥量 MuxSem,没获取到则一直等待
xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
portMAX_DELAY); /* 等待时间 */
if(pdTRUE == xReturn)
printf("HighPriority_Task Running\n");
LED2=!LED2;
xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量
vTaskDelay(500);
}
}