主頁 >  其他 > CubeMX使用FreeRTOS編程指南

CubeMX使用FreeRTOS編程指南

2021-10-22 09:05:14 其他

文章目錄

  • CubeMX使用FreeRTOS編程指南
    • 一、開發前言
      • 1.1 軟體準備
      • 1.2 開啟FreeRTOS
    • 二、配置界面
    • 三、系統設定
      • 2.1 調度內核設定
      • 2.2 記憶體管理設定
      • 2.3 鉤子函式配置
      • 2.5 任務運行追蹤配置
      • 2.6 協程配置
      • 2.7 軟體定時器配置
      • 2.8 中斷優先級配置
    • 三、內核裁剪
    • 四、創建任務與佇列
      • 4.1 CubeMX 下任務創建與配置
      • 4.2 CubeMX 下佇列的創建與配置
    • 五、創建定時器和信號量
      • 5.1 CubeMX下定時器的創建和配置
      • 5.2 CubeMX下信號量的創建和配置
    • 六、創建互斥量
      • 6.1 CubeMX下互斥量的創建和配置
    • 七、創建事件標志組
      • 7.1 CubeMX下事件的創建和配置
    • 八、用戶常量
    • 九、任務通知
    • 十、系統內核配置

CubeMX使用FreeRTOS編程指南

一、開發前言

1.1 軟體準備

  • STM32CubeMX 代碼生成軟體

  • MDK 集成代碼開發環境

1.2 開啟FreeRTOS

新建一個 CubeMX 工程,在配置好時鐘后,點擊 Middleware -> 選擇 FreeRTOS -> 下拉框選擇 V2 版本 CMSIS

到此在 CubeMX 中就已經開啟 FreeRTOS 系統了,下面分享 FreeRTOS 的配置:

二、配置界面

開啟 FreeRTOS 之后,可以看到配置項主要分為以下幾個部分

這幾個部分的主要功能如下表:

配置項功能
Tasks and Queues任務與佇列,用于配置任務體以及訊息佇列;
Timers and Semaphores軟體定時器與信號量,用于配置內核物件 (軟體定時器和信號量);
Mutexes互斥量,用于配置內核物件(互斥量)
Events事件,配置內核物件(事件)
FreeRTOS Heap Usage查看用戶任務和系統任務的堆占用
Config Parameters系統的引數配置
Include Parameters系統的功能裁剪
Advanced SettingsCubeMX 生成代碼預配置項
User Constants用戶常量定義

以上各個功能分的很清晰,我們需要配置什么功能就去對應的選項下進行配置,下面根據各個配置項進行詳細配置介紹

三、系統設定

首先我們先了解一下 Config Parameters,他的配置引數如下

引數功能表:

引數功能
API顯示 FreeRTOS API 介面版本
Version顯示 FreeRTOS 內核版本
顯示 CMSIS 版本
Kernel SettingFreeRTOS 調度內核設定
Memory management setting記憶體管理設定
Hook function related definitions鉤子函式有關定義
Run time and task stats gathering related definitions系統運行時的引數收集配置
Co-routine related definitions協程配置
Software timer definitons軟體定時器任務配置
Interrupt nesting behaviour configuration中斷優先級配置

API 和 Version 不過多解釋,顯示版本資訊

2.1 調度內核設定

Kernel Setting 是 FreeRTOS 的調度內核配置,展開后有下面的配置項,使用時一般保持默認,也可以根據需要修改

  • USE_PREEMPTION

USE_PREEMPTION 是 RTOS 的調度方式選擇,為 1 時使用搶占式調度器,為 0 時使用協程,如果使用搶占式調度器的話內核會在每個時鐘節拍中斷中進行任務切換,當使用協程的話會在如下地方進行任務切換

  1. 一個任務呼叫了函式 taskYIELD(),
  2. 一個任務呼叫了可以使任務進入阻塞態的 API 函式,
  3. 應用程式明確定義了在中斷中執行背景關系切換,
  • CPU_CLOCK_HZ

CPU_CLOCK_HZ 是 CPU 系統時鐘頻率,默認使用的是晶振通過時鐘樹后獲得的時鐘頻率

  • TICK_RATE_HZ

TICK_RATE_HZ 是 RTOS 的心跳時鐘頻率,默認為最大值 1000 ,即心跳時鐘 1ms 跳動一次

  • MAX_PRIORITIES

MAX_PRIORITIES 是 RTOS 任務的最高優先級設定,默認56級,一般來說一個優先級表是32位,這里用了兩個,對應64位,其中8位用于系統任務的優先級處理

  • MINIMAL_STACK_SIZE

MINIMAL_STACK_SIZE 設定分配給空閑任務的堆疊大小,該值是用字(32位)指定的,而不是位元組,默認為128個字,如果修改過空閑任務,則根據實際情況修改

  • MAX_TASK_NAME_LEN

MAX_TASK_NAME_LEN 設定任務名稱的最大字符數,默認16位足夠

  • USE_16_BIT_TICKS

USE_16_BIT_TICKS 存放 Tick 周期的計數器的數字位寬,默認為 Disable 即 16 位

  • IDLE_SHOULD_YIELD

如果IDLE_SHOULD_YIELD 設定為0,則空閑任務永遠不會讓位于另一個任務,只在被搶占時才會離開運行狀態,如果 IDLE_SHOULD_YIELD 設定為1,那么當有另一個空閑優先級任務處于Ready狀態時,空閑任務將不會執行它定義的功能的不止一次迭代,而不會讓位于另一個任務,這確保當應用程式任務處于空閑狀態時,在空閑任務中花費的時間最少,即同在空閑優先級下,空閑任務優先級更高,不會被搶占,不會以時間片運行

  • USE_MUTEXES、USE_RECURSIVE_MUTEXES、USE_COUNTING_SEMAPHORES

為 1 則開啟系統構建程序中的互斥量、遞回互斥量和信號量,該值強制為1(ENABLE)

  • QUEUE_REGISTRY_SIZE

佇列注冊表的大小,可以用于管理佇列名稱和佇列物體,方便運行中進行查看與管理,默認為8

  • USE_APPLICATION_TASK_TAG

使能時會給任務一個 TAG 標簽,便于用戶進行使用

  • ENABLE_BACKWARD_COMPATIBILITY

一個兼容性使能,使能后, FreeRTOS 8.0.0 之后的版本可以通過宏定義使用 8.0.0 版本之前的函式介面,默認使能

  • USE_PORT_OPTIMISED_TASK_SELECTION

查找下一個任務方式的選擇,查找下一個就緒任務就是查找優先級表,對優先級表進行導0演算法分為通用切換或者針對性切換,一般默認不使能,使用通用切換,通用切換使用C撰寫,執行效率低,兼容性高;針對性切換使用處理器自帶的導0指令,使用匯編撰寫,切換效率高,但兼容性差

  • USE_TICKLESS_IDLE

使能后會生成的兩個空函式PreSleepProcessing和PostSleepProcessing,用戶可以撰寫代碼進入低功耗模式,生成函式如下圖

  • USE_TASK_NOTIFICATIONS

任務通知使能,每個RTOS任務都有一個32位的通知值,RTOS任務通知是一個直接發送給任務的事件,它可以解除接收任務的阻塞,并可選地更新接收任務的通知值,為1開啟,為0關閉,關閉可以為每個任務節省8個位元組的記憶體空間

  • RECORD_STACK_HIGH_ADDRESS

記錄任務的堆疊入口地址到TCB,為1使能,為0關閉

2.2 記憶體管理設定

記憶體管理可以看到3個配置引數

  • Memory Allocation

記憶體分配方式,此處默認動態和靜態都可以

  • TOTAL_HEAP_SIZE

記憶體堆的分配大小,堆本質上就是一個陣列,此處是設定堆陣列的大小,設定時要考慮最小要滿足所有任務的使用要求,最大不要超過系統的分配上限

  • Memory Management scheme

記憶體分配方式,有heap_1.c, heap_2.c, heap_3.c, heap_4.c and heap5.c 5種,其中1、2、4、5都是先建立一個堆陣列,從陣列中申請,用完再釋放,與C語言中molloc和free使用鏈表的方式不同,該方式在 MCU 中更安全穩定,此處默認使用的方式4,具體申請釋放方式可以在heap4.c中閱讀到

關于堆和堆疊的區別,可以閱讀我的另外一篇文章進行了解:C語言:記憶體四區

2.3 鉤子函式配置

鉤子函式是一種回呼函式,用于在任務執行一次之后或者某些事件發生后執行的函式,該配置項里面有五個選項,控制5種不同功能的鉤子函式開啟,當然用戶也可以在代碼中自己定義

  • USE_IDLE_HOOK

使能后,系統生成一個慷訓呼函式,由用戶撰寫函式主體

void vApplicationIdleHook(void)

每當空閑任務執行一次,鉤子函式都會被執行一次

  • USE_TICK_HOOK

使能后,系統生成一個慷訓呼函式,由用戶撰寫函式主體

void vApplicationTickHook(void)

每個TICK周期,鉤子函式都會執行一次

  • USE_MALLOC_FAILED_HOOK

使能后,系統生成一個慷訓呼函式,由用戶撰寫函式主體

void vApplicationMallocFailedHook(void)

當申請動態記憶體失敗時,鉤子函式會執行一次

  • USE_DAEMON_TASK_STARTUP_HOOK

使能后,系統生成一個慷訓呼函式,由用戶撰寫函式主體

void vApplicationDaemonTaskStartupHook(void).

任務剛啟動時,鉤子函式會執行一次

  • CHECK_FOR_STACK_OVERFLOW

使能后,系統生成一個慷訓呼函式,由用戶撰寫函式主體

void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName );

任務堆疊溢位時,鉤子函式會執行一次,傳入任務 TCB 和任務名稱

當我們在 CubeMX 里面開啟對應鉤子函式,生成代碼之后,在FreeRTOS就可以看到自動生成的鉤子函式,我們在里面撰寫相應的功能就行

2.5 任務運行追蹤配置

功能配置項如下:

  • GENERATE_RUN_TIME_STATS

開啟時間統計功能,在呼叫 vTaskGetRunTimeStats() 函式時,將任務運行時間資訊保存到可讀串列中

  • USE_TRACE_FACILITY

使能后會包含額外的結構成員和函式以幫助執行可視化和跟蹤,默認開啟,方便 MDK 軟體工具除錯使用

  • USE_STATS_FORMATTING_FUNCTIONS

使能后會生成 vTaskList() 和 vTaskGetRunTimeStats() 函式用于獲取任務運行狀態

2.6 協程配置

Co-routine related definitions 是協程的配置項,兩個選項用來配置協程是否開啟,以及協程的優先級,開啟后,需要用戶手動創建協程,在協程幾乎很少用到了,是 FreeRTOS目前還沒有把協程移除的計劃,但 FreeRTOS是不會再更新和維護協程了,因此大家解一下就行

協程特點:

  1. 堆疊使用
    所有的協程使用同一個堆疊(如果是任務的話每個任務都有自己的堆疊),這樣就比使用任務消耗更少的 RAM
  2. 調度器和優先級
    協程使用合作式的調度器,但是可以在使用搶占式的調度器中使用協程
  3. 宏實作
    協程是通過宏定義來實作的
  4. 使用限制
    為了降低對 RAM 的消耗做了很多的限制

具體 API 介面和調度原理可以參考這篇文章 : FreeRTOS協程

2.7 軟體定時器配置

軟體定時器配置的一些相關項如下:

這四個配置項主要與軟體定時器處理任務有關,軟體定時器任務屬于系統任務(守護執行緒),開啟軟體定時器后用于維護軟體定時器

  • USE_TIMERS

默認開啟軟體定時器任務

  • TIMER_TASK_PRIORITY

軟體定時器任務優先級

  • TIMER_QUEUE_LENGTH

定時器任務佇列長度FreeRTOS 是通過佇列來發送控制命令給定時器任務,叫做定時器命令佇列,此處設定佇列長度

  • TIMER_TASK_STACK_DEPTH

軟體定時器任務堆疊大小

2.8 中斷優先級配置

  • LIBRARY_LOWEST_INTERRUPT_PRIORITY

此宏是用來設定最低優先級,FreeRTOS 使用的4位優先級,對應16位優先級,對應的最低優先級為15

  • LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

設定FreeRTOS 系統可管理的最大優先級,也就是設定閾值優先級,這個大家可以自由設定,這里設定為5,也就是高于5 的優先級(優先級數小于5)不歸 FreeRTOS 管理

三、內核裁剪

Include Parameters 下的選項應用于內核裁剪,裁剪不必要的功能,精簡系統功能,減少資源占用,主要有以下幾個選項:

配置項可裁剪的函式功能如下:

選項功能
vTaskPrioritySet改變某個任務的任務優先級,
uxTaskPriorityGet查詢某個任務的優先級,
vTaskDelete洗掉任務
vTaskCleanUpResources回收任務洗掉后的資源如RAM等等
vTaskSuspend掛起任務
vTaskDelayUntil阻塞延時一段絕對時間(絕對延時去去除程式執行時間,執行更精準)
vTaskDelay阻塞延時一段相對時間
xTaskGetSchedulerState獲取任務調度器的狀態,開啟或未開啟
xTaskResumeFromISR在中斷服務函式中恢復一個任務的運行
xQueueGetMutexHolder獲取信號量的佇列擁有者,回傳擁有此信號量的佇列
xSemaphoreGetMutexHolder查詢擁有互斥鎖的任務,回傳任務控制塊
pcTaskGetTaskName獲取任務名稱
uxTaskGetStackHighWaterMark獲取任務的堆疊的歷史剩余最小值,FreeRTOS 中叫做“高水位線”
xTaskGetCurrentTaskHandle此函式用于獲取當前任務的任務句柄,就是獲取當前任務控制塊
eTaskGetState此函式用于查詢某個任務的運行壯態,比如:運行態、阻塞態、掛起態、就緒態等
xEventGroupSetBitFromISR在中斷服務函式中將指定的事件位清零
xTimerPendFunctionCall定時器守護任務的回呼函式(定時器守護任務使用到一個命令佇列,只要向佇列發送信號就可以執行相應代碼,可以實作“中斷推遲處理”功能)
xTaskAbortDelay中止延時函式,該函式能立即解除任務的阻塞狀態,將任務插入就緒串列中
xTaskGetHandle此函式根據任務名字獲取的任務句柄(控制塊)

四、創建任務與佇列

4.1 CubeMX 下任務創建與配置

任務(執行緒)是作業系統運行的基本單元,也是資源分配的基本單元, CubeMX 任務的創建基本以圖形化進行,配置方式如下

進入Tashs and Queues 配置,點擊 Add 添加新任務

任務配置引數介紹

引數功能
Task Name任務名稱,保存在 TCB 結構體中,設定時自己起名字
Priority任務優先級,任務的調度等級,根據自己創建任務的緊急程度設定
比如通信任務不能被打斷,可以設計較高優先級
Stack Size(Words)設定給任務分配的記憶體大小,單位是字,對于32位單片機來說占4個位元組
Entry Function任務物體,即任務的運行函式名
Code Generation代碼生成模式
As weak: 產生一個用 __weak 修飾的弱定義任務函式,用戶可自己在進行定義;
As external: 產生一個外部參考的任務函式,用戶需要自己定義該函式;
Default: 產生一個默認格式的任務函式,用戶需要在該函式內實作自己的功能
Parameter:傳入的引數,保持默認就行
Allocation:記憶體分配方式
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

設定完成后點擊OK,配置就完成了,之后生成代碼,使用 MDK 進一步配置任務的具體資訊

在生成的代碼中,我們打開 freertos.c 檔案可以在代碼中看到任務的配置資訊

在 freertos.c 檔案的末尾部分,我們可以看到生成的任務物體

任務物體本身就是一個死回圈函式,回圈執行程式代碼,但回圈體代碼里面必須要有延時函式,釋放當前任務對 MCU 的控制權,使其他低優先級可以執行,此外,關于任務,CubeMX 提供了一系列的用戶呼叫介面函式,具體如下

函式功能
osThreadNew創建新任務
*osThreadGetName獲取任務名稱
osThreadGetId獲取當前任務的控制塊(TCB)
osThreadGetState獲取當前任務的運行狀態
osThreadGetStackSize獲取任務的堆疊大小
osThreadGetStackSpace獲取任務剩余的堆疊大小
osThreadSetPriority設定任務優先級
osThreadGetPriority獲取任務優先級
osThreadYield切換控制權給下一個任務
osThreadSuspend掛起任務
osThreadResume恢復任務(掛起多少次恢復多少次)
osThreadDetach分離任務,方便任務結束進行回收
osThreadJoin等待指定的任務停止
osThreadExit停止當前任務
osThreadTerminate停止指定任務
osThreadGetCount獲取激活的任務數量
osThreadEnumerate列舉激活的任務

4.2 CubeMX 下佇列的創建與配置

佇列,又稱為訊息佇列,用于任務間的資料通信,傳輸資料,在作業系統里面,直接使用全域變數傳輸資料十分危險,看似正常運行,但不知道啥時候就會因為暫存器或者記憶體等等原因引起崩潰,所以引入訊息,佇列的概念,任務發送資料到佇列,需要接受訊息的任務掛起在佇列的掛起串列,等待訊息的到來,CubeMX 創建佇列的步驟如下:

先點擊 Add 添加佇列

佇列配置引數介紹

引數功能
Queue Name佇列名稱(自己設定)
Queue Size訊息佇列大小
Item Size佇列傳輸型別,保持默認16 位就行
Allocation佇列記憶體的分配方式
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

配置需要的引數后,點擊OK,然后生成代碼

生成代碼后,我們可以在 freertos.c 中系統初始話函式中看到佇列的初始化

初始化函式會在一開始被呼叫,對 FreeRTOS 系統和內核物件進行初始化,初始化后系統就可以進行調度和使用內核物件,CubeMX 生成的代碼自動將創建的內核物件放到初始化函式內,所以我們在任務和中斷中直接使用就可以,佇列的 FreeRTOS API 介面在CubeMX 內再次進行了封裝,使用更加簡單,使用方式如下:

我們使用的 CMSIS 2.0 版本,所以在任務檔案中包含呼叫宣告頭檔案

#include "cmsis_os2.h"

在佇列頭檔案內我們可以在 600 多行的位置找到有關佇列的 API 函式宣告:

下面介紹一下佇列有關介面的函式介面:

函式功能
osMessageQueueNew創建并初始化一個新的佇列
osMessageQueueGetName獲取佇列的名字
osMessageQueuePut發送一條訊息到佇列
osMessageQueueGet從佇列等待一條訊息
osMessageQueueGetCapacity獲取佇列傳輸訊息的峰值
osMessageQueueGetMsgSize獲取佇列使用記憶體池的最大峰值
osMessageQueueGetCount獲取佇列的訊息數量
osMessageQueueGetSpace獲取佇列剩余的可用空槽
osMessageQueueReset清空佇列
osMessageQueueDelete洗掉佇列

以上的API介面有其對應的傳入引數,具體使用方式需要在翻原始碼的注釋,這里我選常用的來介紹一下:

訊息佇列常用的是插入與獲取訊息,初始化系統已經幫助我們完成,在初始化的時候會獲取一個佇列的句柄,之后對佇列的操作都是圍繞這個句柄展開,比如上面的代碼中,句柄就是 myQueue01Handle ,我們發送一個訊息到這個佇列,就是呼叫發送函式,對句柄進行操作,先看一下發送訊息的函式原型

osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);

引數的功能

引數功能
mq_id傳入佇列的句柄
*msg_ptr指向需要發送的訊息內容的指標
msg_prio本次發送訊息的優先級(目前API未加入功能)
timeout發送訊息的超時時間(設定為0代表一直等待發送成功)
osStatus_t(回傳值)回傳執行結果

回傳值的可能

錯誤含義
osOK執行正常
osError系統錯誤
osErrorTimeout執行超時
osErrorResource資源不可用
osErrorParameter引數無效
osErrorNoMemory記憶體不足
osErrorISR不允許在中斷呼叫
osStatusReserved防止編譯器優化項,不需要管他

所以我們發送一個訊息到佇列,函式用法如下:

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	osStatus_t result;
	uint8_t dat[]="666\r\n";
  /* Infinite loop */
  for(;;)
  {
		result= osMessageQueuePut(&myQueue01Handle,dat,1,0);
		if(result == osOK)
		{
			//發送成功
		}else
		{
			//發送失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartTask02 */
}

發送訊息的優先級暫時無用,CubeMX 對 FreeRTOS 的支持還不完善,發送訊息里面的優先級未使用到,并且入隊方式使用的是發送到佇列尾部,沒有從頭部插入的方式,有需求可以 通過包含 queue.h 檔案,呼叫 FreeRTOS 的官方代碼,或者自己修改 生成代碼的 API 介面結合優先級使用佇列的向前插入和向后插入,豐富系統功能!

除了發送訊息到佇列,接受佇列的訊息 API 介面也經常用到,函式原型如下

osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);

引數的功能

引數功能
mq_id接受佇列的句柄
*msg_ptr用于接受訊息內容的指標
msg_prio存放接受訊息的優先級(目前API未加入功能)
timeout接受訊息的超時時間(設定為10代表,當前任務掛起在掛起串列,直到接收成功時恢復,或者10個TICK等待周期到達然后任務強行恢復,不再等待,為0則是不等待,等待期間任務掛起在內核物件的掛起佇列)
osStatus_t(回傳值)回傳執行結果

函式用法

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	osStatus_t result;
	uint8_t dat[10]={};
	uint8_t *pro;
  /* Infinite loop */
  for(;;)
  {
		result= osMessageQueueGet(&myQueue01Handle,dat,pro,10);
		if(result == osOK)
		{
			//接受成功
		}else
		{
			//接受失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartTask02 */
}

注意:FreeRTOS 中獲取和發送訊息的 API 介面函式分為任務中呼叫和中斷中呼叫,CubeMX 代碼介面將兩者整合了,呼叫時自動判斷呼叫環境是在 ISR 還是正常運行環境中

五、創建定時器和信號量

5.1 CubeMX下定時器的創建和配置

軟體定時器本質上就是設定一段時間,當設定的時間到達之后就執行指定的功能函式,呼叫的這個函式叫做回呼函式,回呼函式的兩次執行間隔叫做定時器的定時周期,簡而言之,當定時器的定時周期到了以后就會執行回呼函式,下面介紹一下 CubeMX 中開啟定時器的方法:

在 CubeMX 里面按下面步驟添加定時器

然后配置具體引數,引數的功能如下:

引數功能
Timer Name設定定時器的名稱
Callback設定定時器的回呼函式體
Type設定定時器的執行型別
osTimerPeriodic 定時器周期執行回呼函式
osTimerOnce 定時器只執行一次回呼函式
Code Generation Option代碼生成模式
As weak: 產生一個用 __weak 修飾的弱定義任務函式,用戶可自己在進行定義;
As external: 產生一個外部參考的任務函式,用戶需要自己定義該函式;
Default: 產生一個默認格式的任務函式,用戶需要在該函式內實作自己的功能
Parameter傳入引數,保持默認NULL就行
Allocation軟體定時器記憶體的分配方式,一般使用動態
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

引數配置完成后,生成代碼,我們可以在 freertos.c 檔案里面看到定時器創建后獲得的句柄,以及生成的回呼函式:

有了句柄,我們就可以呼叫 cmsis_os2.c 里面的定時器介面函式對定時器進行操作,先看一下 CubeMX 提供的定時器介面函式及其功能

函式功能
osTimerNew新建定時器,回傳定時器控制句柄
osTimerGetName獲取定時器名稱
osTimerStart設定定時器周期,啟動定時器
osTimerStop停止定時器
osTimerIsRunning檢測定時器是否在運行
osTimerDelete洗掉定時器

其中常用的介面是定時器的啟動和停止

定時器啟動: osTimerStart,函式原型

osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);

引數介紹:

引數功能
timer_id需要啟動的定時器句柄
ticks設定定時器的運行周期

此處的 ticks 設定的數字是定時器兩次呼叫回呼函式的周期數目,每個 tick 是一個心跳時鐘的長度

使用例程:

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
    osStatus_t result;
    uint8_t dat[10]={0};
    uint8_t *pro;
    result= osTimerStart(&myTimer01Handle,10);
    if(result == osOK)
    {
        //啟動成功
    }else
    {
        //啟動失敗
    }
    
  /* Infinite loop */
  for(;;)
  {
		

    osDelay(10);
  }
  /* USER CODE END StartTask02 */
}

按照例程啟動定時器,定時器會以 10個tick 的周期,呼叫回呼函式

回呼函式不要放阻塞函式,程式盡可能短

定時器啟動: osTimerStop,函式原型

osStatus_t osTimerStop (osTimerId_t timer_id);

引數只有一個,就是定時器的控制句柄,傳入即可停止定時器,例程如下

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	osStatus_t result;
	uint8_t dat[10]={0};
	uint8_t *pro;
    result= osTimerStop(&myTimer01Handle);
    if(result == osOK)
    {
        //停止成功
    }else
    {
        //停止失敗
    }
  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
  }
  /* USER CODE END StartTask02 */
}

軟體定時器是由軟體定時器維護任務進行維護,檢測各個定時器的狀態,進行處理,回呼回呼函式,軟體定時器維護任務的引數配置在前面的 Config 就已經提到過

5.2 CubeMX下信號量的創建和配置

信號量是 RTOS 的一個內核物件,該物件有一個隊串列示該信號量擁有的信號數目,任何任務都可以對這個信號數目進行獲取和釋放,獲取時信號-1,釋放時信號+1,為0時不能繼續獲取,此時有任務想要繼續獲取信號量的話,任務會掛起在該內核物件的掛起串列,等到信號可以獲取時進行恢復,根據這個特性,信號量常用于控制對共享資源的訪問和任務同步,下面介紹一下 CubeMX 下信號量的配置:

點開配置頁面,可以看到有兩個信號量添加頁面,其中 Binary Semaphores 是二值信號量,Counting Semaphores 是計數信號量,二進制信號量,僅有一個佇列或者說 token,用于同步一個操作;計數信號量則擁有多個 tokens,可用于同步多個操作,或者管理有限資源

二值信號量創建:

點擊 Add,配置引數

引數介紹

引數功能
Semaphore Name信號量名稱
Allocation記憶體分配方式,一般使用動態
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

計數信號量:

點擊 Add,配置引數

引數介紹

引數功能
Semaphore Name信號量名稱
Count計數信號量的最大數目
Allocation記憶體分配方式,一般使用動態
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

配置完成后我們生成代碼,在 freertos.c 的初始化代碼中可以看到信號量被創建,并且回傳了信號量的控制句柄

下面介紹一下 CubeMX 提供的信號量操作函式介面:

函式功能
osSemaphoreNew創建新的信號量
*osSemaphoreGetName獲取信號量的名稱
osSemaphoreAcquire獲取信號量
osSemaphoreRelease釋放信號量
osSemaphoreGetCount獲取當前可用信號量的數目
osSemaphoreDelete洗掉信號量

其中常用的函式有獲取和釋放信號量,下面介紹一下這兩個函式的引數和使用方式

獲取信號量 osSemaphoreAcquire

函式原型

osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);

引數介紹

引數功能
semaphore_id傳入要獲取信號量的控制句柄
timeout獲取等待時間(等待期間任務掛起在內核物件的掛起佇列)

