目录
信号量的简介
队列与信号量的对比
二值信号量
二值信号量相关API函数
实验源码
信号量的简介
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。
假设有一个人需要在停车场停车
1.首先判断停车场是否还有空车位(判断信号量是否有资源)
2.停车场正好有空车位(信号量有资源),那么就可以直接将车开入空车位进行停车(获取信号量成功) ;
3.停车场已经没有空车位了(信号量没有资源) ,那么这个人可以选择不停车(获取信号量失败) ;也可以选择等待(任务阻塞)其他人将车开出停车场(释放信号量资源),然后再将车停入空车位。
空车位:可以理解为信号量资源数(计数值)
让出占用车位:释放信号量(计数值++)
占用车位:获取信号量(计数值--)
当计数值大于0,代表有信号量资源
当释放信号量,信号量计数值(资源数)加一
当获取信号量,信号量计数值(资源数)减一
信号量:用于传递状态
信号量的计数值都有限制:限定最大值。
如果最大值被限定为1,那么它就是二值信号量;
如果最大值不是1,它就是计数型信号量。
队列与信号量的对比
二值信号量
二值信号量的本质是一个队列长度为1的队列,该队列就只有空和满两种情况,这就是二值。
二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值信号量更适合用于同步!
二值信号量相关API函数
使用二值信号量的过程:创建二值信号量→释放二值信号量→获取二值信号量
创建二值信号量函数: 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) /*递归互斥信号量*/
释放二值信号量函数: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)
实验源码
将设计三个任务:start_task、task1、task2
start_task:用来创建task1和task2任务
Task1:用于按键扫描,当检测到按键KEY0被按下时,释放二值信号量
task2:获取二值信号量,当成功获取后打印提示信息
/**
******************************************************************************
* @file : user_mian.h
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#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 ****/