基于HAL库的freertos-------四.信号量与事件

一.信号量解释

信号量是操作系统中重要的一部分,信号量一般用来进行资源管理和任务同步。
计数信号量和二值信号量用于访问公共资源,信号量也可以进行任务与任务,中断与中断的同步。
在编写中断服务函数的时候我们都知道一定要快进快出,中断服务函数里面不能放太多的代码,否则的话会影响的中断的实时性。。裸机编写中断服务函数的时候一般都只是在中断服务函数中打个标记,然后在其他的地方根据标记来做具体的处理过程。
在使用 RTOS 系统的时候我们就可以借助信号量完成此功能,当中断发生的时候就释放信号量,中断服务函数不做具体的处理。具体的处理过程做成一个任务,这个任务会获取信号量,如果获取到信号量就说明中断发生了,那么就开始完成相应的处理,这样做的好处就是中断执行时间非常短。

二.实验验证

配置二值信号量,实现任务与任务的同步
在这里插入图片描述

void StartTask03(void *argument)
{
  /* USER CODE BEGIN StartTask03 */
	BaseType_t xHigherPriorityTaskWoken;
  /* Infinite loop */
  for(;;)
  {
		if(key_num==2)
		{
			xSemaphoreGive(myBinarySem01Handle);
			OLED_ShowNum(0,0,key_num,2,16);
		}
    osDelay(1);
  }
  /* USER CODE END StartTask03 */
}

/* USER CODE BEGIN Header_StartTask04 */
/**
* @brief Function implementing the myTask04 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask04 */
void StartTask04(void *argument)
{
  /* USER CODE BEGIN StartTask04 */
	BaseType_t err=pdFALSE;
	uint8_t * str;
  /* Infinite loop */
  for(;;)
  {
		if(myBinarySem01Handle!=NULL)
		{
			err=xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY);//获取信号量
			if(err==pdTRUE) //获取信号量成功
			{
//				sprintf((char*)str,"%s",USART_RX_BUF);
//				printf("USART_RX_BUF %s",str);
				  printf("信号量");
			}
		}
    osDelay(1);
  }
  /* USER CODE END StartTask04 */
}

按键按下,串口输出信息。
在这里插入图片描述
定时器中断与任务的同步

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
		extern osSemaphoreId_t myBinarySem01Handle; //二值信号量句柄
		BaseType_t xHigherPriorityTaskWoken;
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM2) 
	{
   if(myBinarySem01Handle!=NULL))信号量初始化
		{
			xSemaphoreGiveFromISR(myBinarySem01Handle,&xHigherPriorityTaskWoken);
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
			printf("释放二值信号量");
		}
  }
void StartTask04(void *argument)
{
  /* USER CODE BEGIN StartTask04 */
	BaseType_t err=pdFALSE;
	uint8_t * str;
	printf("StartTask04");
  /* Infinite loop */
  for(;;)
  {
		if(myBinarySem01Handle!=NULL)
		{
			err=xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY);//获取信号量
			if(err==pdTRUE) //获取信号量成功
			{
//				sprintf((char*)str,"%s",USART_RX_BUF);
//				printf("USART_RX_BUF %s",str);
				 printf("中断任务同步");
			}
		}
    osDelay(1);
  }
  /* USER CODE END StartTask04 */
}

此实验只要中断发生,就会执行task里的任务。
在这里插入图片描述
串口中断与任务的同步

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  uint8_t str[20];
		extern osSemaphoreId_t myBinarySem01Handle; //二值信号量句柄
		BaseType_t xHigherPriorityTaskWoken;
	if(huart->Instance == USART1)	// 判断是由哪个串口触发的中断
	{
		if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)
		{
			__HAL_UART_CLEAR_IDLEFLAG(huart);
			if(rx_lengh<USART_REC_LEN)
			{
				USART_RX_BUF[rx_lengh++]=Rxbuffer;
			}
			else 
			{
				rx_flag=1;
			}
		}
		//printf("Rxbuffer %d",Rxbuffer-48);
		HAL_UART_Receive_IT(&huart1,&Rxbuffer, 1);
		
		if(myBinarySem01Handle!=NULL)
		{
			xSemaphoreGiveFromISR(myBinarySem01Handle,&xHigherPriorityTaskWoken);
		}
	}
}
void StartTask04(void *argument)
{
  /* USER CODE BEGIN StartTask04 */
	BaseType_t err=pdFALSE;
	uint8_t * str;
	printf("StartTask04");
  /* Infinite loop */
  for(;;)
  {
		//****************定时器2与任务04同步(2)/任务03与任务04同步(2)
		if(myBinarySem01Handle!=NULL)
		{
			err=xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY);//获取信号量
			if(err==pdTRUE) //获取信号量成功
			{
				 printf("中断任务同步");
			}
		}
    osDelay(1);
  }
  /* USER CODE END StartTask04 */
}

在这里插入图片描述
接收中断触发后,与任务同步

二.事件

使用信号量来同步的话任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。FreeRTOS 为此提供了一个可选的解决方法,那就是事件标志组。
即事件可以同步多个任务
使用事件必须配置V2接口
在这里插入图片描述

	BaseType_t xHigherPriorityTaskWoken;
	BaseType_t RE;
	if(huart->Instance == USART1)
	{
		if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)
		{
			__HAL_UART_CLEAR_IDLEFLAG(huart);
			if(rx_lengh<USART_REC_LEN)
			{
				USART_RX_BUF[rx_lengh++]=Rxbuffer;
			}
			else 
			{
				rx_flag=1;
			}
		}
		printf("Rxbuffer %d",Rxbuffer);
		if(Rxbuffer=='0')
		{
			RE=xEventGroupSetBitsFromISR(myEvent01Handle,EVENTBIT_3,&xHigherPriorityTaskWoken);
			if(RE!=pdFAIL)
			{
				portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
			}
		}
		HAL_UART_Receive_IT(&huart1,&Rxbuffer, 1);
	}
	BaseType_t xHigherPriorityTaskWoken;
  /* Infinite loop */
  for(;;)
  {
		EventBits_t EventValue;
		if(myEvent01Handle!=NULL)
		{
			EventValue=xEventGroupWaitBits((EventGroupHandle_t )myEvent01Handle, 
																						(EventBits_t ) EVENTBIT_ALL,
																						(BaseType_t )pdTRUE,
																						(BaseType_t )pdTRUE,
																						 (TickType_t )portMAX_DELAY);
			printf("事件标志组的值:%d\r\n",EventValue);
			printf("三个事件同步");
			OLED_Full();
		}
void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	
  /* Infinite loop */
  for(;;)
  {
		if(myEvent01Handle!=NULL)
		{
			key_num=read_key();
			switch(key_num)
			{
				case 2:printf("2");osEventFlagsSet(myEvent01Handle,EVENTBIT_0);break;
				case 3:printf("3");osEventFlagsSet(myEvent01Handle,EVENTBIT_1);break;
			}
		}
    osDelay(1);
  }
  /* USER CODE END StartTask02 */
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

地球先生_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值