11.FreeRTOS信号量操作

01.初识freeRTOS
02.FreeRTOS的移植
03.FreeRTOS系统配置
04.FreeRTOS任务创建与删除
05.FreeRTOS任务挂起与恢复
06.FreeRTOS中断管理
07.FreeRTOS列表与列表项
08.FreeRTOS任务调度与任务切换
09.FreeRTOS时间片调度与任务相关函数
10.FreeRTOS队列操作
11.FreeRTOS信号量操作
12.FreeRTOS队列集和事件标志组
13.FreeRTOS任务通知
14.FreeRTOS软件定时器
15.FreeRTOS低功耗
16.FreeRTOS内存管理

11. FreeRTOS信号量操作

1. 信号量的简介

信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。其中,“同步”指的是任务间的同步,即信号量可以使得一个任务等待另一个任务完成某件事情后,才继续执行:而“有序访问”指的是对被多任务或中断访问的共享资源(如全局变量)的管理,当一个任务在访问(读取或写入)一个共享资源时,信号量可以防止其他任务或中断在这期间访问(读取或写入)这个共享资源。

在这里插入图片描述

在这里插入图片描述

队列和信号量的对比:

队列信号量
可以容纳多个数据;
创建队列有两部分内存:队列结构体+队列项存储空间
仅存放计数值,无法存放其他数据;
创建信号量,只需分配信号量结构体
写入队列:当队列满时,可阻塞;释放信号量:不可阻塞,计数值++,当计数值为最大值时,返回失败;
读取队列:当队列为空时,可阻塞;获取信号量:计数值–,当没有资源时,可阻塞;

2. 二值信号量

二值信号量的简介:

在这里插入图片描述

二值信号量的相关API函数:

函数描述
xSemaphoreCreateBinary()使用动态方式创建二值信号量
xSemaphoreCreateBinaryStatic()使用静态方式创建二值信号量
xSemaphoreGive()释放信号量
xSemaphoreGiveFromISR()在中断中释放信号量
xSemaphoreTake()获取信号量
xSemaphoreTakeFromISR()在中断中获取信号量

创建二值信号量函数:

在这里插入图片描述

释放二值信号量函数:

在这里插入图片描述

获取二值信号量函数:

在这里插入图片描述

二值信号量相关实验:

在这里插入图片描述

  • 二值信号量的创建:

    //定义句柄
    QueueHandle_t semphore_handle;
    
    semphore_handle = xSemaphoreCreateBinary();
    if(semphore_handle != NULL)
    {
    	printf("二值信号量创建成功!\r\n");
    }
    
  • 任务一:释放二值信号量

    /*任务一:释放二值信号量*/
    void task1(void* pvParamter)
    {	
    	uint8_t key = 0;
    	while(1)
    	{
    		key = key_scan(0);
    		if(key == KEY0_PRES)
    		{
    			if(semphore_handle != NULL)
    			{
    				if(pdPASS == xSemaphoreGive(semphore_handle))
    				{
    					printf("信号量释放成功!\r\n");
    				}
    				else
    				{
    					printf("释放信号量失败!\r\n");
    				}
    			}
    		}
    		vTaskDelay(20);
    	}
    }
    
  • 任务二:获取二值信号量

    /*任务二:获取二值信号量*/
    void task2(void* pvParamter)
    {
    	uint32_t i = 0;
    	while(1)
    	{
    		if(pdTRUE == xSemaphoreTake(semphore_handle, 1000))  //获取信号量死等
    		{
    			printf("获取信号量成功!\r\n");
    		}
    		else
    		{
    			printf("已超时 %d\r\n", ++i);
    		}
    	}
    }
    
  • 实验结果

    在这里插入图片描述

3. 计数型信号量

计数型信号量的简介:

在这里插入图片描述

计数型信号量的相关API函数:

函数描述
xSemaphoreCreateCounting()使用动态方法创建计数型信号量。
xSemaphoreCreateCountingStatic()使用静态方法创建计数型信号量
uxSemaphoreGetCount()获取信号量的计数值

创建计数型信号量:

在这里插入图片描述

获取当前计数值大小:

在这里插入图片描述

计数型信号量相关实验:

