【FreeRTOS-信号量】

参照正点原子以及以下gitee笔记整理本博客,并将实验结果附在文末。
https://gitee.com/xrbin/FreeRTOS_learning/tree/master

一、信号量简介

1、什么是信号量

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

假设有一个人需要在停车场停车。
在这里插入图片描述

  • 空车位:信号量资源数(计数值)
  • 让出占用车位: 释放信号量(计数值++)
  • 占用车位: 获取信号量(计数值–)
  1. 首先判断停车场是否还有空车位(判断信号量是否有资源)。
  2. 停车场正好有空车位(信号量有资源),那么就可以直接将车开入停车位进行停车(获取信号量成功)。
  3. 停车场已经没有空车位了(信号量没有资源),那么可以选择不停车(获取信号量失败),也可以选择等待(任务阻塞)其他人将车开出停车位(释放信号),然后在将车停如空车位。

2、信号量简介

答:
在这里插入图片描述- 当计数值大于0,表示有信号量资源。

  • 当释放信号量,信号量计数值(资源数)加一。
  • 当获取信号量,信号量计数值(资源数)减一。
  • 信号量的计数值都是有限的:限定最大值。
  • 如果最大值被限定为1,那么它就是二值信号量
  • 如果最大值不是1,它就是计数型信号量

注意:信号量用于传递状态

3、队列与信号量的对比

答:
在这里插入图片描述

二、二值信号量

1、二值信号量介绍

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

注意:二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值信号量更适合用于同步!!!
在这里插入图片描述

2、二值信号量相关API函数

答:使用二值信号量的过程:创建二值信号量 -> 释放二值信号量 -> 获取二值信号量
在这里插入图片描述

3、创建二值信号量函数

答:创建二值信号量函数:

SemaphoreHandle_t  xSemaphoreCreateBinary( void );
#define   xSemaphoreCreateBinary()
xQueueGenericCreate(1 , semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE)  /*二值信号量就是长度为1的队列、semSEMAPHORE_QUEUE_ITEM_LENGTH队列项大小是0,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 ) /* 递归互斥信号量 */

返回值:
在这里插入图片描述

4、释放二值信号量函数

答:释放二值信号量函数:

BaseType_t   xSemaphoreGive( xSemaphore ) 
#define   xSemaphoreGive ( xSemaphore )
xQueueGenericSend((QueueHandle_t)( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK) /*句柄,NULL表示数据,阻塞时间为0,尾部插入*/
#define   semGIVE_BLOCK_TIME       ( ( TickType_t ) 0U )

函数参数:
在这里插入图片描述
函数返回值:
在这里插入图片描述

5、获取二值信号量函数

答:获取二值信号量函数:

BaseType_t   xSemaphoreTake( xSemaphore, xBlockTime ) 

函数参数:
在这里插入图片描述
函数返回值:
在这里插入图片描述

三、计数型信号量

1、计数型信号量介绍

答:计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源(计数值),这在计数型信号量被创建的时候确定的。

计数型信号量适用场合:

  • 事件计数 : 当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1),其他任务会获取计数型信号量(计数值-1),这种场合一般在创建时将初始化计数值设置为0.
  • 资源管理 : 信号量表示有效资源数量。任务必须先获取信号量(信号计数值-1)才能获取资源控制权。当计数值减为0时表示没有资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)。信号量创建时计数值应等于最大资源数目。

注意:事件计数和资源管理的区别在于信号计数值的初始值不同

2、计数型信号量相关API函数

答:使用计数型信号量的过程:创建计数型信号量 -> 释放信号量 -> 获取信号量

在这里插入图片描述
注意:计数型信号量的释放与获取的函数和二值信号量一样。

3、计数型信号量创建函数

答:

#define 	xSemaphoreCreateCounting( uxMaxCount , uxInitialCount )xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) ) 

函数参数:
在这里插入图片描述
资源数取决于设置的初始计数值!

函数返回值:
在这里插入图片描述

4、获取计数型信号量计数值函数

答:

