FreeRTOS-信号量

一、信号量简介

  • 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。信号量中存在计数值,计数值>0时表示信号量有资源
  • 信号量仅存放数值,无法存放其他数据;释放信号量,不可阻塞,计数值++,计数值最大时,返回失败;获取信号量,计数值–,当没有资源时,可阻塞

二、 二值信号量

2.1 二值信号量简介

  • 二值信号量的本质是一个长度为1的队列,该队列就只有空和满两种状态(0,1),这就是二值
  • 二值信号量通常用于互斥访问(条件判断只有一种情况满足)或任务同步(任务按前后顺序执行
  • 下面是二值信号量相关的API函数
  • 使用二值信号量的过程创建二值信号量-释放二值信号量(入队)-获取二值信号量(出队)
xSemaphoreCreatBinary();//动态方式创建二值信号量
xSemaphoreCreatBinaryStatic();//静态方式创建二值信号量
xSemaphoreGive();//释放信号量
xSemaphoreGiveFromISR();//在中断中释放信号量
xSemaphoreTake();//获取信号量
xSemaphoreTakeFromISR();//在中断中获取信号量
  • 动态创建二值信号量,本质上创建信号量就是创建长度为1的队列
SemaphoreHandle_t xSemaphoreCreateBinary();
#define xSemaphoreCreateBinary()  xQueueGenericCreate(1,队列项大小,创建类型)
//返回值句柄判断是否创建成功
  • 释放二值信号量,本质上是入队操作
BaseType_t xSemaphoreGive(xSemaphore)
#define xSemaphoreGive(xSemaphore)	xQueueGenericSend(xSemaphore,NULL,semGIVE_BLOCK_TIME,queueSEND_TO_BACK)
//形参是释放的信号量 返回值判断释放是否成功
  • 获取二值信号量
BaseType_t xSemaphoreTake(xSemaphore,xBlockTime)
//形参 获取信号量的句柄 阻塞时间
//返回值判断是否获取成功

2.2 二值信号量实验

  • 设计三个任务,start_task:创建task1和task2。task1:按键扫描,当检测到按键key0按下时,释放二值信号量。task2:获取二值信号量
#define configSUPPORT_DYNAMIC_ALLOCATION					1//动态创建任务/信号量宏定义配置


//start_task参数宏定义
#define	START_TASK_STACK_SIZE 								128//堆栈大小
#define	START_TASK_PRIO										1//任务优先级
TaskHandle_t	start_task_handle;							//任务句柄
//task1参数宏定义
#define	TASK1_STACK_SIZE 									128//堆栈大小
#define	TASK1_PRIO											2//任务优先级
TaskHandle_t	task1_handle;								//任务句柄
//task2参数宏定义
#define	TASK2_STACK_SIZE 									128//堆栈大小
#define	TASK2_PRIO											3//任务优先级
TaskHandle_t	task2_handle;								//任务句柄


//task1任务函数:key0按下释放信号量
void task1( void * pvParameters )
{
		uint8_t KeyNum = 0;
		BaseType_t err;//释放返回值,判断是否释放成功
		while(1)
		{
			KeyNum = Key_GetNum();
			if(KeyNum == 0)//key0按下
			{
				err = xSemaphoreGive(semphopre_handle);//释放二值信号量
			}
			vTaskDelay(10);//自带延时函数
		}
}
//task2任务函数:获取信号量
void task2( void * pvParameters )
{
		while(1)
		{
			xSemaphoreTake(semphopre_handle,portMAX_DELAY);//获取信号量,阻塞时间最大值
		}
}

//Start_task任务函数
void Start_task( void * pvParameters )
{
		taskENTER_CRITICAL();//进入临界区
		//创建任务1
		xTaskCreate(task1,//任务函数
					"task1",//任务名称
					TASK1_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK1_PRIO,//优先级
					&task1_handle//任务句柄
					);
		//创建任务2
		xTaskCreate(task2,//任务函数
					"task2",//任务名称
					TASK2_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK2_PRIO,//优先级
					&task2_handle//句柄
					);
		vTaskDelete(start_task_handle);
		//删除自身任务Start_task,start_task_handle或NULL都可以
		taskEXIT_CRITICAL();//退出临界区
}

QueueHandle_t semphopre_handle;//信号量句柄,返回值判断信号量是否创建成功
//FreeRTOS入口函数,程序从此处开始执行
void freertos_demo()
{
		semphopre_handle= xSemaphoreCreateBinary();//创建二值信号量
		xTaskCreate(Start_task,//任务函数
					"Start_task",//任务名称
					START_TASK_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					START_TASK_PRIO,//优先级
					&start_task_handle//句柄
					);//创建Start任务
		vTaskStartScheduler();//开启任务调度器,开启执行Start任务,创建task123
}

三、计数型信号量

3.1 计数型信号量简介

  • 计数型信号量相当于队列长度大于1的队列,可以容纳多个资源,队列长度创建信号量时确定
  • 计数型信号量适用于事件计数-事件发生,释放计数型信号量(计数值+1),其他任务获取信号量(计数值-1),创建时初始计数值设置为0、同时适用于资源管理-信号量表示有效的资源数目
  • 使用流程创建计数型信号量(初始为0)-释放信号量(+1)-获取信号量
  • 下面是计数型信号量的相关API函数
  • 计数型信号量的释放和获取与二值信号量一致
xSemaphoreCreateCounting();//动态方式创建计数型信号量
xSemaphoreCreateCountingStatic();//静态方法创建计数型信号量
xSemaphoreGetCount();//获取信号量的计数值
xSemaphoreGive();//释放信号量
xSemaphoreGiveFromISR();//在中断中释放信号量
xSemaphoreTake();//获取信号量
xSemaphoreTakeFromISR();//在中断中获取信号量
  • 动态创建计数型信号量
xSemaphoreCreateCounting(uxMaxCount,uxInitialCount);
//形参:计数值的最大值限定 计数值的初始值
//返回值:NULL创建失败 信号量句柄创建成功
  • 获取计数型信号量当前计数值大小
uxSemaphoreGetCount(xSemaphore);
//形参:信号量句柄
//返回值:整数-当前信号量计数值大小

3.2 计数型信号量实验

  • 设计三个任务,start_task:创建task1和task2。task1:按键扫描,当检测到按键key0按下时,释放(+1)计数型信号量量。task2:每过一秒获取(-1)一次计数型信号量
#define configSUPPORT_DYNAMIC_ALLOCATION					1//动态创建任务/信号量宏定义配置


//start_task参数宏定义
#define	START_TASK_STACK_SIZE 								128//堆栈大小
#define	START_TASK_PRIO										1//任务优先级
TaskHandle_t	start_task_handle;							//任务句柄
//task1参数宏定义
#define	TASK1_STACK_SIZE 									128//堆栈大小
#define	TASK1_PRIO											2//任务优先级
TaskHandle_t	task1_handle;								//任务句柄
//task2参数宏定义
#define	TASK2_STACK_SIZE 									128//堆栈大小
#define	TASK2_PRIO											3//任务优先级
TaskHandle_t	task2_handle;								//任务句柄


//task1任务函数:key0按下释放计数型信号量
void task1( void * pvParameters )
{
		uint8_t KeyNum = 0;
		BaseType_t err;//释放返回值,判断是否释放成功
		while(1)
		{
			KeyNum = Key_GetNum();
			if(KeyNum == 0)//key0按下
			{
				err = xSemaphoreGive(count_semphopre_handle);//释放计数型信号量
			}
			vTaskDelay(10);//自带延时函数
		}
}
//task2任务函数:获取计数型信号量
void task2( void * pvParameters )
{
		while(1)
		{
			xSemaphoreTake(count_semphopre_handle,portMAX_DELAY);//获取计数型信号量,阻塞时间最大值
			vTaskDelay(1000);//1s延时
		}
}

//Start_task任务函数
void Start_task( void * pvParameters )
{
		taskENTER_CRITICAL();//进入临界区
		//创建任务1
		xTaskCreate(task1,//任务函数
					"task1",//任务名称
					TASK1_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK1_PRIO,//优先级
					&task1_handle//任务句柄
					);
		//创建任务2
		xTaskCreate(task2,//任务函数
					"task2",//任务名称
					TASK2_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK2_PRIO,//优先级
					&task2_handle//句柄
					);
		vTaskDelete(start_task_handle);
		//删除自身任务Start_task,start_task_handle或NULL都可以
		taskEXIT_CRITICAL();//退出临界区
}

QueueHandle_t count_semphopre_handle;//计数型信号量句柄,返回值判断信号量是否创建成功
//FreeRTOS入口函数,程序从此处开始执行
void freertos_demo()
{
		count_semphopre_handle= xSemaphoreCreateCounting(100,0);//创建计数型信号量
		xTaskCreate(Start_task,//任务函数
					"Start_task",//任务名称
					START_TASK_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					START_TASK_PRIO,//优先级
					&start_task_handle//句柄
					);//创建Start任务
		vTaskStartScheduler();//开启任务调度器,开启执行Start任务,创建task123
}

四、互斥信号量

4.1 互斥信号量简介

  • 互斥信号量是一个拥有优先级继承二值信号量,适用于需要互斥访问的应用中
  • 优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞(高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级)
  • 优先级继承并不能完全消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响,只是将低优先级抬高
  • 互斥信号量不能用于中断服务函数中
  • 使用互斥信号量流程configUSE_MUTEXES置1创建互斥信号量-获取信号量-释放信号量(创建互斥信号量时会主动释放一次信号量)
  • 互斥信号量相关API函数
xSemaphoreCreateMutex();//动态创建互斥信号量
xSemaphoreCreateMutexStatic();//静态创建互斥信号量
xSemaphoreGive();//释放信号量
xSemaphoreTake();//获取信号量
  • 动态创建互斥信号量
xSemaphoreCreateMutex();
//返回值:NULL创建失败 互斥信号量句柄表示创建成功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值