使用例程

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
	
	
  /* Infinite loop */
  for(;;)
  {
		result = osSemaphoreAcquire(&myBinarySem01Handle,10);
		if(result == osOK)
		{
			//獲取成功
		}else
		{
			//獲取失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

釋放信號量 osSemaphoreRelease

函式原型

osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);
引數功能
semaphore_id傳入要釋放的信號量控制句柄

使用例程

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
	
	
  /* Infinite loop */
  for(;;)
  {
		result = osSemaphoreRelease(&myBinarySem01Handle);
		if(result == osOK)
		{
			//釋放成功
		}else
		{
			//釋放失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

二值信號量和計數信號量的操作基本一致,沒用區別,只是用有的信號佇列最大數目不同而已

同時注意信號量在使用程序中會出現優先級反轉的Bug,使用時需要注意

六、創建互斥量

6.1 CubeMX下互斥量的創建和配置

互斥量其實就是一個擁有優先級繼承的二值信號量,互斥信號量適合用于那些需要互斥訪問的應用中,在互斥訪問中互斥信號量相當于一個鑰匙,當任務想要使用資源的時候就必須先獲得這個鑰匙,當使用完資源以后就必須歸還這個鑰匙,這樣其他的任務就可以拿著這個鑰匙去使用資源,與信號量不同的是,互斥量的釋放必須由獲取他的任務進行釋放,如果不釋放,可能會造成死鎖

死鎖就是兩個任務獲取對方擁有的鎖,各自進入掛起串列,無法釋放互斥鎖

下面介紹一下 CubeMX 下互斥量的配置,在配置界面我們可用看到兩個互斥量配置界面,上面的是普通互斥量,其獲取只能獲取一次,重復獲取是無效的,而第二個則是遞回互斥量,遞回互斥信號量可以獲取多次,但對應的也要釋放多次才能讓出使用權,比如我獲取3次,任務要釋放3次才能釋放該互斥量的使用權

使用互斥量,需要點擊 Add 然后配置引數

引數介紹:

引數功能
Mutex Name互斥量名稱
Allocation記憶體分配方式,一般使用動態
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

遞回互斥信號量的配置方式與其相同,包括配置引數也相同,兩者只是在用法上有些許區別,添加方式如下:

添加配置完成后,點擊生成代碼,在 freertos.c 檔案中我們可以看到互斥量初始化完成,并且生成了對應的控制句柄

CubeMX 提供的 API 介面函式如下

函式功能
osMutexNew創建互斥量
*osMutexGetName獲取互斥量名稱
osMutexAcquire任務獲取互斥量
osMutexRelease任務釋放互斥量
osMutexGetOwner獲取互斥量的擁有任務的任務 TCB
osMutexDelete洗掉互斥量

主要使用到的還是互斥量的獲取與釋放,下面分析一下這兩個函式:

獲取互斥量 osMutexAcquire

函式原型

osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);

引數介紹:

引數功能
mutex_id互斥量控制句柄
timeout獲取互斥量時的等待時間(等待期間任務掛起在內核物件的掛起佇列)

使用方式

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	osStatus_t result;
    result= osMutexAcquire(&myMutex01Handle,10);
    if(result == osOK)
    {
        //獲取成功
    }else
    {
        //獲取失敗
    }
  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
  }
  /* USER CODE END StartTask02 */
}

釋放互斥量 osMutexRelease

函式原型

osStatus_t osMutexRelease (osMutexId_t mutex_id);

引數介紹:

引數功能
mutex_id互斥量控制句柄

使用方式

void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
	osStatus_t result;
    result= osMutexRelease(&myMutex01Handle);
    if(result == osOK)
    {
        //釋放成功
    }else
    {
        //釋放失敗
    }
  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
  }
  /* USER CODE END StartTask02 */
}

使用方式和信號量基本相同,因為互斥量本質上就是信號量的一種

七、創建事件標志組

7.1 CubeMX下事件的創建和配置

任務間的同步除了信號量還有時間標志組,信號的同步通常是一對一的同步,有的時候系統需要多對一的同步,比如同時滿足5個按鍵按下時,任務啟動,如果使用信號會很占據資源,所以 RTOS 引入了事件標志組來滿足這一需求,下面我們看一下 CubeMX 內事件標志組的配置方法:

點擊 Add 創建事件標志組

配置介紹

引數功能
Event flags Name事件標志組名稱
Allocation記憶體分配方式,一般使用動態
Static: 靜態方式是直接在RAM占據一個靜態空間
Dynamic:動態方則是在初始配置的記憶體池大小陣列中動態申請、釋放空間

配置完成后,生成代碼,在系統初始化內,看有沒有生成事件標志組控制句柄,可以看到句柄創建完成

CubeMX 提供的配置事件標志組的介面 API 如下:

函式功能
osEventFlagsNew創建事件標志組
*osEventFlagsGetName獲取事件標志組名稱
osEventFlagsSet設定事件標志組
osEventFlagsClear清除事件標志組
osEventFlagsGet獲取當前事件組標志資訊
osEventFlagsWait等待事件標志組觸發
osEventFlagsDelete洗掉事件標志組

常用的 API 介面是設定事件標志組以及等待事件標志組的觸發,下面我們分析一下這兩個 API

在了解 API 前我們需要簡單了解一下事件的觸發原理:首先事件標志組的資料型別為 EventGroupHandle_t,事件標志組中的所有事件位都存盤在一個無符號的 EventBits_t 型別的變數中,當 configUSE_16_BIT_TICKS 為 1 的時候事件標志組可以存盤 8 個事件位,當 configUSE_16_BIT_TICKS 為 0 的時候事件標志組存盤 24個事件位,每個事件位其實就是一個0或者1數字,就像下面的24位組成一個事件標志組

我們在使用事件API介面函式前需要先定義我們需要的觸發事件位,比如添加如下的代碼

#define event1 1<<1 	//事件1
#define event2 1<<2 	//事件2

撰寫好觸發事件后,我們在看如何使用 API 介面

設定事件標志 osEventFlagsSet

函式原型

uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags);

引數介紹:

引數功能
ef_id事件標志組控制句柄
flags事件位

