FreeRTOS系统-二值信号量的使用

FreeRTOS系统-二值信号量的使用


日期 作者 版本 说明
2020.12.26 Hxj V1.0 完成主体
2021.01.08 Hxj V1.1 加入了串口中断使用二值信号量

提示:以下文章基于FreeRTOS全部移植完成,能够正常运行.


前言

FreeRTOS系统的引入可以极大的提高程序的运行效率,搭建的框架也提高了程序的易写性,提高编程效率.
在使用FreeRTOS系统的过程中,笔者发现GPIO触发外部中断,在中断服务函数中做一个Delay_ms(20)的延时消抖时,会导致FreeRTOS系统停止工作,这样会导致系统效率降低更严重的情况会导致一些需要实时性的功能断层.


一、FreeRTOS系统的中断管理?

configLIBRARY_LOWEST_INTERRUPT_PRIORITY]
这个宏是可以定义的中断最低优先级,由于STM32中断管理只用了4位来分配抢占优先级和子优先级,并且FreeRTOS使用优先级分组4(没有子优先级),所以该宏设为15

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
这个宏是系统可管理的最高中断优先级,即为一个阈值,低于该值的可以调用一些fromISR的函数。高于该优先级的中断则不响应打开和关断中断(一直都可以进行中断操作)。

configKERNEL_INTERRUPT_PRIORITY
这个宏定义是( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ),实质上就是把15左移4位当作真正的优先级。(因为第四位保留了)

configMAX_SYSCALL_INTERRUPT_PRIORITY
相当于( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ),原因与configKERNEL_INTERRUPT_PRIORITY相同。

经过对上面configLIBRARY_LOWEST_INTERRUPT_PRIORITY]configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的宏定义便确定了在这个优先级范围内能够调用FreeRTOS系统的API了。

这个优先级范围的确定,接下来我们在外部中断的优先级定义就必须在此范围内,否则FreeRTOS的API的调用在中断服务函数中卡死。

二、二值信号量

1.二值信号量介绍

二值型信号量可以理解为任务与中断间或者两个任务间的标志,该标志非“满”即“空”。Give操作相当把该标志置“满”,Take操作相关与把该标志取"空",经过send和receive操作实现任务与中断间或者两任务的操作同步。

需要用到的头文件

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

创建信号量

函数 描述
xSemaphoreCreateBinary() 动态创建二值信号量
vSemaphoreCreateBinaryStatic() 静态创建二值信号量

使用(示例):

SemaphoreHandle_t Semaphore_Exit1 = NULL;//声明变量 用来接收创建二值信号量的句柄
Semaphore_Exit1 = xSemaphoreCreateBinary();//创建外部中断1	二值信号量

释放信号量

函数 描述
xSemaphoreGive() 任务级释放二值信号量
xSemaphoreGiveFromISR() 中断中释放二值信号量

以上两个释放二值信号量的函数,需用户根据自己的使用环境进行选择。在中断服务函数中一定选择 xSemaphoreGiveFromISR()

使用(示例):

//在外部1中释放Semaphore_Exit1二值信号量
//参数1:传入你要释放的二值信号量的句柄,也就是你创建二值信号量的返回值
//参数2:默认NULL
void EXTI_1_Triggered_Mptor1_Stop(void)
{
    
    
    xSemaphoreGiveFromISR( Semaphore_Exit1, NULL );//发送二值信号量
}
 

获取信号量

函数 描述
xSemaphoreTake() 任务级获得二值信号量
xSemaphoreTakeFromISR() 中断级获得二值信号量

以上两个获取二值信号量的函数,需用户根据自己的使用环境进行选择,与释放二值信号量配套使用。

使用(示例):

//创建一个任务进行对二值信号量的获取判断,获取后进行操作,未获取则进行等待,并释放资源使其他任务继续进行。
void  Exit1_Irq_task(void *pvParameters)
{
    
    
	while (1)
	{
    
    
	//参数1:需要获取的二值信号量句柄
	//参数2:等待时间 portMAX_DELAY为永久等待
	//返回值:成功返回1	失败返回 0
		if(pdTRUE == xSemaphoreTake(Semaphore_Exit1,portMAX_DELAY))//等待二值信号量  永久等待
			{
    
    
				vTaskDelay(20);//FreeRTOS的延时是一种阻塞态并不会占用系统资源
				/********/
					省略代码
				/*******/
			}
	}
}


2.使用指南

外部中断

思路说明:在一个外部中断服务函数中释放二值信号量,创建一个任务进行等待二值信号量的到来,在任务中进行操作,这样极大的减少了在系统中断中停留的时间。使得系统运行效率大大提高。

