14_FreeRTOS二值信号量

目录

信号量的简介

队列与信号量的对比

二值信号量

二值信号量相关API函数

实验源码


信号量的简介

信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问

假设有一个人需要在停车场停车

1.首先判断停车场是否还有空车位(判断信号量是否有资源)

2.停车场正好有空车位(信号量有资源),那么就可以直接将车开入空车位进行停车(获取信号量成功) ;

3.停车场已经没有空车位了(信号量没有资源) ,那么这个人可以选择不停车(获取信号量失败) ;也可以选择等待(任务阻塞)其他人将车开出停车场(释放信号量资源),然后再将车停入空车位。

空车位:可以理解为信号量资源数(计数值)

让出占用车位:释放信号量(计数值++)

占用车位:获取信号量(计数值--)

14_FreeRTOS二值信号量_第1张图片

当计数值大于0,代表有信号量资源

当释放信号量,信号量计数值(资源数)加一

当获取信号量,信号量计数值(资源数)减一

信号量:用于传递状态

信号量的计数值都有限制:限定最大值。

如果最大值被限定为1,那么它就是二值信号量;

如果最大值不是1,它就是计数型信号量。

队列与信号量的对比

14_FreeRTOS二值信号量_第2张图片

 

 

二值信号量

二值信号量的本质是一个队列长度为1的队列,该队列就只有空和满两种情况,这就是二值。

二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值信号量更适合用于同步!

14_FreeRTOS二值信号量_第3张图片

二值信号量相关API函数

使用二值信号量的过程:创建二值信号量→释放二值信号量→获取二值信号量

14_FreeRTOS二值信号量_第4张图片

 

创建二值信号量函数: SemaphoreHandle_t  xSemaphoreCreateBinary(void)
#define xSemaphoreCreateBinary()

xQueueGenericCreate(1,semSEMAPHORE_QUEUE_ITEM_LENGTH,queueQUEUE_TYPE_BINARY_SEMAPHORE) 

#define semSEMAPHORE_QUEUE_ITEM_LENGTH ((uint8_t) 0U)

#define queueQUEUE_TYPE_BASE  		((uint8_t) 0U)		 /*队列*/
#define queueQUEUE_TYPE_SET		((uint8_t) 0U)		 /*队列集*/
#define queueQUEUE_TYPE_MUTEX		((uint8_t) 1U)		/*互斥信号量*/
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE 	 ((uint8_t) 2U)	 /*计数型信号量*/
#define queueQUEUE_TYPE_BINARY_SEMAPHORE 	 ((uint8_t) 3U) /*二值信号量*/
#define queueQUEUE_TYPE_RECURSIVE_MUTEX		((uint8_t) 4U) 	/*递归互斥信号量*/

14_FreeRTOS二值信号量_第5张图片

 

释放二值信号量函数:BaseType_t xSemaphoreGive(xSemaphore)

#define xSemaphoreGive ( xSemaphore )

xQueueGenericSend( (QueueHandle_t) (xSemaphore), NULL , 
semGIVE_BLOCK_TIME , queueSEND_TO_BACK)

 #define semGIVE_BLOCK_TIME((TickType_t) 0U)

 

 

获取二值信号量函数: BaseType_t xSemaphoreTake(xSemaphore, xBlockTime)

14_FreeRTOS二值信号量_第6张图片

 

 

实验源码

将设计三个任务:start_task、task1、task2

start_task:用来创建task1和task2任务

Task1:用于按键扫描,当检测到按键KEY0被按下时,释放二值信号量

task2:获取二值信号量,当成功获取后打印提示信息

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include 
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "user_key.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/*二值信号量句柄*/
QueueHandle_t semphore_handle;
/* Variables 变量--------------------------------------------------------------*/ 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);


//任务优先级
#define TASK1_PRIO			2
//任务堆栈大小	
#define TASK1_STK_SIZE 		100  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);


//任务优先级
#define TASK2_PRIO			3
//任务堆栈大小	
#define TASK2_STK_SIZE 		100  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);



 int main(void)
 {	

	/*配置系统中断分组为4位抢占*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*创建二值信号量*/
	 semphore_handle = xSemaphoreCreateBinary(); 
	 
	 if(semphore_handle == NULL)
	 {
		printf("二值信号量创建不成功\r\n\r\n");
	 }else
	 {
		printf("二值信号量创建成功\r\n\r\n");
	 }
	 
	 /*创建开始任务*/
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
		

}
 

/*!
	\brief		开始任务函数
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建任务1
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler);   
    //创建任务2
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler); 

				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/*!
	\brief		task1释放二值信号量
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void task1(void *pvParameters)
{
	uint8_t key = 0;
	BaseType_t err;
    while(1)
    {	
		/*获取按键值*/
		key = Key_Scan(0);
		
		if(key == KEY0_PRES)
		{
			if(semphore_handle != NULL)
			{	
				err = xSemaphoreGive(semphore_handle);
				if(err == pdPASS)
				{
					printf("信号量释放成功\r\n\r\n");
				}else
				{
					printf("信号量释放失败\r\n\r\n");
				}
			}		
		}
		
		vTaskDelay(100);
    }
} 


/*!
	\brief		task2获取二值信号量
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void task2(void *pvParameters)
{

    while(1)
    {
		/*获取信号量死等,进入阻塞态*/
		xSemaphoreTake(semphore_handle,portMAX_DELAY);
		
		printf("获取信号量成功!!!\r\n\r\n");
    }
}



 /************************************************************** END OF FILE ****/

14_FreeRTOS二值信号量_第7张图片

 

你可能感兴趣的:(FreeRTOS,FreeRTOS,stm32,单片机,物联网,嵌入式硬件)