這個是全網(wǎng)最詳細(xì)的STM32項目教學(xué)視頻。
第一篇在這里:
視頻在這里
V3:HAL庫開發(fā)、手把手教學(xué)下面功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、openmv視覺控制、電磁循跡、FreeRTOS、K210視覺智能車(更新中)、K230視覺智能車(更新中)、MSPM0G3507視覺智能車(更新中)
22.3-任務(wù)棧大小 和 系統(tǒng)可用堆
我們前面創(chuàng)建任務(wù)使用了任務(wù)棧的概念,那么我們新建任務(wù)的時候,設(shè)置多大的任務(wù)棧合適那?任務(wù)棧又是從哪里來的,那塊空間又如何獲得那?
實際開發(fā)中無法精準(zhǔn)計算任務(wù)需要的任務(wù)棧大小,如果任務(wù)中有較大數(shù)組或者變量,一定要設(shè)置的比變量更大,如果沒有則可以先按照默認(rèn)128字設(shè)置,然后任務(wù)編寫完成后加入uxTaskGetStackHighWaterMark 函數(shù)獲得任務(wù)堆棧的“高水位標(biāo)記”(剩余未使用的堆棧空間的最小值),還要加入xPortGetFreeHeapSize函數(shù)獲得當(dāng)前系統(tǒng)的可用堆內(nèi)存。
22.3.1-任務(wù)棧 和 系統(tǒng)可用堆 知識!!(重點掌握)
任務(wù)棧是 FreeRTOS 為每個任務(wù)分配的一塊獨立內(nèi)存,用于保存任務(wù)運行時的局部變量、函數(shù)調(diào)用上下文、中斷上下文等。將如下的幾個選項簡單的累加就可以得到一個粗略的棧大?。?/p>
1、函數(shù)
① 局部變量
② 函數(shù)形參 (針對函數(shù)嵌套)
③ 函數(shù)返回地址 (針對函數(shù)嵌套)
④ 函數(shù)內(nèi)部的狀態(tài)保存
2、任務(wù)切換
3、發(fā)生中斷
實際應(yīng)用中將這些都加起來是一件非常麻煩的工作,上面這些棧空間加起來的總和只是棧的最小需求,實際分配的棧大小可以在最小棧需求的基礎(chǔ)上乘以一個安全系數(shù),一般取 1.5-2。
上面的計算是我們用戶可以確定的棧大小,項目應(yīng)用中還存在無法確定的棧大小,比如調(diào)用printf函數(shù)就很難確定實際的棧消耗。又比如通過函數(shù)指針實現(xiàn)函數(shù)的間接調(diào)用,因為函數(shù)指針不是固定的指向一個函數(shù)進(jìn)行調(diào)用,而是根據(jù)不同的程序設(shè)計可以指向不同的函數(shù),使得棧大小的計算變得比較麻煩。
另外還要注意一點,建議不要編寫遞歸代碼(函數(shù)直接或間接地調(diào)用自身),因為我們不知道遞歸的層數(shù),棧的大小也是不好確定的。
通過函數(shù)獲得任務(wù) 高水位 線 uxTaskGetStackHighWaterMark 【這里展示使用這個】
通過函數(shù)uxTaskGetStackHighWaterMark 用于獲得一個任務(wù)的高水位值,其原型定義如下:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
如果要查詢?nèi)蝿?wù)自己的高水位值,將參數(shù)xTask設(shè)置NULL即可。
諾要使用這個函數(shù),必須將參數(shù)宏INCLUDE_uxTaskGetStackHighWaterMark 必須為 1可以在Cubemx里設(shè)置。高水位值實際就是任務(wù)的??臻g最小可用剩余空間的大小,單位是字(word),這個值越小,表示任務(wù)的棧空間越容易溢出。
比如一個任務(wù)中增加下面代碼,可以輸出當(dāng)前任務(wù)的棧高水位值
UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 獲取當(dāng)前任務(wù)的棧高水位值
printf("Stack High Water Mark: %u wordsn", (unsigned int)stackHighWaterMark);
通過函數(shù)分析任務(wù)資源vTaskGetRunTimeStats[這里不展開,后面單獨講解]
這個需要功能需要修改一個定時器,這里因為定時器都用完了所以暫時不演示這個功能,如果芯片定時器資源充足可以使用,但是項目開發(fā)完或者發(fā)布量產(chǎn)代碼要去掉這個相關(guān)功能。
vTaskGetRunTimeStats()
:適用于獲取任務(wù)的 CPU 占用時間 和 運行時間,對于性能調(diào)優(yōu)、任務(wù)優(yōu)化和分析系統(tǒng)資源消耗非常有幫助。
需要設(shè)置一個定時器,這個定時器的時間基準(zhǔn)精度要高于系統(tǒng)時鐘節(jié)拍,達(dá)到系統(tǒng)時鐘節(jié)拍的10-20倍,這樣測量的任務(wù)信息才能準(zhǔn)確。
此測試方法僅限用于調(diào)試,測試,實際發(fā)布項目代碼中不要使用,因為這種測試方式比較消耗資源,影響系統(tǒng)實時性。
FreeRTOS的系統(tǒng)內(nèi)核沒有對計數(shù)時間做出溢出保護(hù),比如定時器周期為50us,最大支持計數(shù)時間是2^32*50us/3600s=59.6分鐘,運行時間超過59.6分鐘就將不準(zhǔn)確了。
任務(wù)棧使用哪里的空間-如何查看當(dāng)前系統(tǒng)的可用堆內(nèi)存
(FreeRTOS堆中可用的RAM總量)定義freeRTOS系統(tǒng)堆大小。
configTOTAL_HEAP_SIZE
設(shè)置了 FreeRTOS從芯片的RAM分配的堆內(nèi)存的總大小,這個堆內(nèi)存用于FreeRTOS所有動態(tài)內(nèi)存分配,具體將用于FreeRTOS的任務(wù)棧的分配,隊列、信號量等資源,內(nèi)存池或動態(tài)內(nèi)存分配。
FreeRTOS 提供了 xPortGetFreeHeapSize()
函數(shù)來監(jiān)控當(dāng)前堆內(nèi)存的剩余空間。你可以在程序中定期調(diào)用該函數(shù),查看堆內(nèi)存的使用情況,以確保內(nèi)存不會耗盡。
size_t heapRemaining = xPortGetFreeHeapSize();
比如任務(wù)加入下面代碼
size_t freeHeapSize = xPortGetFreeHeapSize();// 獲取系統(tǒng)的可用堆空間
printf("Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);