目录
一、信号量的概念
1、信号量的基本概念
2、信号量的分类
二、二值信号量简介
三、二值信号量相关API
1、创建二值信号量
2、释放二值信号量
3、获取二值信号量
四、二值信号量实操
1、实验需求
2、CubeMX配置
3、代码实现
一、信号量的概念
1、信号量的基本概念
信号量(Semaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关键代 码段不被并发调用。
信号量这个名字,我们可以把它拆分来看,信号可以起到通知信号的作用,然后我们的量还可以 用来表示资源的数量,当我们的量只有0和1的时候,它就可以被称作二值信号量,只有两个状 态,当我们的那个量没有限制的时候,它就可以被称作为计数型信号量。
信号量也是队列的一种。
2、信号量的分类
二值信号量(同步应用)
计数信号量(资源管理)
互斥信号量(互斥访问)
递归互斥信号量(简要了解即可)
二、二值信号量简介
二值信号量其实就是一个长度为1,大小为零的队列,只有0和1两种状态,通常情况下,我们用它来进行互斥访问或任务同步。
互斥访问:比如门跟钥匙,只有获取到钥匙才可以开门
任务同步:比如学习完知识点才能写博客
三、二值信号量相关API
函数 | 描述 |
xSemaphoreCreateBinary() | 使用动态方式创建二值信号量 |
xSemaphoreCreateBinaryStatic() | 使用静态方式创建二值信号量 |
xSemaphoreGive() | 释放信号量 |
xSemaphoreGiveFromISR() | 在中断中释放信号量 |
xSemaphoreTake() | 获取信号量 |
xSemaphoreTakeFromISR() | 在中断中获取信号量 |
1、创建二值信号量
SemaphoreHandle_t xSemaphoreCreateBinary( void );
参数:
- 无
返回值:
- 成功,返回对应二值信号量的句柄;
- 失败,返回 NULL 。
2、释放二值信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
参数:
- xSemaphore:要释放的信号量句柄
返回值:
- 成功,返回 pdPASS ;
- 失败,返回 errQUEUE_FULL 。
3、获取二值信号量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait );
参数:
- xSemaphore:要获取的信号量句柄
- xTicksToWait:超时时间,0 表示不超时,portMAX_DELAY表示卡死等待;
返回值:
- 成功,返回 pdPASS ;
- 失败,返回 errQUEUE_FULL 。
四、二值信号量实操
1、实验需求
创建一个二值信号量,按下 KEY1 则释放信号量,按下 KEY2 获取信号量。
2、CubeMX配置
这里已经将FreeRTOS移植到STM32F103C8T6,具体操作流程看前面的文章。
查看原理图配置按键引脚
这里已经将FreeRTOS移植到STM32F103C8T6,具体操作流程看前面的文章。
创建两个任务用来放入和获取信号量
创建一个二值信号量
3、代码实现
uart.c 重定向printf
#include "stdio.h"
int fputc(int ch,FILE *f)
{unsigned char temp[1] = {ch};HAL_UART_Transmit(&huart1,temp,1,0xffff);return ch;
}
需要打开魔术棒勾上红框内选项实现串口打印
打开freertos.c并添加代码
void StartTaskGive(void const * argument)
{for(;;){if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){osDelay(20);if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){ if(xSemaphoreGive(myBinarySemHandle) == pdPASS) printf("二值信号量获取成功\r\n");elseprintf("二值信号量放释放失败\r\n");}while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);}osDelay(10);}
}void StartTaskTake(void const * argument)
{for(;;){if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){osDelay(20);if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){// 0 表示不超时,portMAX_DELAY表示卡死等待 if(xSemaphoreTake(myBinarySemHandle, portMAX_DELAY ) == pdPASS) printf("二值信号量获取成功\r\n");elseprintf("二值信号量获取失败\r\n");}while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);}osDelay(10);}
}
可见释放二值信号量后便可以成功获取获取二值信号量,但是只能释放多次就只有第一次能释放成功,同时获取也是只能获取一次(前提是已经释放),多次获取也只有第一次能获取成功。
注意:
- 创建后的二值信号量原先代码和修改后的代码如下:由于CubeMX内置函数中存在bug,即在创建二值信号量时就已经释放二值信号量,所以会出现不按下KEY1(释放二值信号量)时,按下KEY2就直接能获取二值信号量,如下:
- 若将获取二值信号量函数的第二个参数修改成卡斯等待,即portMAX_DELAY,如下
xSemaphoreTake(myBinarySemHandle, portMAX_DELAY )
那么会出现在没释放二值信号量前按下KEY2(获取二值信号量),那么会一直卡死等待释放二值信号量,当KEY1一按下,二值信号量会被立马获取,此时就不存在二值信号量,当KEY1再次按下时,还是会释放成功,如下: