FreeRTOS系列|二值信号量

二值信号量

1. 信号量简介

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

Semaphore
Binary
Count
Mutex
RecursiveMutex
Mutex
2. 二值信号量简介

二值信号量即任务与中断间或者两个任务间的标志,该标志非“满”即“空”。也可以理解为只有一个队列项的队列,该队列要么是满要么是空,Send操作相当把该标志置“满”,Receive操作相关与把该标志取"空",经过send和receive操作实现任务与中断间或者两任务的操作同步。二值信号量的使用方法如下图所示

在这里插入图片描述

3. 二值信号量的函数应用
3.1 创建二值信号量
/********************动态创建二值信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateBinary(void);
/********************静态创建二值信号量**********************************************/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer);
参数:pxSemaphoreBuffer指向一个StaticSemaphore_t类型的变量,用来保存信号量结构体
/***********************************************************************************/
返回值:创建成功返回二值信号量句柄;失败返回NULL

二值信号量创建函数是一个宏,最终是通过xQueueGenericCreate()函数来完成,其源码如下:

/*其实就是创建了一个长度为1、队列项长度为0、类型为二值信号量的队列*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateBinary() 						\
xQueueGenericCreate((UBaseType_t) 1, 					\
					semSEMAPHORE_QUEUE_ITEM_LENGTH, 	\
					queueQUEUE_TYPE_BINARY_SEMAPHORE)	\
#endif
3.2 释放信号量
/********************任务级信号量释放**********************************************/
BaseType_t xSemaphoreGive(SemaphoreHandle_t  xSemaphore)
/********************中断级信号量释放**********************************************/
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,//要释放的信号量句柄
                         BaseType_t *pxHigherPriorityTaskWoken)//标记退出后是否切换任务
/***********************************************************************************/
返回值:释放成功返回pdPASS;释放失败返回errQUEUE_FULL                         

二值信号量释放函数xSemaphoreGive()是一个宏,其实就是向队列发送消息,其源码如下:

/*其实就是没有具体消息、阻塞时间为0、后向入队的入队过程*/
#define xSemaphoreGive(xSemaphore)				\
xQueueGenericSend((QueueHandle_t) (xSemaphore), \
				  NULL, 						\
				  semGIVE_BLOCK_TIME, 			\
				  queueSEND_TO_BACK)			\
3.3 获取信号量
/********************任务级信号量获取**********************************************/
BaseType_t xSemaphoreTake(SemaphoreHandle_t  xSemaphore//要获取的信号量句柄
						  TickType_t xBlockTime)//阻塞时间
/********************中断级信号量获取**********************************************/
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,//要获取的信号量句柄
                         BaseType_t *pxHigherPriorityTaskWoken)//标记退出后是否切换任务
/***********************************************************************************/
返回值:获取成功返回pdPASS;释放失败返回pdFALSE                      

获取信号量函数也是一个宏,其实就是读取队列的过程,其源码如下

#define xSemaphoreTake(xSemaphore, xBlockTime)		\
xQueueGenericReceive((QueueHandle_t) (xSemaphore), 	\
					 NULL, 							\
					 (xBlockTime), 					\
					 pdFALSE)						\
4. 二值信号量的应用实例

本实例介绍如何使用二值信号量来完成任务与中断之间的同步。

使用STM32CubeMX将FreeRTOS移植到工程中,创建两个任务、一个二值信号量,开启串口中断。

LED_Task:闪烁LED1,提示系统运行正常
CMDprocess_Task:根据串口收到的指令,控制不同的LED2/LED3的亮灭
二值信号量:用于串口中断和CMDprocess_Task任务间的同步

4.1 STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0/PC1/PC2设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位;开启串口中断
  • 激活FreeRTOS,添加任务,设置任务名称、优先级、堆栈大小、函数名称等参数

在这里插入图片描述

  • 动态创建二值信号量

在这里插入图片描述

  • 使用FreeRTOS操作系统,一定要将HAL库的Timebase Source从SysTick改为其他定时器,选好定时器后,系统会自动配置TIM
  • 输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
4.2 MDK-ARM软件编程
  • 添加LEDTask、CMDprocessTask任务函数代码
