建FreeRTOS工程和第一個多任務(wù)程序))
上節(jié)我們簡單了解了FreeRTOS相關(guān)理論現(xiàn)在我們開始正式的實操我們先介紹如何在CubeMX里面創(chuàng)建FreeRTOS工程1.、在 SYS 選項里將 Debug 設(shè)為 Serial Wire 并且將 Timebase Source 設(shè)為 TIM4 其它定時器也行。Timebase Source 為什么不能設(shè)置為 SysTick ? 裸機的時鐘源默認是 SysTick但是開啟 FreeRTOS 后FreeRTOS會占用 SysTick 用來生成1ms 定時用于任務(wù)調(diào)度所以需要為其他總線提供另外的時鐘源。2、將RCC里的HSE設(shè)置為Crystal/Ceramic Resonator 晶振源3.、選擇 FREERTOS 選項并將 Interface 改為 CMSIS_V2 。FreeRTOS 各配置選項卡的解釋Events事件相關(guān)的創(chuàng)建Task and Queues 任務(wù)與隊列的創(chuàng)建Timers and Semaphores 定時器和信號量的創(chuàng)建Mutexes 互斥量的創(chuàng)建FreeRTOS Heap Usage 用于查看堆使用情況Config parameters 內(nèi)核參數(shù)設(shè)置用戶根據(jù)自己的實際應(yīng)用來裁剪定制FreeRTOS 內(nèi)核Include parameters FreeRTOS 部分函數(shù)的使能User Constants 相關(guān)宏的定義可以自建一些常量在工程中使用Advanced settings高級設(shè)置接著我們就可以開始創(chuàng)建第一個多任務(wù)程序在上節(jié)我們了解到了任務(wù)其實就是在內(nèi)存里分配一塊堆然后在堆里面分配棧即創(chuàng)建任務(wù)任務(wù)通常都含有while1死循環(huán)在FreeRTOS里面任務(wù)的原型如下voidStartDefaultTask(void*argument){while1{//代碼邏輯}}下面示例如何創(chuàng)建任務(wù)voidMyTask(void*argument){while(1){Led_Test();}}xTaskCreate(MyTask,MyFirstTask,128,NULL,osPriorityNormal,NULL);上面的我們從理論那節(jié)都已經(jīng)有很清晰的了解了吧ARM架構(gòu)從上圖我們可以看到CPU在對內(nèi)存進行一些程序操作那那些操作的變量保存在CPU哪里呢我們深入CPU內(nèi)部看看可以看到CPU在對內(nèi)存進行讀寫操作時會涉及到四條匯編指令就是我們的程序這些匯編指令保存在Flash上CPU從Flash得到指令然后去對內(nèi)存執(zhí)行可以看到CPU上有16個寄存器這些寄存器就是暫時保留對內(nèi)存讀寫操作過程的值那這些寄存器只有暫存數(shù)據(jù)的作用嗎往下看可以看到R13保存棧地址,R14,R15寫入到要跳轉(zhuǎn)的地址跳轉(zhuǎn)后執(zhí)行程序還有其它的作用而R14我們之前介紹過匯編指令下面是通過程序來了解匯編指令在程序的運行機器碼就是就是對應(yīng)的匯編指令如下圖MOV 是指將右邊值賦給左邊注意這里PUSH是指將1rr1r0寄存器該棧的值內(nèi)存寫入到寄存器中CPU所以1r寄存器的值是返回地址。這里的LDRD是指從棧的sp開始的第4個字節(jié)和第8個字節(jié)的位置內(nèi)存值分別寫入到r0和r1寄存器中CPUFreeRTOS源碼可以看到我們選擇配置FreeRTOS并生成文件時會有上圖中關(guān)于FreeRTOS的源代碼這是入口函數(shù)其中MX_FREERTOS_Init函數(shù)里面就包含了我們在Task.c里面的任務(wù)函數(shù)數(shù)據(jù)類型內(nèi)存管理這是堆相關(guān)的配置第一個是選擇動態(tài)分配/靜態(tài)分配第二個是配置堆的大小第三個是選擇堆的配置文件這四種配置文件區(qū)別如下平時我們用到的配置文件都是4和5下面我來說說它們的區(qū)別如上圖文件1只從內(nèi)存中分配堆卻不能釋放也沒有相關(guān)的頭部來存儲堆的信息文件2能從內(nèi)存中分配堆和頭部不過假設(shè)這塊內(nèi)存已經(jīng)滿了而且我把buf1和buf2都釋放了然后我要重新分配一塊120字節(jié)大小的堆會發(fā)現(xiàn)分配不了因為buf為100字節(jié)大小buf為50字節(jié)大小所以這120字節(jié)大小都分配不進去所以這就是文件2的缺點不能解決碎片問題即不能將這兩塊堆合并文件4就是在文件二的基礎(chǔ)上解決了碎片問題文件5可以看到除了能在RAM剩余內(nèi)存中可以分配堆在EXT_RAM中也能分配堆所以文件5就能管理這兩塊堆通過鏈表空閑鏈表頭指向第一個堆再指向第二個堆我們需要告訴鏈表頭有多少塊離散的堆函數(shù)如下不過在程序中我們主要使用這兩個函數(shù)就行了//分配一塊內(nèi)存void*pvPortMaalloc(size_txWantedSize)//釋放一塊內(nèi)存voidvPortFree(void*pv)