<FreeRTOS入门第七节>信号量学习(上)

本文详细介绍了嵌入式RTOS中的两种信号量——二值式信号量和计数型信号量。二值式信号量仅有两种状态,用于任务同步;计数型信号量则能记录队列中使用的资源数量,适用于资源管理和事件计数。文中通过创建、释放和获取信号量的API示例,展示了如何在实际任务中运用这两种信号量,并给出了相关代码实现及效果展示。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

今天很充实,晚上去吃席。


一、什么是信号量?

信号量就是用来管理资源和同步任务的,并且信号量可以分为二值式信号量,计数型信号量、互斥信号量,递归互斥信号量。
本编博客主要说二值式和计数型信号量。

二、二值式信号量

2.1 什么是二值式信号量

二值式信号量:就是只有两个状态,0或1。有数据和没有数据。主要用于任务同步。
其实质就是一个包含一个项的队列,这个你可以看下semaphore的相关源码就能清楚明了了。

在这里插入图片描述

在这里插入图片描述

2.2 相关API介绍

使用信号量的API时要主函数要添加semphr.h库
创建二值信号量
在这里插入图片描述

其中第一个是老版的创建二值信号量(已经淘汰),动态创建二值信号量使用xSemaphoreCreateBinary()函数。这里只讲一下动态创建API,其他自己看源码哈。

/*
	动态创建二值信号量  打开configSUPPORT_DYNAMIC_ALLOCATION宏
	BaseType_t的返回值函数。
	成功:其他值
	失败:NULL	
*/
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xSemaphoreCreateBinary()    xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif

释放二值信号量
在这里插入图片描述

/*
	释放信号量(像队列中添加消息)
	xSemaphore:semaphore的句柄
	成功:pdTRUE 
	失败:pdFALSE
*/
#define xSemaphoreGive( xSemaphore )    xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

获取二值信号量
在这里插入图片描述

/*
	获取二值式信号量数据
	xSemaphore:semaphore的句柄
	xBlockTime:阻塞时间
	成功:pdTRUE 
	失败:pdFALSE	
*/
#define xSemaphoreTake( xSemaphore, xBlockTime )    xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )

实战
main.c
任务一获取信号量的数据然后判断在通过串口打印“Semaphore->True”
任务二使用一个变量来实现二值信号量的释放

#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "stdio.h"

#ifdef __GNUC__ //printf重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch,1,HAL_MAX_DELAY);
    return ch;
}

TaskHandle_t HandlerTask1;
TaskHandle_t Task_Name4;


BaseType_t xReturn;

SemaphoreHandle_t Task1semaphore;


void SystemClock_Config(void);
StackType_t xTask3Static[128];
StaticTask_t xTaskTCB;

StackType_t xIdle3Static[128];
StaticTask_t xIdleTCB;

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize ){
			*ppxIdleTaskTCBBuffer=&xIdleTCB;				
			*ppxIdleTaskStackBuffer=xIdle3Static;
			*pulIdleTaskStackSize=128;
}

void Task1Function( void * param){
		BaseType_t err;
	for(;;){
		if(Task1semaphore!=NULL){
			err=xSemaphoreTake(Task1semaphore,portMAX_DELAY);
			if(err==pdTRUE){
				printf("Semaphore->True\r\n");			
			}
		}
		vTaskDelay(100);
	}
}
void Task2Function(void* param){
		uint8_t num;
		
  for(;;)
  {
		num++;
		if(num==2){
			xSemaphoreGive(Task1semaphore);
			
		}else if(num==8){
			xSemaphoreGive(Task1semaphore);	
		
		}
		printf("Task%d\r\n",num);
		vTaskDelay(100);
  }
}
void Task3Funtion(void* param){
	TickType_t st_time=xTaskGetTickCount(); 

	while(1){
		uint32_t num =1;
		xTaskDelayUntil(&st_time,30);
		
	}
	
}

void Task4Funtion(void* param){
	taskENTER_CRITICAL();
	
	Task1semaphore=xSemaphoreCreateBinary();
	
	xReturn=xTaskCreate(Task1Function,"Task1",128,NULL,2,&HandlerTask1);
	
	xTaskCreate(Task2Function,"Task2",128,NULL,2,NULL);

 	xTaskCreateStatic(Task3Funtion,"Task3",128,NULL,2,xTask3Static,&xTaskTCB);
	if(xReturn == pdPASS){
			uint8_t buffS[20]="Task1 Create OK..\r\n";
			HAL_UART_Transmit(&huart1,(uint8_t*)buffS,strlen(buffS)*sizeof(char),HAL_MAX_DELAY);
			
		}
	vTaskDelete(Task_Name4);
	taskEXIT_CRITICAL();
}