/******************LEDTask**************************/
void LEDTask(void const * argument){
  for(;;){
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    osDelay(500);
  }
}
/******************CMDprocessTask*******************/
void CMDprocessTask(void const * argument){
  BaseType_t err = pdFALSE;
  for(;;){
    if(BinarySemHandle != 0){
	  err = xSemaphoreTake(BinarySemHandle,portMAX_DELAY);
	  if(err == pdPASS){
		printf("CMDprocessTask take the binary Semaphore!\r\n");
		printf("Received CMD is:");
		for(int i =0;i<8;i++)
		  printf("%c",RxBuff[i]);
		printf("\n");
				
		if(strncmp((char *)RxBuff,"LED2on",6) == 0)
		  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_RESET);		
		else if(strncmp((char *)RxBuff,"LED2off",6) == 0)
		  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_SET);	
		else if(strncmp((char *)RxBuff,"LED3on",6) == 0)
		  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_RESET);	
		else if(strncmp((char *)RxBuff,"LED3off",6) == 0)
		  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET);	
		else
		  printf("invalid CMD,please input LED2on LED2off LED3on or LED3off\r\n");
				
	  }
	  else
		osDelay(10);
	}
  }
}
  • 添加串口中断回调函数:串口接收完命令后释放二值信号量
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){  
  RxBuff[Rx_Count++]=RxByte;	
  if((RxByte==0x0A)&&(BinarySemHandle!=0)){
	xSemaphoreGiveFromISR(BinarySemHandle,NULL);	
	printf("Semaphore Give FromISR succesed!\r\n");
	Rx_Count=0;
  }
	
  if(Rx_Count > 8){
	printf("Wrong CMD, Please Check...!\r\n");
	memset(RxBuff,0,sizeof(RxBuff));
	Rx_Count=0;
  }	
  while(HAL_UART_Receive_IT(&huart1,&RxByte,1)==HAL_OK);
}
  • 在main.c中开启串口接收中断
int main(void){
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  printf("BinarySemaphore test....\r\n");
  if(HAL_OK == HAL_UART_Receive_IT(&huart1,&RxByte,1))
	printf("UART_Receive_IT successed!\r\n");
  else 
	printf("UART_Receive_IT failed!\r\n");
  /* USER CODE END 2 */
  MX_FREERTOS_Init(); 
  osKernelStart();
  while (1)
  {
  }
}
4.3 下载验证

编译无误下载到开发板后,打开串口调试助手,LED1闪烁表示程序正常运行;串口中输入字符串“LED2on、LED2off、LED3on、LED3off”可以控制LED2/LED3的亮灭并打印出相应的二值信号量的释放和获取的信息

在这里插入图片描述

关注我的公众号,在公众号里发如下消息,即可获取相应的工程源代码:

FreeRTOS二值信号量实例

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS 中的二值信号量是一种同步机制,用于在任务之间进行简单的通信和同步。二值信号量只有两个状态:可用和不可用(或者称为占用和释放)。一个任务可以获取(占用)二值信号量,如果二值信号量已经被其他任务占用,则该任务将被阻塞,直到二值信号量被释放。当二值信号量被释放时,阻塞的任务将被唤醒,继续执行。 下面是使用 FreeRTOS 二值信号量的一般步骤: 1. 创建二值信号量:使用 xSemaphoreCreateBinary() 函数创建一个二值信号量。这个函数返回一个指向新创建的二值信号量的句柄。 2. 获取二值信号量:在任务中使用 xSemaphoreTake() 函数来获取二值信号量。如果二值信号量当前不可用,则该任务将被阻塞,直到二值信号量被释放。 3. 释放二值信号量:在任务中使用 xSemaphoreGive() 函数来释放二值信号量。一旦释放了二值信号量,其他等待该信号量的任务将被唤醒,可以继续执行。 需要注意的是,只有拥有二值信号量的任务才能释放它。如果其他任务试图释放一个不可用的二值信号量,会导致不确定的行为。 二值信号量常用于以下情况: 1. 任务同步:一个任务可以等待另一个任务完成某个操作后才能继续执行。 2. 资源共享:多个任务可以共享一个资源,通过二值信号量来控制对该资源的访问。 3. 事件通知:一个任务可以等待某个特定事件的发生,其他任务在事件发生时释放二值信号量,通知等待的任务。 FreeRTOS二值信号量功能强大且易于使用,可以帮助开发者实现任务之间的同步和通信。在使用时,应注意正确地获取和释放二值信号量,以避免死锁和竞争条件等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安迪西嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值