【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
英文地址,請注明出處:http://en.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;盲目使用會導致程序穩定性…