FreeRTOS信号量---二值信号量

信号量可以用来进行资源管理和任务同步,FreeRTOS中信号量又分为二值信号量、计算型信号量、互斥信号量和递归互斥信号量。

0x01 二值信号量

二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的,任务和中断不用在乎队列中存的是什么消息,只需要知道这个队列是满的还是空的,可以利用这个机制完成任务与中断之间的同步。

1. 创建二值信号量

FreeRTOS信号量---二值信号量_第1张图片
vSemaphoreCreateBinary

vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )
  • xSemaphore :保存创建成功的二值信号量
    此函数是老版本FreeRTOS创建二值信号量函数,新版本已经不再使用。

xSemaphoreCreateBinary:

SemaphoreHandle_t xSemaphoreCreateBinary( void )

此函数是新版本FreeRTOS中统一使用此函数来创建二值信号量,使用此函数创建二值信号量的话,信号量所需要的内存是有FreeRTOS的内存管理部分动态分配的,此函数创建好的二值信号量默认是空的,也就是说创建好的二值信号量使用函数xSemaphoreTask是获取不到的。

xSemaphoreCreateBinaryStatic

SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
  • pxSemaphoreBuffer :保存信号量结构体
    此函数创建二值信号量所需要的内存需要由用户分配
2. 释放信号量

在这里插入图片描述

xSemaphoreGive

xSemaphoreGive( SemaphoreHandle_t xSemaphore )
  • xSemaphore:要释放的信号量句柄
    此函数用于释放二值信号量、计数型信号量或互斥信号量

xSemaphoreGiveFromISR

 xSemaphoreGiveFromISR(
                          SemaphoreHandle_t xSemaphore,
                          BaseType_t *pxHigherPriorityTaskWoken
                      )
  • xSemaphore:要释放的信号量句柄
  • BaseType_t *pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,此值为pdTRUE的时候在退出中断之前一定要进行一次任务切换

此函数只能用来释放二值信号量和计数型信号量

3. 获取信号量

在这里插入图片描述
xSemaphoreTake

xSemaphoreTake(
 *                   SemaphoreHandle_t xSemaphore,
 *                   TickType_t xBlockTime
 *               )
  • SemaphoreHandle_t xSemaphore:要获取信号量的句柄
  • TickType_t xBlockTime:阻塞时间
    此函数用于获取二值信号量、计数型信号量或互斥信号量

xSemaphoreTakeFromISR

 xSemaphoreTakeFromISR(
                          SemaphoreHandle_t xSemaphore,
                          BaseType_t *pxHigherPriorityTaskWoken
                      )
  • SemaphoreHandle_t xSemaphore:要获取信号量的句柄
  • BaseType_t *pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,等于pdTURE一定进行任务切换
4. 验证

设计一个通过串口发送指定的指令来控制开发版上的LED1和BEEP开关的实验。指令如下:
LED1ON:打开LED1
LED1OFF:关闭LED1
BEEFON:打开BEEF
BEEFOFF:关闭BEEF
设计三个任务,功能如下:
start_task:用来创建其他2个任务
task1_task:控制LED0闪烁,提示系统正在运行
DataProcess_task:指令处理任务,根据接收到的指令来控制不同的外设
实验中还创建一个二值信号量BinarySemaphore用于完成串口中断和任务DataProcess_task之间的同步。

DataProcess_task函数

void DataProcess_task(void *pvParameters)
{
	u8 len = 0;
	u8 CommandValue = COMMANDERR;
	BaseType_t err = pdFALSE;
	
	u8 *CommandStr;
	POINT_COLOR = BLUE;
	while(1)
	{
		if(BinarySemaphore!=NULL)
		{
			err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取信号量
			if(err==pdTRUE)										//获取信号量成功
			{
				len=USART_RX_STA&0x3fff;						//得到此次接收到的数据长度
				CommandStr=mymalloc(SRAMIN,len+1);				//申请内存
				sprintf((char*)CommandStr,"%s",USART_RX_BUF);
				CommandStr[len]='\0';							//加上字符串结尾符号
				LowerToCap(CommandStr,len);						//将字符串转换为大写		
				CommandValue=CommandProcess(CommandStr);		//命令解析
				if(CommandValue!=COMMANDERR)
				{
					LCD_Fill(10,90,210,110,WHITE);				//清除显示区域
					LCD_ShowString(10,90,200,16,16,CommandStr);	//在LCD上显示命令
					printf("命令为:%s\r\n",CommandStr);
					switch(CommandValue)						//处理命令
					{
						case LED1ON: 
							LED1=0;
							break;
						case LED1OFF:
							LED1=1;
							break;
						case BEEPON:
							BEEP=0;
							break;
						case BEEPOFF:
							BEEP=1;
							break;
					}
				}
				else
				{
					printf("无效的命令,请重新输入!!\r\n");
				}
				USART_RX_STA=0;
				memset(USART_RX_BUF,0,USART_REC_LEN);			//串口接收缓冲区清零
				myfree(SRAMIN,CommandStr);						//释放内存
			}
		}
		else if(err==pdFALSE)
		{
			vTaskDelay(10);      //延时10ms,也就是10个时钟节拍	
		}
	}
}

DataProcess_task是用来申请获取信号量,如果申请到了,就往下执行,如果没事申请到,就会一直阻塞,申请到之后,对数据做处理,然后做出相应的回应。

串口1中断服务程序

//串口1中断服务程序
void USART1_IRQHandler(void)                	
{ 
	u32 timeout=0;
	u32 maxDelay=0x1FFFF;
	BaseType_t xHigherPriorityTaskWoken;
	
	HAL_UART_IRQHandler(&UART1_Handler);	//调用HAL库中断处理公用函数
	
	timeout=0;
    while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)//等待就绪
	{
		timeout++;超时处理
		if(timeout>maxDelay) break;		
	}  
	timeout=0;
	while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
	{
		timeout++; //超时处理
		if(timeout>maxDelay) break;	
	}
	//释放二值信号量
	if((USART_RX_STA&0x8000)&&(BinarySemaphore!=NULL))//接收到数据,并且二值信号量有效
	{
		xSemaphoreGiveFromISR(BinarySemaphore,&xHigherPriorityTaskWoken);	//释放二值信号量
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}
} 

串口1中断服务程序是用来接收串口发送的数据,如果接收完毕,将会释放二值信号量,DataProcess_task才能往下执行,如果没有接收完数据或者没有接收到数据,DataProcess_task会一直阻塞。

你可能感兴趣的:(FreeRTOS,stm32,单片机,arm)