#define 	uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting(( QueueHandle_t )( xSemaphore ))

函数参数:
在这里插入图片描述
函数返回值:
在这里插入图片描述

四、优先级翻转介绍

1、优先级翻转简介

答:优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行。

优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。

在使用二值信号量的时候,经常会遇到优先级翻转的问题。

2、优先级翻转的例子

答:
在这里插入图片描述
高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中等优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)。

五、互斥信号量

1、互斥信号量介绍

答:互斥信号量其实就是一个 拥有优先级翻转的二值信号量

  • 二值信号量更适用于同步的应用。
  • 互斥信号量更适合那些需要互斥访问的应用(资源紧缺,需要资源保护)。

2、什么是优先级继承

答:当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有一个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级

3、优先级继承示例

答:

在这里插入图片描述
变为
在这里插入图片描述
此时任务H的阻塞时间仅仅是任务L的执行时间,将优先级翻转的危害降低到了最低。

4、互斥信号量的注意事项

答:优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响。

注意:互斥信号量不能用于中断服务函数中,原因如下:

  1. 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥信号量只能用于任务中,不能用于中断服务函数中。
  2. 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

5、互斥信号量相关API函数

答:使用互斥信号量:首先将宏configUSE_MUTEXES置1.

使用流程:创建互斥信号量 -> (task)获取信号量 -> (give)释放信号量

创建互斥信号量函数:
在这里插入图片描述
互斥信号量的释放和获取函数与二值信号量相同!!!只不过互斥信号量不支持中断中调用。

注意:创建互斥信号量时,会主动释放一次信号量。而二值信号量需要在创建完后进行手动释放,才能获取该信号量。
在这里插入图片描述

6、创建互斥信号量函数

答:

xxxxxxxxxx1 1#define   xSemaphoreCreateMutex()      xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )

函数返回值:
在这里插入图片描述
注意:

释放信号量不支持设置阻塞时间;

获取信号量支持设置阻塞时间;

六、二值信号量实验(掌握)

实验简介

在这里插入图片描述

实验现象

在这里插入图片描述
二值信号量状态变化:

1、创建信号量后的初始状态

semphore_handle = xSemaphoreCreateBinary();
  • 初始状态:0(空状态)

  • 刚创建的二值信号量是空的,没有可用的信号

2、释放信号量(Give)

xSemaphoreGive(semphore_handle);
  • 状态变化:0 → 1(空状态 → 满状态)

  • 释放信号量使其变为可用状态

3、获取信号量(take)

xSemaphoreTake(semphore_handle, portMAX_DELAY);

在这里插入图片描述

部分实验代码