使用方式:設定事件1和事件2

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osEventFlagsSet(&myEvent01Handle,event1);
		if(result == osOK)
		{
			//事件1設定成功
		}else
		{
			//事件1設定失敗
		}
		result = osEventFlagsSet(&myEvent01Handle,event2);
		if(result == osOK)
		{
			//事件2設定成功
		}else
		{
			//事件2設定失敗
		} 
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

等待事件標志 osEventFlagsWait

函式原型

uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);

引數介紹:

引數功能
ef_id事件標志組控制句柄
flags等待的事件位
options等待事件位的操作
osFlagsWaitAny :等待的事件位有任意一個等到就恢復任務
osFlagsWaitAll:等待的事件位全部等到才恢復任務
osFlagsNoClear:等待成功后不清楚所等待的標志位(默認清除)
timeout等待事件組的等待時間(等待期間任務掛起在內核物件的掛起佇列)

使用例子:同時等待事件1和事件2,且等待到不清除

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osEventFlagsWait(&myEvent01Handle,event1|event2,osFlagsWaitAll|osFlagsNoClear,10);
		if(result == osOK)
		{
			//等待成功
		}else
		{
			//等待失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

八、用戶常量

User Constants 用于添加用戶常量,將不變的量轉化為常量保存,可以節省 RAM 資源空間,因為常量和變數的保存位置不同,詳細了解可以參考這篇文章:C語言:記憶體四區

九、任務通知

FreeRTOS 的每個任務都有一個 32 位的通知值,任務控制塊中的成員變數 ulNotifiedValue 就是這個通知值,任務通知是一個事件,假如某個任務通知的接收任務因為等待任務通知而阻塞的話,向這個接收任務發送任務通知以后就會解除這個任務的阻塞狀態,CubeMX內沒有提供相關的配置項,但在其生成的 FreeRTOS 介面里面有相關函式進行配置,函式位置如下:

介面函式功能:

函式功能
osThreadFlagsSet設定任務的通知標志
osThreadFlagsClear清除任務通知
osThreadFlagsGet獲取任務標志
osThreadFlagsWait等待特定的任務標志

常用的兩個 API 就是設定任務通知和等待任務通知函式

設定通知 osThreadFlagsSet

函式原型

uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);

引數介紹:

引數功能
thread_id任務控制塊
flags設定的標志

使用方式

先定義一個事件標志

#define  event1 1<<1 	//事件1

然后呼叫 API 通知對應任務事件發生

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
  /* Infinite loop */
  for(;;)
  {
		
		result = osThreadFlagsSet(&myTask02Handle,event1);
		if(result == osOK)
		{
			//設定成功
		}else
		{
			//設定失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

等待通知 osThreadFlagsWait

函式原型

uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout);

引數介紹:

引數功能
flags設定的標志
options設定功能
timeout超時時間

options引數

引數功能
osFlagsWaitAny等待32位通知值任意一位觸發后恢復任務(默認)
osFlagsWaitAll等待指定的任務通知值全部觸發后再恢復任務
osFlagsNoClear恢復任務后不清除任務標志(默認清除)

使用方式

呼叫 API 等待對應的任務通知就緒,當其他任務設定到對應的通知后,任務恢復運行

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
	osStatus_t result;
  /* Infinite loop */
  for(;;)
  {
		
		result = osThreadFlagsWait(&myTask02Handle,osFlagsWaitAll,event1);
		if(result == osOK)
		{
			//等待成功
		}else
		{
			//等待失敗
		}
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

任務通知其實個任務事件標志組使用上沒有多大的區別,但他們兩個的實作原理不同,同時任務通知對資源的占用更少

根據 FreeRTOS 官方的統計,使用任務通知替代二值信號量的時候任務解除阻 塞的時間要快 45%,并且需要的 RAM 也更少

十、系統內核配置

CubeMX 生成的代碼中封裝了一系列內核配置函式,有些函式也經常使用到,比如獲取時間戳和調度器管理的函式,這里不做過多解釋,簡單的介紹一下函式的功能

函式功能
osKernelInitialize初始化RTOS的內核
osKernelGetInfo獲取RTOS的資訊
osKernelGetState獲取當前內核的運行狀態
osKernelStart啟動內核調度
osKernelLock鎖內核調度器
osKernelUnlock解鎖內核調度器
osKernelRestoreLock恢復RTOS內核調度器鎖狀態
osKernelSuspend掛起任務
osKernelResume恢復任務
osKernelGetTickCount用于獲取系統當前運行的時鐘節拍數
osKernelGetTickFreq用于獲取系統當前運行的時鐘節拍的分頻頻率
osKernelGetSysTimerCount獲取系統時鐘(SysTick)的計數值
osKernelGetSysTimerFreq獲取系統時鐘(SysTick)的頻率

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/330431.html

標籤:其他

上一篇:【入門嵌入式系統】基礎知識梳理總結

下一篇:unity3d 減少DC(DrawCalls)的方法之一光照貼圖

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more