文章目录[隐藏]
FreeRTOS复习笔记(四) —— 信号量
一、二值信号量与计数信号量
1.本例程思路:
本篇将二值信号量与计数信号量写入同一段代码,使用 _USE_BINARY_SEMAPHORE 与 _USE_COUNT_SEMAPHORE 进行区分
对于二值信号量,创建两个任务,一个任务用于释放信号量,另一个任务用于获取信号量,当KEY_GPIO(PA0)出现下降沿时释放信号量
对于计数信号量,当KEY_GPIO(PA0)出现下降沿时获取信号量和释放信号量,并打印当前可使用信号量数量
二值信号量的创建可以调用 xSemaphoreCreateBinary 函数,计数信号量的创建可以调用 xSemaphoreCreateCounting 函数
释放信号量使用 xSemaphoreGive,获取信号量使用 xSemaphoreTake
2.代码编写
/**
******************************************************************************
* @文件名: xxx.c
* @作 者: author
* @版 本: v1.0.0
* @日 期: 2021.12.24
* @简 介: 无
* @注 意: 无
******************************************************************************
*/
#include "stm32f10x.h"
#include "dr_usart.h"
#include "dr_led.h"
#include "dr_key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
//#define _USE_BINARY_SEMAPHORE
#define _USE_COUNT_SEMAPHORE
void AppTaskCreateTask(void *);
void LEDTask(void *);
void KEYTask(void *);
/* --- 任务 --- */
TaskHandle_t LEDTask_Handle = NULL;
#ifdef _USE_BINARY_SEMAPHORE
/* --- 二值信号量 --- */
SemaphoreHandle_t BinarySemaphore_Handle = NULL;
#endif
#ifdef _USE_COUNT_SEMAPHORE
/* --- 计数信号量 --- */
SemaphoreHandle_t CountSemaphore_Handle = NULL;
#endif
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
int main(void)
{
/* --------- --------- --------- --------- --------- --------- --------- */
/* 中断分组4 */
NVIC_Priority_Group_Config(); /* * */
/* 串口1配置 */
USART1_Config(); /* * */
/* LED(PA8, PA6)配置 */
LED_GPIO_Config(); /* * */
/* KEY(PA0)配置 */
KEY_GPIO_Config();
/* --------- --------- --------- --------- --------- --------- --------- */
/* 创建任务 */
xTaskCreate(AppTaskCreateTask, "AppTaskCreateTask", 128, NULL, 1, NULL);
/* 开启任务调度 */
vTaskStartScheduler();
while(1);
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void AppTaskCreateTask(void *pvParameters)
{
/* 临界保护 */
taskENTER_CRITICAL();
/* 创建任务 */
xTaskCreate(LEDTask, "LEDTask", 128, NULL, 2, &LEDTask_Handle);
xTaskCreate(KEYTask, "KEYTask", 128, NULL, 3, NULL);
#ifdef _USE_BINARY_SEMAPHORE
/* 创建二值信号量 */
BinarySemaphore_Handle = xSemaphoreCreateBinary();
if (BinarySemaphore_Handle != NULL)
printf("--- The BinarySemaphore was created successful ---.\r\n\r\n");
#endif
#ifdef _USE_COUNT_SEMAPHORE
/* 创建计数信号量, 信号量个数 初始化均可被获取 */
CountSemaphore_Handle = xSemaphoreCreateCounting(2, 2);
if (CountSemaphore_Handle != NULL)
printf("--- The CountSemaphores was created ---.\r\n\r\n");
#endif
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void LEDTask(void *pvParameters)
{
BaseType_t xReturn = pdFALSE;
for (;;)
{
#ifdef _USE_BINARY_SEMAPHORE
/* 获取二值信号量, 信号量句柄 等待超时时间 */
xReturn = xSemaphoreTake(BinarySemaphore_Handle, 0);
if (xReturn == pdTRUE)
printf("The BinarySemaphore has been obtained.\r\n");
#endif
/* 翻转LED */
GPIOA->ODR ^= ((uint16_t)0x0100);
// printf("LED %s\r\n", ((GPIOA->IDR & 0x0100) != 0) ? "is running." : "stops running.");
(void)xReturn;
vTaskDelay(50);
}
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void KEYTask(void *pvParameters)
{
uint8_t level_high = 0;
uint8_t level_low = 0;
uint8_t edge_fall = 0;
uint8_t edge_rise = 0;
uint8_t _switch = 0;
BaseType_t xReturn = pdFALSE;
UBaseType_t CurrentSemaphoreNum = 0;
for (;;)
{
/* 高电平/上升沿检测 */
if ( (GPIOA->IDR & 0x0001) != 0 )
{
if(level_low == 1)
edge_rise = 1;
level_low = 0;
level_high = 1;
}
/* 低电平/下降沿检测 */
if ( (GPIOA->IDR & 0x0001) == 0 )
{
if(level_high == 1)
edge_fall = 1;
level_high = 0;
level_low = 1;
}
/* 出现下降沿 */
if (edge_fall)
{
#ifdef _USE_BINARY_SEMAPHORE
/* 释放二值信号量 */
xReturn = xSemaphoreGive(BinarySemaphore_Handle);
if (xReturn == pdTRUE)
printf("The BinarySemaphore has been released successful.\r\n");
#endif
#ifdef _USE_COUNT_SEMAPHORE
switch(_switch)
{
case 0:
/* 获取计数信号量, 信号量句柄 等待超时时间 */
xReturn = xSemaphoreTake(CountSemaphore_Handle, 0);
_switch++;
break;
case 1:
/* 获取计数信号量 */
xReturn = xSemaphoreTake(CountSemaphore_Handle, 0);
_switch++;
break;
case 2:
/* 获取计数信号量 */
xReturn = xSemaphoreTake(CountSemaphore_Handle, 0);
_switch++;
break;
case 3:
/* 释放计数信号量, 信号量句柄 */
xReturn = xSemaphoreGive(CountSemaphore_Handle);
_switch++;
break;
case 4:
/* 释放计数信号量 */
xReturn = xSemaphoreGive(CountSemaphore_Handle);
_switch = 0;
break;
default: _switch = 0;
}
if ( (_switch == 1) || (_switch == 2) || (_switch == 3) )
{
if (xReturn == pdTRUE)
printf("obtained. ");
else
printf("#error: no Semaphore. ");
}
if ( (_switch == 0) || (_switch == 4) )
printf("released. ");
/* 计数信号量数量 */
CurrentSemaphoreNum = uxSemaphoreGetCount(CountSemaphore_Handle);
printf("CurrentSemphoresNum: %lu\r\n", CurrentSemaphoreNum);
#endif
}
edge_fall = 0;
edge_rise = 0;
(void)edge_rise;
(void)_switch;
(void)CurrentSemaphoreNum;
vTaskDelay(20);
}
}
3.使用串口观察输出信息
二值信号量(一个任务释放信号量,另一个任务获取信号量)
计数信号量(获取后信号量数量减少,释放后增加)
经验证,程序运行结果与预想一致
二、互斥信号量
1.本例程思路:
创建三个任务,首先使用二值信号量模拟出优先级翻转,随后将二值信号量改为使用互斥信号量,与二值信号量进行对比,展示出互斥信号量的优先级继承机制
本篇使用 _USE_BINARY_SEMAPHORE 与 _USE_MUTEX_SEMAPHORE 区分使用二值信号量与互斥信号量
创建二值信号量调用 xSemaphoreCreateBinary 函数,创建互斥信号量调用 xSemaphoreCreateMutex 函数
2.代码编写
/**
******************************************************************************
* @文件名: xxx.c
* @作 者: author
* @版 本: v1.0.0
* @日 期: 2021.12.26
* @简 介: 无
* @注 意: 无
******************************************************************************
*/
#include "stm32f10x.h"
#include "dr_usart.h"
#include "dr_led.h"
#include "dr_key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
//#define _USE_BINARY_SEMAPHORE
#define _USE_MUTEX_SEMAPHORE
void AppTaskCreateTask(void *);
void LowPriorityTask(void *);
void MidPriorityTask(void *);
void HighPriorityTask(void *);
#ifdef _USE_BINARY_SEMAPHORE
/* --- 二值信号量 --- */
SemaphoreHandle_t BinarySemaphore_Handle = NULL;
#else
/* --- 互斥信号量 --- */
SemaphoreHandle_t MutexSemaphore_Handle = NULL;
#endif
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
int main(void)
{
/* --------- --------- --------- --------- --------- --------- --------- */
/* 中断分组4 */
NVIC_Priority_Group_Config(); /* * */
/* 串口1配置 */
USART1_Config(); /* * */
/* LED(PA8, PA6)配置 */
LED_GPIO_Config(); /* * */
/* KEY(PA0)配置 */
KEY_GPIO_Config();
/* --------- --------- --------- --------- --------- --------- --------- */
/* 创建任务 */
xTaskCreate(AppTaskCreateTask, "AppTaskCreateTask", (uint16_t)128, NULL, (UBaseType_t)1, NULL);
/* 开启任务调度 */
vTaskStartScheduler();
while(1);
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void AppTaskCreateTask(void *pvParameters)
{
/* 临界保护 */
taskENTER_CRITICAL();
/* 创建任务 */
xTaskCreate(HighPriorityTask, "HighPriorityTask", (uint16_t)128, NULL, (UBaseType_t)4, NULL);
xTaskCreate(MidPriorityTask, "MidPriorityTask", (uint16_t)128, NULL, (UBaseType_t)3, NULL);
xTaskCreate(LowPriorityTask, "LowPriorityTask", (uint16_t)128, NULL, (UBaseType_t)2, NULL);
#ifdef _USE_BINARY_SEMAPHORE
/* 创建二值信号量 */
BinarySemaphore_Handle = xSemaphoreCreateBinary();
if (BinarySemaphore_Handle != NULL)
printf("--- BinarySemaphore was Created ---.\r\n\r\n");
/* 释放二值信号量 */
xSemaphoreGive(BinarySemaphore_Handle);
#else
/* 创建互斥信号量 */
MutexSemaphore_Handle = xSemaphoreCreateMutex();
if (MutexSemaphore_Handle != NULL)
printf("--- MutexSemaphore was Created ---.\r\n\r\n");
#endif
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void LowPriorityTask(void *pvParameters)
{
uint32_t i = 0;
BaseType_t xReturn = pdFALSE;
for (;;)
{
#ifdef _USE_BINARY_SEMAPHORE
/* 等待二值信号量 */
xReturn = xSemaphoreTake(BinarySemaphore_Handle, portMAX_DELAY);
#else
/* 等待互斥信号量 */
xReturn = xSemaphoreTake(MutexSemaphore_Handle, portMAX_DELAY);
#endif
/* LowPriorityTask 占用信号量 */
if (xReturn == pdTRUE)
printf("LowPriorityTask has obtained the semaphore.\r\n");
/* 任务切换 */
for(i = 0; i < 0x7ffff; i++)
taskYIELD();
#ifdef _USE_BINARY_SEMAPHORE
/* 释放二值信号量 */
xReturn = xSemaphoreGive(BinarySemaphore_Handle);
#else
/* 释放互斥信号量 */
xReturn = xSemaphoreGive(MutexSemaphore_Handle);
#endif
/* LowPriorityTask 释放信号量 */
if (xReturn == pdTRUE)
printf("LowPriorityTask has released the semaphore.\r\n");
vTaskDelay(50);
}
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void MidPriorityTask(void *pvParameters)
{
for (;;)
{
/* 翻转LED */
GPIOA->ODR ^= ((uint16_t)0x0100);
printf("MidPriorityTask is running.\r\n");
vTaskDelay(50);
}
}
/**
* @简 介: 无
* @参 数: 无
* @返回值: 无
*/
void HighPriorityTask(void *pvParameters)
{
BaseType_t xReturn = pdFALSE;
for (;;)
{
#ifdef _USE_BINARY_SEMAPHORE
/* 等待二值信号量 */
xReturn = xSemaphoreTake(BinarySemaphore_Handle, portMAX_DELAY);
#else
/* 等待互斥信号量 */
xReturn = xSemaphoreTake(MutexSemaphore_Handle, portMAX_DELAY);
#endif
/* HighPriorityTask 占用信号量 */
if (xReturn == pdTRUE)
printf("HighPriorityTask has obtained the semaphore.\r\n");
#ifdef _USE_BINARY_SEMAPHORE
/* 释放二值信号量 */
xReturn = xSemaphoreGive(BinarySemaphore_Handle);
#else
/* 释放互斥信号量 */
xReturn = xSemaphoreGive(MutexSemaphore_Handle);
#endif
/* HighPriorityTask 释放信号量 */
if (xReturn == pdTRUE)
printf("HighPriorityTask has released the semaphore.\r\n");
vTaskDelay(50);
}
}
3.使用串口观察输出信息
二值信号量(发生了优先级翻转,打断了高优先级任务)
互斥信号量(体现出了互斥量的优先级继承机制,提升了低优先级任务的优先级)
经验证,程序运行结果与预想一致
版权声明:本文为CSDN博主「SSS&10&01」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45691873/article/details/122159390
暂无评论