/******************************************************************************************************* @file        freertos.c* @author      正点原子团队(ALIENTEK)* @version     V1.4* @date        2022-01-04* @brief       FreeRTOS 移植实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 探索者F407开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO  1
#define START_TASK_STACK_SIZE  128
TaskHandle_t start_task_handle;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define TASK1_PRIO  2
#define TASK1_STACK_SIZE  128
TaskHandle_t task1_handle;
void task1(void * pvParameters);/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define TASK2_PRIO  3
#define TASK2_STACK_SIZE  128
TaskHandle_t task2_handle;
void task2(void * pvParameters);
QueueHandle_t semphore_handle;/******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    semphore_handle = xSemaphoreCreateBinary();if(semphore_handle != NULL){printf("二值信号量创建成功\r\n");}xTaskCreate( (TaskFunction_t        )   start_task,(char *                )   "start_task",(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   START_TASK_PRIO,(TaskHandle_t *        )   &start_task_handle);//开启任务调度器vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();                     /*进入临界区,任务切换不会进行*/xTaskCreate( (TaskFunction_t        )     task1,(char *                )   "task1",(configSTACK_DEPTH_TYPE)   TASK1_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   TASK1_PRIO,(TaskHandle_t *        )   &task1_handle);xTaskCreate( (TaskFunction_t        )     task2,(char *                )   "task2",(configSTACK_DEPTH_TYPE)   TASK2_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   TASK2_PRIO,(TaskHandle_t *        )   &task2_handle);vTaskDelete( NULL );taskEXIT_CRITICAL();                       /*退出临界区,才会开始任务切换*//*简单而言,临界区保护,就是保护那些不想被打断的从程序段							 */							 }/* 任务一,释放二值信号量 */
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");}else{printf("信号量释放失败!!\r\n");}}}vTaskDelay(10);}
}/* 任务二,获取二值信号量 */
void task2(void * pvParameters)
{uint32_t i = 0;while(1){xSemaphoreTake(semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */printf("获取信号量成功:%d!!\r\n",++i);}
}

七、计数型信号量实验(掌握)

实验简介

在这里插入图片描述

实验现象

在这里插入图片描述

  1. 信号量创建
  • 创建最大计数值为100的计数型信号量

  • 初始计数值为0

  1. 任务分工
  • Task1(优先级2):监听按键,释放信号量

  • Task2(优先级3):获取信号量,打印计数值

  1. 工作流程
  • Task2在xSemaphoreTake()处阻塞等待,因为初始计数为0

  • 用户按下KEY0按键,Task1调用xSemaphoreGive()释放信号量,计数+1

  • Task2获取到信号量,计数-1,打印当前计数值

  • Task2延时1秒后继续循环

部分实验代码

/******************************************************************************************************* @file        freertos.c* @author      正点原子团队(ALIENTEK)* @version     V1.4* @date        2022-01-04* @brief       FreeRTOS 移植实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 探索者F407开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include <stdio.h>
#include <stdint.h>
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t start_task_handle;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO              2
#define TASK1_STACK_SIZE        128
TaskHandle_t task1_handle;
void task1(void * pvParameters);/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO              3
#define TASK2_STACK_SIZE        128
TaskHandle_t task2_handle;
void task2(void * pvParameters);/* 计数型信号量句柄 */
SemaphoreHandle_t Count_semphore_handle;/* 统计信息 */
static uint32_t semaphore_give_count = 0;      /* 释放次数统计 */
static uint32_t semaphore_take_count = 0;      /* 获取次数统计 *//******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    /* 创建计数型信号量:最大计数100,初始值0 */Count_semphore_handle = xSemaphoreCreateCounting(100, 0);if(Count_semphore_handle != NULL){printf("计数型信号量创建成功\r\n");printf("最大计数值: 100, 初始计数值: 0\r\n");}else{printf("计数型信号量创建失败\r\n");return;}/* 创建启动任务 */xTaskCreate( (TaskFunction_t        )   start_task,(char *                )   "start_task",(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   START_TASK_PRIO,(TaskHandle_t *        )   &start_task_handle);/* 开启任务调度器 */vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();                     /* 进入临界区,任务切换不会进行 *//* 创建任务1:信号量释放任务 */xTaskCreate( (TaskFunction_t        )     task1,(char *                )   "semaphore_give_task",(configSTACK_DEPTH_TYPE)   TASK1_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   TASK1_PRIO,(TaskHandle_t *        )   &task1_handle);/* 创建任务2:信号量获取任务 */                 xTaskCreate( (TaskFunction_t        )     task2,(char *                )   "semaphore_take_task",(configSTACK_DEPTH_TYPE)   TASK2_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   TASK2_PRIO,(TaskHandle_t *        )   &task2_handle);printf("所有任务创建完成\r\n");printf("按下KEY0释放信号量\r\n");vTaskDelete( NULL );                      /* 删除启动任务 */taskEXIT_CRITICAL();                      /* 退出临界区,才会开始任务切换 */
}/* 任务一,释放计数型信号量 */
void task1(void * pvParameters)
{uint8_t key = 0;BaseType_t result;while(1){ key = key_scan(0);if(key == KEY0_PRES){if(Count_semphore_handle != NULL){result = xSemaphoreGive(Count_semphore_handle);  /* 释放信号量 */if(result == pdPASS){semaphore_give_count++;printf("释放成功 [第%lu次] 当前计数值: %u\r\n", semaphore_give_count, (unsigned int)uxSemaphoreGetCount(Count_semphore_handle));}else{printf("释放失败 - 信号量已达最大值\r\n");}}}vTaskDelay(10);  /* 10ms延时,避免按键抖动 */}
}/* 任务二,获取计数型信号量 */
void task2(void * pvParameters)
{BaseType_t result;while(1){/* 获取信号量,最大等待时间5秒 */result = xSemaphoreTake(Count_semphore_handle, pdMS_TO_TICKS(5000));if(result == pdPASS){semaphore_take_count++;printf("获取成功 [第%lu次] 剩余计数值: %u\r\n", semaphore_take_count,(unsigned int)uxSemaphoreGetCount(Count_semphore_handle));/* 显示统计信息 */printf("统计 - 释放: %lu次, 获取: %lu次\r\n", semaphore_give_count, semaphore_take_count);}else{printf("获取超时 - 5秒内未获取到信号量\r\n");}vTaskDelay(pdMS_TO_TICKS(1000));  /* 1000ms延时 */}
}

八、优先级翻转实验(掌握)

实验简介

在这里插入图片描述

实验现象

在这里插入图片描述
在这里插入图片描述

部分实验代码

/******************************************************************************************************* @file        freertos.c* @author      正点原子团队(ALIENTEK)* @version     V1.4* @date        2022-01-04* @brief       FreeRTOS 移植实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 探索者F407开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO  1
#define START_TASK_STACK_SIZE  128
TaskHandle_t start_task_handle;
void start_task( void * pvParameters );/* low_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define low_task_PRIO  2
#define low_task_STACK_SIZE  128
TaskHandle_t low_task_handle;
void low_task(void * pvParameters);/* middle_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define middle_task_PRIO  3
#define middle_task_STACK_SIZE  128
TaskHandle_t middle_task_handle;
void middle_task(void * pvParameters);/* high_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define high_task_PRIO  4
#define high_task_STACK_SIZE  128
TaskHandle_t high_task_handle;
void high_task(void * pvParameters);/******************************************************************************************************/
QueueHandle_t semaphore_handle;
/*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    semaphore_handle = xSemaphoreCreateBinary();  /*创建二值信号量后资源数为0*/if(semaphore_handle != NULL){printf("二值信号量创建成功!!!\r\n");}xSemaphoreGive(semaphore_handle);xTaskCreate( (TaskFunction_t        )   start_task,(char *                )   "start_task",(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   START_TASK_PRIO,(TaskHandle_t *        )   &start_task_handle);//开启任务调度器vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();                     /*进入临界区,任务切换不会进行*/xTaskCreate( (TaskFunction_t        )     low_task,(char *                )   "low_task",(configSTACK_DEPTH_TYPE)   low_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   low_task_PRIO,(TaskHandle_t *        )   &low_task_handle);xTaskCreate( (TaskFunction_t        )     middle_task,(char *                )   "middle_task",(configSTACK_DEPTH_TYPE)   middle_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   middle_task_PRIO,(TaskHandle_t *        )   &middle_task_handle);xTaskCreate( (TaskFunction_t        )     high_task,(char *                )   "high_task",(configSTACK_DEPTH_TYPE)   high_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   high_task_PRIO,(TaskHandle_t *        )   &high_task_handle);vTaskDelete( NULL );taskEXIT_CRITICAL();                       /*退出临界区,才会开始任务切换*//*简单而言,临界区保护,就是保护那些不想被打断的从程序段							 */							 }/* 任务一,低优先级 */
void low_task(void * pvParameters)
{while(1){ printf("low_task is taking semaphore\r\n");xSemaphoreTake(semaphore_handle,portMAX_DELAY); printf("low_task is running\r\n");delay_ms(3000);printf("low_task is giving semaphore\r\n");xSemaphoreGive(semaphore_handle);vTaskDelay(1000);}
}/* 任务二,中优先级 */
void middle_task(void * pvParameters)
{while(1){printf("middle_task is running\r\n");vTaskDelay(1000);}
}/* 任务三,高优先级 */
void high_task(void * pvParameters)
{while(1){printf("high_task is taking semaphore\r\n");xSemaphoreTake(semaphore_handle,portMAX_DELAY); printf("high_task is running\r\n");delay_ms(1000);printf("high_task is giving semaphore\r\n");xSemaphoreGive(semaphore_handle);vTaskDelay(10);}
}

九、互斥信号量实验(掌握)

实验简介

在这里插入图片描述

实验现象

解决M打断L执行,从而使得高优先级等待更久时间的问题。
在这里插入图片描述

部分实验代码

/******************************************************************************************************* @file        freertos.c* @author      正点原子团队(ALIENTEK)* @version     V1.4* @date        2022-01-04* @brief       FreeRTOS 移植实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 探索者F407开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO  1
#define START_TASK_STACK_SIZE  128
TaskHandle_t start_task_handle;
void start_task( void * pvParameters );/* low_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define low_task_PRIO  2
#define low_task_STACK_SIZE  128
TaskHandle_t low_task_handle;
void low_task(void * pvParameters);/* middle_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define middle_task_PRIO  3
#define middle_task_STACK_SIZE  128
TaskHandle_t middle_task_handle;
void middle_task(void * pvParameters);/* high_task 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/#define high_task_PRIO  4
#define high_task_STACK_SIZE  128
TaskHandle_t high_task_handle;
void high_task(void * pvParameters);/******************************************************************************************************/
QueueHandle_t mutex_semaphore_handle;
/*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    mutex_semaphore_handle = xSemaphoreCreateMutex();  /*创建互斥信号量,并且主动释放一次信号量*/if(mutex_semaphore_handle != NULL){printf("互斥信号量创建成功!!!\r\n");}//xSemaphoreGive(mutex_semaphore_handle);  //互斥信号量在创建的时候默认自动释放信号量xTaskCreate( (TaskFunction_t        )   start_task,(char *                )   "start_task",(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   START_TASK_PRIO,(TaskHandle_t *        )   &start_task_handle);//开启任务调度器vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();                     /*进入临界区,任务切换不会进行*/xTaskCreate( (TaskFunction_t        )     low_task,(char *                )   "low_task",(configSTACK_DEPTH_TYPE)   low_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   low_task_PRIO,(TaskHandle_t *        )   &low_task_handle);xTaskCreate( (TaskFunction_t        )     middle_task,(char *                )   "middle_task",(configSTACK_DEPTH_TYPE)   middle_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   middle_task_PRIO,(TaskHandle_t *        )   &middle_task_handle);xTaskCreate( (TaskFunction_t        )     high_task,(char *                )   "high_task",(configSTACK_DEPTH_TYPE)   high_task_STACK_SIZE,(void *                )   NULL,   (UBaseType_t           )   high_task_PRIO,(TaskHandle_t *        )   &high_task_handle);vTaskDelete( NULL );taskEXIT_CRITICAL();                       /*退出临界区,才会开始任务切换*//*简单而言,临界区保护,就是保护那些不想被打断的从程序段							 */							 }/* 任务一,低优先级 */
void low_task(void * pvParameters)
{while(1){ printf("low_task is taking semaphore\r\n");xSemaphoreTake(mutex_semaphore_handle,portMAX_DELAY); printf("low_task is running\r\n");delay_ms(3000);printf("low_task is giving semaphore\r\n");xSemaphoreGive(mutex_semaphore_handle);vTaskDelay(1000);}
}/* 任务二,中优先级 */
void middle_task(void * pvParameters)
{while(1){printf("middle_task is running\r\n");vTaskDelay(1000);}
}/* 任务三,高优先级 */
void high_task(void * pvParameters)
{while(1){printf("high_task is taking semaphore\r\n");xSemaphoreTake(mutex_semaphore_handle,portMAX_DELAY); printf("high_task is running\r\n");delay_ms(1000);printf("high_task is giving semaphore\r\n");xSemaphoreGive(mutex_semaphore_handle);vTaskDelay(10);}
}

十、课堂总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84240.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中decltype / auto 类型自动推导的深入讲解

一、基本定义 关键字含义出现版本auto根据初始化表达式自动推导类型C11decltype根据表达式的类型推导类型C11 二、二者区别 特性autodecltype(expr)用途声明变量获取表达式类型是否需要初始化是否&#xff08;可用表达式&#xff0c;如函数参数&#xff09;是否推导引用否&am…

Echarts数据可视化开发教程+120套开源数据可视化大屏H5模板

数据可视化跨越了语言、技术和专业的边界&#xff0c;是能够推动实现跨界沟通&#xff0c;实现国际间跨行业的创新的工具。 正如画家用颜料表达自我&#xff0c;作者用文字讲述故事&#xff0c;而统计人员用数字沟通 ...... 同样&#xff0c;数据可视化的核心还是传达信息。 …

华为提取版,低调使用!

大家好呀&#xff01;今天想给大家推荐两款实用软件&#xff0c;一个是视频软件的定制版&#xff0c;另一个是卫星地图软件。 01 引言 之前给大家推荐过某秋音乐的定制版&#xff0c;结果被投诉了。以后大家推荐某秋家的软件要小心&#xff0c;不然很容易违规。 今天推荐的是…

天汇企业的网络设计与实现

天汇企业网络的设计与实现 摘要&#xff1a;互联网技术与通信技术的相互带动作用&#xff0c;使得两者皆呈现多样化的快速发展趋势&#xff0c;5G的时代序幕在已经逐渐开启&#xff0c;由此引发的互联网技术和设备变革必然是各界人士关注的重点&#xff0c;几乎所有与计算机相…

系统架构设计师:安全架构考点解析与例题

一、安全架构概述 安全架构是系统架构设计中确保信息系统安全性的重要组成部分,它定义了保护系统免受安全威胁的策略、技术和方法。安全架构需要贯穿系统设计的全生命周期,从需求分析到部署运维。 安全架构核心目标 ​​保密性​​:防止未授权访问信息​​完整性​​:防止…

计量经济学(复习/自用/未完)

补充&#xff1a; 1、多重共线性的补充 所谓的估计标准误&#xff0c;指的是回归系数的标准误差。例如回归方程&#xff1a; y β0 β1X1 β2X2 e 我们构建的回归方程的系数的计算得出是基于样本的。这意味着&#xff0c;我们每从总体中进行一次抽样&#xff0c;然后计算…

HarmonyOS性能优化——感知流畅优化

在应用开发中&#xff0c;动画可以为用户界面增添生动、流畅的交互效果&#xff0c;提升用户对应用的好感度。然而&#xff0c;滥用动画也会导致应用性能下降&#xff0c;消耗过多的系统资源&#xff0c;甚至影响用户体验。关于感知流畅度请参阅提升动画感知流畅度。 视觉感知…

基于Python的房屋信息可视化及价格预测系统

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.10(必须)数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;PyCharm 系统展示 系统首页 系统登录 房价预测 房屋管理 房屋分析 个人信息 密码修改 用户管理 摘…

(17)-java+ selenium->自动化测试-元素定位大法之By css上

1.简介 CSS定位方式和xpath定位方式基本相同,只是CSS定位表达式有其自己的格式。CSS定位方式拥有比xpath定位速度快,且比CSS稳定的特性。下面详细介绍CSS定位方式的使用方法。相对CSS来说,具有语法简单,定位速度快等优点。 2.CSS定位优势 CSS定位是平常使用过程中非常重要…

高效I/O处理:模型与多路复用的探讨

目录 一、了解IO模型 &#xff08;一&#xff09;异步IO和同步IO &#xff08;二&#xff09;五种IO快速回顾 二、IO多路复用 &#xff08;一&#xff09;IO 多路复用模型 &#xff08;二&#xff09;select 实现原理 &#xff08;三&#xff09;poll 实现原理 &#x…

行列式展开定理(第三种定义) 线性代数

目录 1.余子式 2代数余子式 3行列式展开公式&#xff08;常用&#xff09; 本篇的用途是关于三阶以上行列式的一般解法。因为对于三阶以上行列式我们没有类似于2阶和三阶一样的特殊的求值办法&#xff0c;而对于我们上一篇讲的办法来说又太复杂了&#xff0c;一般考试几乎不…

一种轻量级IDS,使用新型特征选择方法进行早期APT检测

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 高级持续性威胁 (APT) 是一种多阶段、高度复杂且隐蔽的网络威胁形式&#xff0c;它通过获得对网络的未授权访问来窃取有价值的数据或破坏目标网络。这些威胁通常在很长一段时间内未被发现&#xff0c;这…

深入理解 let、var 和 const

JavaScript 中的变量声明有三种主要方式&#xff1a;var、let 和 const。理解它们之间的差异对于编写清晰、有效的代码至关重要。本文将深入探讨这三种声明方式的区别、使用场景以及潜在的陷阱。 一、var 关键字 1.1 特点 函数作用域&#xff1a;var 声明的变量在函数内是局…

RT thread 在gd32f303平台下rtc bug date获取时间错误始终是1970

现象 时间设置指令 date 2025 6 18 10 28 00 时间获取指令 date date指定显示设置OK,但是返回的时间始终是Thu Jan 1 08:00:00 1970 msh >date local time: Thu Jan 1 08:00:00 1970 timestamps: 0 timezone: UTC+

jieba中lcut与cut的区别及用法

jieba 库中的 cut 和 lcut 是中文分词的核心函数&#xff0c;两者的核心区别在于​​返回类型​​和​​适用场景​​&#xff0c;具体对比如下&#xff1a; ⚙️ 1. ​​核心区别​​ ​​函数​​​​返回类型​​​​特点​​​​等价操作​​jieba.cut生成器&#xff08;G…

LoRA、QLoRA是什么

一&#xff1a; LoRA&#xff08;Low-Rank Adaptation&#xff0c;低秩适应&#xff09;是一种高效的大模型参数微调技术&#xff0c;由Meta在2021年提出。它通过冻结预训练模型参数&#xff0c;仅训练少量新增的低秩矩阵&#xff0c;大幅减少了需要训练的参数量&#xff0c;同…

【web应用】在 Vue 3 中实现饼图:使用 Chart.js实现饼图显示数据分析结果

文章目录 前言一、准备工作二、实现饼图组件三、关键点解析四、实现效果总结 前言 在现代 Web 应用中&#xff0c;数据可视化是不可或缺的一部分。无论是展示统计信息还是监控关键指标&#xff0c;图表都能帮助用户更直观地理解数据。在 Vue 3 项目中&#xff0c;我们可以使用…

分页数据不准问题分析与解决

大纲 &#x1f4d6; 1、场景 &#x1fab5;2、原因 &#x1f525;3、解决方式&#xff1a;游标分页 &#x1f4cf;4、一点思考&#x1f4a1;5、全表查询的优化思路 &#x1f345; 记录一个分页不准的问题 1、场景 &#x1fab5; 调用一个第三方List接口&#xff08;带分页&am…

MyBatis原理剖析(三)--加载配置文件

下面我们正式进入mybatis的源码学习&#xff0c;之前我们已经了解过mybatis中通过配置文件来保证与数据库的交互。配置文件分为核心配置文件和映射配置文件&#xff0c;核心配置文件的主要作用就是加载数据库的一些配置信息而映射配置文件则是执行对应的sql语句。同时核心配置文…

C++(运算符重载)

一.友元 C中使用关键字friend可以在类外访问所有的成员&#xff0c;包括私有成员&#xff08;之前提到过封装的核心思想是隐藏内部实现细节&#xff0c;通过公共接口控制访问&#xff09;&#xff0c;所以友元可以突破封装的限制访问数据&#xff0c;盲目使用会导致程序稳定性…