FreeRTOS-互斥信号量(五)

介绍互斥信号量所用到的函数

1.互斥量创建函数

xSemaphoreCreateMutex() 
功能:互斥量创建函数
参 数:void 无
返回值:返回一个互斥量句柄 

2.互斥量获取函数

 xSemaphoreTake( xSemaphore, xBlockTime )
参数:
xSemaphore:互斥量句柄
xBlockTime :
 				portMAX_DELAY 没有申请到资源阻塞,
				 0 申请到立马返回

3.互斥量释放函数

 xSemaphoreGive( xSemaphore )
参数:
xSemaphore :互斥量句柄

4.模拟优先级翻转代码

模拟优先级翻转实验是在 FreeRTOS 中创建了三个任务与一个二值信号量,任务分别是高优先级任务,中优先级任务,低优先级任务, 用于模拟产生优先级翻转。
低优先级任 务在获取信号量的时候,被中优先级打断,中优先级的任务执行时间较长,因为低优先级还未释放信号量,那么高优先级任务就无法取得信号量继续运行,此时就发生了优先级翻 转,

#include "main.h"

static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
static TaskHandle_t LowPriority_Task_Handle = NULL;/* LowPriority_Task 任务句柄 */ 
static TaskHandle_t MidPriority_Task_Handle = NULL;/* MidPriority_Task 任务句柄 */
static TaskHandle_t HighPriority_Task_Handle = NULL;/* HighPriority_Task 任务句柄 */ 

SemaphoreHandle_t BinarySem_Handle =NULL;
static void AppTaskCreate(void);/* 用于创建任务 */

static void LowPriority_Task(void* pvParameters);/* LowPriority_Task 任务实现 */
static void MidPriority_Task(void* pvParameters);/* MidPriority_Task 任务实现 */
static void HighPriority_Task(void* pvParameters);/* MidPriority_Task 任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 */ 

int main(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	BSP_Init();	/* 开发板硬件初始化 */
	printf("优先级翻转实验! \n");

xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /*任务入口函数 */
						(const char* )"AppTaskCreate",/* 任务名字 */
						(uint16_t )512, /* 任务栈大小 */
						(void* )NULL,/* 任务入口函数参数 */ 
						(UBaseType_t )1, /* 任务的优先级 */
						(TaskHandle_t*)&AppTaskCreate_Handle);/* 任务控制块指针 */
	 /* 启动任务调度 */
	 if (pdPASS == xReturn)
		 vTaskStartScheduler(); /* 启动任务,开启调度 */
	 else
		 return -1;
} 


static void AppTaskCreate(void)
 {
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	 taskENTER_CRITICAL(); //进入临界区

	 BinarySem_Handle = xSemaphoreCreateBinary();
	 if (NULL != BinarySem_Handle )
	 printf("BinarySem_Handle 二值信号量创建成功!\r\n");

	 xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量

/* 创建 LowPriority_Task 任务 */
xReturn = xTaskCreate((TaskFunction_t )LowPriority_Task, /* 任务入口函数 */
 						(const char* )"LowPriority_Task",/*任务名字 */
						(uint16_t )512, /* 任务栈大小 */
 						(void* )NULL, /* 任务入口函数参数 */
						(UBaseType_t )2, /* 任务的优先级 */
 					(TaskHandle_t* )&LowPriority_Task_Handle);/* 任务控制块指针 */
 if (pdPASS == xReturn)
	 printf("创建 LowPriority_Task 任务成功!\r\n");

 /* 创建 MidPriority_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )MidPriority_Task, /* 任务入口函数 */
						 (const char* )"MidPriority_Task",/*任务名字 */
 						 (uint16_t )512, /* 任务栈大小 */
						 (void* )NULL,/* 任务入口函数参数 */
						 (UBaseType_t )3, /* 任务的优先级 */
 						 (TaskHandle_t* )&MidPriority_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
	 printf("创建 MidPriority_Task 任务成功!\n");

 /* 创建 HighPriority_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )HighPriority_Task, /* 任务入口函数 */
 						(const char* )"HighPriority_Task",/* 任务名字 */
 						(uint16_t )512, /* 任务栈大小 */
 						(void* )NULL,/* 任务入口函数参数 */
 						(UBaseType_t )4, /* 任务的优先级 */
 						(TaskHandle_t* )&HighPriority_Task_Handle);/*任务控制块指针 */
	  if (pdPASS == xReturn)
		printf("创建 HighPriority_Task 任务成功!\n\n");
	
	 vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务
	 taskEXIT_CRITICAL(); //退出临界区
 }
 
 