在这里插入图片描述

  • 计数型信号量的创建:

    //句柄定义
    QueueHandle_t count_semphore_handle;
    
    count_semphore_handle = xSemaphoreCreateCounting(100, 0);
    if(count_semphore_handle != NULL)
    {
    	printf("计数型信号量创建成功!\r\n");
    }
    
  • 任务一:释放计数型信号量

    /*任务一:释放计数型信号量*/
    void task1(void* pvParamter)
    {	
    	uint8_t key = 0, i = 0;
    	while(1)
    	{
    		key = key_scan(0);
    		if(key == KEY0_PRES)
    		{
    			if(count_semphore_handle != NULL)
    			{
    				if(pdPASS == xSemaphoreGive(count_semphore_handle))
    				{
    					printf("信号量释放成功! %d\r\n",++i);
    				}
    				else
    				{
    					printf("释放信号量失败!\r\n");
    				}
    			}
    		}
    		vTaskDelay(20);
    	}
    }
    
  • 任务二:获取计数型信号量

    /*任务二:获取计数型信号量*/
    void task2(void* pvParamter)
    {
    	while(1)
    	{
    		if(pdTRUE == xSemaphoreTake(count_semphore_handle, portMAX_DELAY))  //获取信号量死等
    		{
    			printf("信号量计数值为:%d\r\n", (int)uxSemaphoreGetCount(count_semphore_handle));
    		}
    		vTaskDelay(1000);
    	}
    }
    
  • 实验结果

    在这里插入图片描述

4. 优先级翻转

优先级翻转的简介:

在这里插入图片描述

优先级翻转示例:

在这里插入图片描述

优先级翻转相关实验:

在这里插入图片描述

二值信号量的创建:

QueueHandle_t semphore_handle;

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

低优先级任务:

void low_task(void* pvParamter)
{	
	while(1)
	{
		printf("low_task获取信号量\r\n");
		xSemaphoreTake(semphore_handle, portMAX_DELAY);
		printf("low_task正在运行\r\n");
		delay_ms(3000);
		xSemaphoreGive(semphore_handle);
		printf("low_task释放信号量\r\n");
		vTaskDelay(1000);
	}
}

中优先级任务:

void middle_task(void* pvParamter)
{
	while(1)
	{
		printf("中优先级任务正在运行!\r\n");
		vTaskDelay(1000);
	}
}

高优先级任务:

void high_task(void* pvParamter)
{
	while(1)
	{
		printf("high_task获取信号量\r\n");
		xSemaphoreTake(semphore_handle, portMAX_DELAY);
		printf("high_task正在运行\r\n");
		delay_ms(1000);
		xSemaphoreGive(semphore_handle);
		printf("high_task释放信号量\r\n");
		vTaskDelay(1000);
	}
}

实验结果:

在这里插入图片描述

5. 互斥信号量

互斥信号量的简介:

互斥信号量其实就是一个拥有优先级继承二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中。在互斥访问中互斥信号量相当于一把钥匙,当任务想要访问共享资源的时候就必须先获得这把钥匙,当访问完共享资源以后就必须归还这把钥匙,这样其他的任务就可以拿着这把钥匙去访问资源。

在这里插入图片描述

互斥信号量的示例:

在这里插入图片描述

互斥信号量注意事项:

在这里插入图片描述

互斥信号量相关API函数:

在这里插入图片描述

在这里插入图片描述

互斥信号量相关实验:

在优先级翻转实验的基础,加入互斥信号量,解决优先级翻转问题,只需要修改变量的创建函数,把xSemaphoreCreateBinary()改成xSemaphoreCreateMutex()

QueueHandle_t mutex_semphore_handle;

mutex_semphore_handle = xSemaphoreCreateMutex();
if(mutex_semphore_handle != NULL)
{
	printf("互斥信号量创建成功!\r\n");
}

实验结果:

在这里插入图片描述

FreeRTOS 信号量是一种同步机制,用于在任务之间共享资源。信号量是一个计数器,用于记录可用资源的数量。当一个任务需要使用共享资源时,它会尝试获取信号量。如果信号量计数器的值为正,则任务可以获取该信号量,并将计数器减一。如果信号量的计数器值为零,则任务将进入等待状态,直到有其他任务释放信号量FreeRTOS 中的信号量有两种类型:二进制信号量和计数信号量。 1. 二进制信号量:二进制信号量只有两种状态:可用和不可用。当计数器值为 0 时,信号量不可用;当计数器值为 1 时,信号量可用。 2. 计数信号量:计数信号量允许计数器的值大于 1。当计数器值为 0 时,信号量不可用;当计数器值大于 0 时,信号量可用。 使用 FreeRTOS 信号量需要调用以下函数: 1. `xSemaphoreCreateBinary()`: 创建二进制信号量。 2. `xSemaphoreCreateCounting()`: 创建计数信号量。 3. `xSemaphoreGive()`: 释放信号量。 4. `xSemaphoreTake()`: 获取信号量。 在使用信号量时,需要注意以下几点: 1. 释放信号量的任务必须先获取该信号量。 2. 在获取信号量时,可以设置超时时间,避免任务一直等待。 3. 在使用计数信号量时,需要注意计数器的上限,避免产生资源浪费或死锁的情况。 4. 在使用二进制信号量时,需要注意任务的优先级,避免优先级反转导致的问题。 总之,FreeRTOS 信号量是一种非常实用的同步机制,可以在多任务系统中解决资源共享的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值