代码如下(示例):

SemaphoreHandle_t Semaphore_Exit1 = NULL;//声明变量 用来接收创建二值信号量的句柄
Semaphore_Exit1 = xSemaphoreCreateBinary();//创建外部中断1	二值信号量

void FreeRTOS_Exec()
{
    
    
	//创建二值信号量获取后的处理任务
	xTaskCreate((TaskFunction_t )Exit1_Irq_task,
			(const char*    )"Exit1_Irq_task",
			(uint16_t       )EXIT1_TRQ_STK_SIZE,
			(void*          )NULL,
			(UBaseType_t    )EXIT1_IRQ_TASK_PRIO,
			(TaskHandle_t*  )&Exit1_Irq_Task_Handler);
	vTaskStartScheduler();									//开启任务调度
}

//创建一个任务进行对二值信号量的获取判断,获取后进行操作,未获取则进行等待,并释放资源使其他任务继续进行。
void  Exit1_Irq_task(void *pvParameters)
{
    
    
	while (1)
	{
    
    
	//参数1:需要获取的二值信号量句柄
	//参数2:等待时间 portMAX_DELAY为永久等待
	//返回值:成功返回1	失败返回 0
		if(pdTRUE == xSemaphoreTake(Semaphore_Exit1,portMAX_DELAY))//等待二值信号量  永久等待
			{
    
    
				vTaskDelay(20);//FreeRTOS的延时是一种阻塞态并不会占用系统资源
				/********/
					省略代码
				/*******/
			}
	}
}

 //在外部中断1中释放Semaphore_Exit1二值信号量
//参数1:传入你要释放的二值信号量的句柄,也就是你创建二值信号量的返回值
//参数2:默认NULL
void EXTI_1_Triggered_Mptor1_Stop(void)
{
    
    
    xSemaphoreGiveFromISR( Semaphore_Exit1, NULL );//发送二值信号量
}


串口的接收空闲中断释放二值信号量

思路说明:在串口接收数据时,空闲中断会是一个判断是否接收完成的标志。在一个串口中断服务函数中的空闲中断中释放二值信号量,创建一个任务进行等待二值信号量的到来,在任务中进行对接收的数据进行处理,这样极大的减少了在系统中断中停留的时间。使得系统运行效率大大提高。

代码如下(示例):

SemaphoreHandle_t Semaphore_Usart3= NULL;//声明变量 用来接收创建二值信号量的句柄
Semaphore_Usart3= xSemaphoreCreateBinary();//创建外部中断1	二值信号量

void FreeRTOS_Exec()
{
    
    
	//创建USART3的接受处理的任务
	xTaskCreate((TaskFunction_t )Usart3_Rx_Pro_task,
			(const char*    )"PORTswitch_task",
			(uint16_t       )USART3_RX_PRO_STK_SIZE,
			(void*          )NULL,
			(UBaseType_t    )USART3_RX_PRO_TASK_PRIO,
			(TaskHandle_t*  )&Usart3RxProTask_Handler);
	vTaskStartScheduler();									//开启任务调度
}

//创建一个任务进行对二值信号量的获取判断,获取后进行操作,未获取则进行等待,并释放资源使其他任务继续进行。
void  Usart3_Rx_Pro_task(void *pvParameters)
{
    
    
	while (1)
	{
    
    
	//参数1:需要获取的二值信号量句柄
	//参数2:等待时间 portMAX_DELAY为永久等待
	//返回值:成功返回1	失败返回 0
		if(pdTRUE == xSemaphoreTake(Semaphore_Usart3,portMAX_DELAY))//等待二值信号量  永久等待
			{
    
    
				/********/
					省略代码
				/*******/
			}
	}
}

 //在串口中断3的空闲中断中释放Semaphore_Usart3二值信号量
void USART3_IRQHandler(void)
{
    
    
	if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)
	{
    
    
		if(Semaphore_Usart3 != NULL)
		{
    
    
			//参数1:传入你要释放的二值信号量的句柄,也就是你创建二值信号量的返回值
			//参数2:默认NULL
			xSemaphoreGiveFromISR( Semaphore_Usart3, NULL );//发送二值信号量
		}
		Free_Read_Rst = USART3 ->SR;
		Free_Read_Rst = USART3 ->DR;//清除空闲中断
	}
}

总结

[1].任务的优先级以及分配的空间大小需要适合。
[2].中断中发送信号量尽量使用xSemaphoreGiveFromISR。
[3]释放信号量的中断的优先级数值应大configMAX_SYSCALL_INTERRUPT_PRIORITY

猜你喜欢

转载自blog.csdn.net/qq_45531642/article/details/111667002