static void LowPriority_Task(void* parameter)
 {
	 static uint32_t i;
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	 while (1) {
		 printf("LowPriority_Task 获取信号量\n");
		 //获取二值信号量 xSemaphore,没获取到则一直等待
		 xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
		 						portMAX_DELAY); /* 等待时间 */
		 if (pdTRUE == xReturn)
		 printf("LowPriority_Task Runing\n\n");
	
		 for (i=0; i<2000000; i++) //模拟低优先级任务占用互斥量
		 { 
		 	taskYIELD();//发起任务调度
	 	 }
		 printf("LowPriority_Task 释放信号量!\r\n");
		 xReturn = xSemaphoreGive( BinarySem_Handle);//给出二值信号量
		 LED1_TOGGLE;
		 vTaskDelay(1000);
	 }
 }
 
 static void MidPriority_Task(void* parameter)
 {
	 while (1) 
	 {
		 printf("MidPriority_Task Runing\n");
		 vTaskDelay(1000);
	 }
 }
 
 static void HighPriority_Task(void* parameter)
 {
	 BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为 pdPASS */
	 while (1)
	  {
		 printf("HighPriority_Task 获取信号量\n");
		 //获取互斥量 MuxSem,没获取到则一直等待
		 xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
		 						portMAX_DELAY); /* 等待时间 */
		 if (pdTRUE == xReturn)
		 printf("HighPriority_Task Runing\n");
		 LED1_TOGGLE;
		 printf("HighPriority_Task 释放信号量!\r\n");
		 xReturn = xSemaphoreGive( BinarySem_Handle);//给出二值信号量
		 vTaskDelay(1000);
	 }
 }
 
 static void BSP_Init(void)
 {
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
	LED_GPIO_Config();
	USART_Config();
	Key_GPIO_Config();
 }

5.互斥量代码

互斥量实验是基于优先级翻转实验进行修改的,目的是为了测试互斥量的优先级继承机制是否有效

 #include "main.h"

static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
static TaskHandle_t LowPriority_Task_Handle = NULL;/* LowPriority_Task 任务句柄 */ 
static TaskHandle_t MidPriority_Task_Handle = NULL;/* MidPriority_Task 任务句柄 */
static TaskHandle_t HighPriority_Task_Handle = NULL;/* HighPriority_Task 任务句柄 */ 

SemaphoreHandle_t MuxSem_Handle =NULL; 
static void AppTaskCreate(void);/* 用于创建任务 */

static void LowPriority_Task(void* pvParameters);/* LowPriority_Task 任务实现 */
static void MidPriority_Task(void* pvParameters);/* MidPriority_Task 任务实现 */
static void HighPriority_Task(void* pvParameters);/* MidPriority_Task 任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 */ 
int main(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	BSP_Init();	/* 开发板硬件初始化 */
	printf("互斥信号量实验! \n");

xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /*任务入口函数 */
						(const char* )"AppTaskCreate",/* 任务名字 */
						(uint16_t )512, /* 任务栈大小 */
						(void* )NULL,/* 任务入口函数参数 */ 
						(UBaseType_t )1, /* 任务的优先级 */
						(TaskHandle_t*)&AppTaskCreate_Handle);/* 任务控制块指针 */
	 /* 启动任务调度 */
	 if (pdPASS == xReturn)
		 vTaskStartScheduler(); /* 启动任务,开启调度 */
	 else
		 return -1;
} 

static void AppTaskCreate(void)
 {
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	 taskENTER_CRITICAL(); //进入临界区

	 MuxSem_Handle = xSemaphoreCreateMutex();
	 if (NULL != MuxSem_Handle)
	 printf("MuxSem_Handle 互斥量创建成功!\r\n");

	 xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量

/* 创建 LowPriority_Task 任务 */
xReturn = xTaskCreate((TaskFunction_t )LowPriority_Task, /* 任务入口函数 */
 						(const char* )"LowPriority_Task",/*任务名字 */
						(uint16_t )512, /* 任务栈大小 */
 						(void* )NULL, /* 任务入口函数参数 */
						(UBaseType_t )2, /* 任务的优先级 */
 					(TaskHandle_t* )&LowPriority_Task_Handle);/* 任务控制块指针 */
	 if (pdPASS == xReturn)
	 printf("创建 LowPriority_Task 任务成功!\r\n");

 /* 创建 MidPriority_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )MidPriority_Task, /* 任务入口函数 */
						 (const char* )"MidPriority_Task",/*任务名字 */
 						 (uint16_t )512, /* 任务栈大小 */
						 (void* )NULL,/* 任务入口函数参数 */
						 (UBaseType_t )3, /* 任务的优先级 */
 						 (TaskHandle_t* )&MidPriority_Task_Handle);/* 任务控制块指针 */
	 if (pdPASS == xReturn)
	 printf("创建 MidPriority_Task 任务成功!\n");

 /* 创建 HighPriority_Task 任务 */
 xReturn = xTaskCreate((TaskFunction_t )HighPriority_Task, /* 任务入口函数 */
 						(const char* )"HighPriority_Task",/* 任务名字 */
 						(uint16_t )512, /* 任务栈大小 */
 						(void* )NULL,/* 任务入口函数参数 */
 						(UBaseType_t )4, /* 任务的优先级 */
 						(TaskHandle_t* )&HighPriority_Task_Handle);/*任务控制块指针 */
	  if (pdPASS == xReturn)
		printf("创建 HighPriority_Task 任务成功!\n\n");
	
	 vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务
	 taskEXIT_CRITICAL(); //退出临界区
 }
 
 