int main(void)
{
  
	
	HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
	MX_USART1_UART_Init();
	
	xTaskCreate(Task4Funtion,"Task4",600,NULL,1,&Task_Name4);
	
  vTaskStartScheduler();
	
  while (1)
  {
   
  }
 
}


void SystemClock_Config(void)
{
	
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
 
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{

}
#endif /* USE_FULL_ASSERT */

效果展示:
在这里插入图片描述

三、计数型信号量

3.1 什么是计数型信号量

计数型信号量就是有多个队列,并且你可以读取现在队列里使用了多少的队列项,其主要用于事件计数和资源管理

3.2 相关API介绍

在这里插入图片描述

主要介绍一下计数型信号量的创建函数

/*
	动态创建计数型信号量
	uxMaxCount:队列项的数量
	uxInitialCount:队列项的初始开始位
	成功:返回其他
	失败:NULL
*/
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )    xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif
/*
	获取计数型信号量的队列值
	SemaphoreHandle_t:信号量句柄
	成功:pdTRUE 
	失败:pdFALSE
	注意使用uxSemaphoreGetCount()函数时不要使用xSemaphoreTake();,不然获取的数一直为初始化的值
*/
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );

案例代码
main.c

#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "stdio.h"

#ifdef __GNUC__ //printf重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch,1,HAL_MAX_DELAY);
    return ch;
}

TaskHandle_t HandlerTask1;
TaskHandle_t Task_Name4;


BaseType_t xReturn;

SemaphoreHandle_t Task1semaphore;


void SystemClock_Config(void);
StackType_t xTask3Static[128];
StaticTask_t xTaskTCB;

StackType_t xIdle3Static[128];
StaticTask_t xIdleTCB;

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize ){
			*ppxIdleTaskTCBBuffer=&xIdleTCB;				
			*ppxIdleTaskStackBuffer=xIdle3Static;
			*pulIdleTaskStackSize=128;
}

void Task1Function( void * param){
		BaseType_t err;
		UBaseType_t Semaphore_num;
	for(;;){
		if(Task1semaphore!=NULL){
			//xSemaphoreTake(Task1semaphore,portMAX_DELAY);
			//if(err==pdTRUE){
				Semaphore_num=uxSemaphoreGetCount(Task1semaphore);
				printf("Semaphore->Number:%d\r\n",Semaphore_num);			
			//}
		}
		vTaskDelay(100);
	}
}
void Task2Function(void* param){
		uint8_t num;
		
  for(;;)
  {
		num++;
		xSemaphoreGive(Task1semaphore);		
		printf("Task%d\r\n",num);
		vTaskDelay(100);
  }
}
void Task3Funtion(void* param){
	TickType_t st_time=xTaskGetTickCount(); 

	while(1){
		uint32_t num =1;
		xTaskDelayUntil(&st_time,30);
		
	}
	
}

void Task4Funtion(void* param){
	taskENTER_CRITICAL();
	
	Task1semaphore=xSemaphoreCreateCounting(255,0);
	//Task1semaphore=xSemaphoreCreateBinary();
	xReturn=xTaskCreate(Task1Function,"Task1",128,NULL,2,&HandlerTask1);
	
	xTaskCreate(Task2Function,"Task2",128,NULL,2,NULL);

 	xTaskCreateStatic(Task3Funtion,"Task3",128,NULL,2,xTask3Static,&xTaskTCB);
	if(xReturn == pdPASS){
			uint8_t buffS[20]="Task1 Create OK..\r\n";
			HAL_UART_Transmit(&huart1,(uint8_t*)buffS,strlen(buffS)*sizeof(char),HAL_MAX_DELAY);
			
		}
	vTaskDelete(Task_Name4);
	taskEXIT_CRITICAL();
}



int main(void)
{
  
	
	HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
	MX_USART1_UART_Init();
	
	xTaskCreate(Task4Funtion,"Task4",600,NULL,1,&Task_Name4);
	
  vTaskStartScheduler();
	
  while (1)
  {
   
  }
 
}


void SystemClock_Config(void)
{
	
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
 
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{

}
#endif /* USE_FULL_ASSERT */

效果展示
在这里插入图片描述

总结

二值式信号量和计数型信号量区别就是二值式只有一个队列,计数型的队列是很多。
少壮不努力,老大徒伤悲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

单片有机机

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

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

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

打赏作者

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

抵扣说明:

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

余额充值