static void LowPriority_Task(void* parameter)
 {
	 static uint32_t i;
	 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	 while (1) {
		 printf("LowPriority_Task 获取信号量\n");

		 xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
		 						portMAX_DELAY); /* 等待时间 */
		 if (pdTRUE == xReturn)
		 printf("LowPriority_Task Runing\n\n");
	
		 for (i=0; i<2000000; i++) //模拟低优先级任务占用互斥量
		 { 
		 	taskYIELD();//发起任务调度
	 	 }

		 printf("LowPriority_Task 释放信号量!\r\n");
		 xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量
		 LED1_TOGGLE;
		 vTaskDelay(1000);
	 }
 }
 
 static void MidPriority_Task(void* parameter)
 {
	 while (1) 
	 {
	 printf("MidPriority_Task Runing\n");
	 vTaskDelay(1000);
	 }
 }
 
 static void HighPriority_Task(void* parameter)
 {
	 BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为 pdPASS */
	 while (1)
	  {
		 printf("HighPriority_Task 获取信号量\n");
		 //获取互斥量 MuxSem,没获取到则一直等待
		 xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
		 						portMAX_DELAY); /* 等待时间 */
		 if (pdTRUE == xReturn)
		 printf("HighPriority_Task Runing\n");
		 LED1_TOGGLE;
		 printf("HighPriority_Task 释放信号量!\r\n");
		 xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量
		 vTaskDelay(1000);
	 }
 }
 
 static void BSP_Init(void)
 {
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
	LED_GPIO_Config();
	USART_Config();
	Key_GPIO_Config();
 }

总结

优先级翻转问题与优先级继承这个概念一定要理解清楚。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS提供了互斥信号量(Mutex Semaphore)作为一种同步机制,它可以用于多个任务之间共享资源的访问。互斥信号量与二进制信号量(Binary Semaphore)的区别在于,互斥信号量可以防止不同任务之间同时访问共享资源,而二进制信号量只能用于任务之间的互斥访问。 互斥信号量的使用步骤如下: 1. 创建互斥信号量:使用xSemaphoreCreateMutex()函数创建一个互斥信号量。 2. 请求互斥信号量:使用xSemaphoreTake()函数请求一个互斥信号量。如果互斥信号量已被占用,则任务会进入阻塞状态,直到互斥信号量被释放为止。 3. 访问共享资源:在请求到互斥信号量后,任务可以安全地访问共享资源。 4. 释放互斥信号量:使用xSemaphoreGive()函数释放一个互斥信号量,以便其他任务可以获得它。 下面是一个使用互斥信号量的示例代码: ```c /* 创建互斥信号量 */ SemaphoreHandle_t xMutex = xSemaphoreCreateMutex(); /* 在任务中请求互斥信号量 */ void vTask1(void *pvParameters) { while (1) { /* 请求互斥信号量 */ if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { /* 访问共享资源 */ printf("Task 1 accessing shared resource...\n"); /* 释放互斥信号量 */ xSemaphoreGive(xMutex); } /* 延时一段时间 */ vTaskDelay(pdMS_TO_TICKS(1000)); } } /* 在另一个任务中请求互斥信号量 */ void vTask2(void *pvParameters) { while (1) { /* 请求互斥信号量 */ if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) { /* 访问共享资源 */ printf("Task 2 accessing shared resource...\n"); /* 释放互斥信号量 */ xSemaphoreGive(xMutex); } /* 延时一段时间 */ vTaskDelay(pdMS_TO_TICKS(1000)); } } ``` 在上面的示例代码中,两个任务都需要访问共享资源,并且在访问之前都会请求互斥信号量。如果互斥信号量已被占用,则任务会进入阻塞状态,直到互斥信号量被释放为止。这样可以避免不同任务之间同时访问共享资源导致的数据竞争问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值