
RTOS幾點(diǎn)思考為什么使用RTOS?1. 先考慮OS有什么特點(diǎn)2. 再考慮什么情況下使用OS?FreeRTOS調(diào)試技巧任務(wù)管理1. 任務(wù)調(diào)度流程2. 任務(wù)棧大小棧溢出檢測(cè)3. 中斷管理4. 內(nèi)存管理FreeRTOS API接口1. 任務(wù)創(chuàng)建為什么使用RTOS?1. 先考慮OS有什么特點(diǎn)無(wú)OS開發(fā)情況下就是一個(gè)while循環(huán)中執(zhí)行所有模塊功能順序執(zhí)行模塊依次執(zhí)行不能調(diào)換順序更不能同步實(shí)時(shí)執(zhí)行voidmain(){BSP_Init();//硬件初始化while(1){task1();//模塊1執(zhí)行.......task4();//模塊4執(zhí)行}}狀態(tài)調(diào)度模塊根據(jù)狀態(tài)變化執(zhí)行可以調(diào)換順序不能同步實(shí)時(shí)執(zhí)行unsignedintswitchflag;voidmain(){BSP_Init();//硬件初始化while(1){switch(switchflag){casestatus1:task1();//模塊1執(zhí)行break;casestatus2:task2();//模塊2執(zhí)行break;.......}}}上面的任務(wù)都需要執(zhí)行完才能跳轉(zhuǎn)到其它任務(wù)不能在任務(wù)運(yùn)行期間跳轉(zhuǎn)。也有一種情況是任務(wù)自己提前break但是你能讓自己break你不能讓別人break啊所以我們需要一個(gè)東西管理任務(wù)切換執(zhí)行這個(gè)就是OS了。基于這個(gè)最初的需求可以看一下現(xiàn)在的OS實(shí)現(xiàn)了什么功能支持搶占切換/合作切換/時(shí)間片切換任務(wù)支持低功耗模式支持多種系統(tǒng)架構(gòu)支持任務(wù)同步機(jī)制支持堆棧溢出檢測(cè)工具免費(fèi)源碼免費(fèi)版權(quán)免費(fèi)2. 再考慮什么情況下使用OS?1.項(xiàng)目功能單一程序簡(jiǎn)單各模塊沒有強(qiáng)烈同步執(zhí)行的需求實(shí)時(shí)性需求不強(qiáng)不需要OS2.項(xiàng)目功能復(fù)雜模塊交織多個(gè)模塊有強(qiáng)烈同步執(zhí)行的需求實(shí)時(shí)性需求強(qiáng)需要OS根據(jù)項(xiàng)目考量沒有明確界限FreeRTOS調(diào)試技巧重定向printf/scanf函數(shù)進(jìn)行串口打印/*重定向printf函數(shù)*/intfputc(intdata,FILE*file){USART_SendData(USARTx,(char)data);//發(fā)送一個(gè)字節(jié)while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)RESET);//等待發(fā)送成功returndata;}/*重定向scanf函數(shù)*/intfgetc(FILE*file){chardata;while(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)RESET);//等待接收成功dataUSART_ReceiveData(USARTx);//接收一個(gè)字節(jié)return(int)data;}調(diào)試任務(wù)運(yùn)行狀態(tài)任務(wù)棧余量CPU占用率實(shí)現(xiàn)計(jì)數(shù)器volatileuint32_tOS_DebugTimeTicks0;//調(diào)試心跳voidBSP_Timex(){//實(shí)現(xiàn)20KHz頻率的定時(shí)器//開定時(shí)器中斷//OS_DebugTimeTicks在中斷中自增}FreeRTOSConfig.h文件宏配置externuint32_tOS_DebugTimeTicks;#defineconfigUSE_TRACE_FACILITY1#defineconfigGENERATE_RUN_TIME_STATS1#defineconfigUSE_STATS_FORMATTING_FUNCTIONS1#defineportCONFIGURE_TIMER_FOR_RUN_TIME_STATS()(OS_DebugTimeTicks0UL)#defineportGET_RUN_TIME_COUNTER_VALUE()OS_DebugTimeTicks調(diào)用RTOS調(diào)試函數(shù)vTaskList()vTaskGetRunTimeStats()輸出任務(wù)信息staticvoidvTaskTaskUserIF(void*pvParameters){uint8_tucKeyCode;uint8_tDebugInfoBuff[500];while(1){printf(\r\n);printf(任務(wù)名 任務(wù)狀態(tài) 優(yōu)先級(jí) 剩余棧 任務(wù)序號(hào)\r\n);vTaskList((char*)DebugInfoBuff);printf(%s\r\n,DebugInfoBuff);printf(\r\n任務(wù)名 運(yùn)行計(jì)數(shù) 使用率\r\n);vTaskGetRunTimeStats((char*)DebugInfoBuff);printf(%s\r\n,DebugInfoBuff);vTaskDelay(20);}}任務(wù)管理1. 任務(wù)調(diào)度流程2. 任務(wù)棧大小棧溢出檢測(cè)棧大小最小??臻g棧內(nèi)容函數(shù)每層函數(shù)局部變量形參返回地址狀態(tài)保存任務(wù)切換部分CPU寄存器 FPU寄存器中斷部分CPU寄存器 FPU寄存器可變參函數(shù)函數(shù)指針遞歸無(wú)法確定棧大小標(biāo)準(zhǔn)??臻g最小棧大小的1.5~2倍大小函數(shù)棧大小及嵌套深度可以參考工程編譯文件.htm文件RTOS調(diào)試技巧測(cè)試??臻g適當(dāng)調(diào)整棧溢出檢測(cè)棧生長(zhǎng)地址由高到低如果棧指針下移的地址越過(guò)了任務(wù)棧的基地址則棧溢出。軟件預(yù)設(shè)檢測(cè)在棧生長(zhǎng)方向的末端開辟一段空間專門存放固定值定時(shí)判斷固定值有沒有被修改被修改說(shuō)明棧溢出了。存在棧溢出超過(guò)判斷區(qū)間直接宕機(jī)的可能。MPU內(nèi)存保護(hù)通過(guò)MPU對(duì)棧生長(zhǎng)方向的末端區(qū)間進(jìn)行保護(hù)如果出現(xiàn)棧溢出觸發(fā)MPU異常在異常中分析棧溢出情況。FreeRTOS棧溢出檢測(cè)方法1任務(wù)切換時(shí)檢測(cè)棧指針是否越界棧溢出觸發(fā)溢出回調(diào)函數(shù)vApplicationStackOverflowHook#defineconfigCHECK_FOR_STACK_OVERFLOW1voidvApplicationStackOverflowHook(TaskHandle_t xTask,signedchar*pcTaskName);//溢出回調(diào)函數(shù)方法2 任務(wù)棧初始化為固定值任務(wù)切換時(shí)檢測(cè)棧尾16個(gè)字節(jié)是否都是初始化設(shè)置的固定值。#defineconfigCHECK_FOR_STACK_OVERFLOW2voidvApplicationStackOverflowHook(TaskHandle_t xTask,signedchar*pcTaskName);//溢出回調(diào)函數(shù)任務(wù)切換時(shí)進(jìn)行棧溢出檢測(cè)無(wú)法確保任務(wù)運(yùn)行期間棧不溢出。任務(wù)切換時(shí)進(jìn)行棧溢出檢測(cè)無(wú)問(wèn)題只能說(shuō)明棧尾的數(shù)據(jù)是固定值但是不能說(shuō)明是初始時(shí)設(shè)置的固定值還是運(yùn)行時(shí)保存的固定值存在第2種情況的可能性。3. 中斷管理M3/M4內(nèi)核MCU中斷優(yōu)先級(jí)取寄存器8位中的高4位表示共有16種組合。幾點(diǎn)原則RTOS采用中斷分組4也就是0~15級(jí)全搶占式優(yōu)先級(jí)高搶占級(jí)中斷可以搶占低搶占級(jí)中斷同搶占級(jí)中斷不能互相搶占先到先行ResetNMI不可屏蔽中斷Hard Fault高于普通中斷優(yōu)先級(jí)固定RTOS中斷配置Systick中斷產(chǎn)生心跳觸發(fā)PendSV中斷PendSV中斷任務(wù)切換SVC中斷啟動(dòng)任務(wù)只執(zhí)行一次#defineconfigPRIO_BITS4//優(yōu)先級(jí)占用bits#defineconfigLIBRARY_LOWEST_INTERRUPT_PRIORITY15//RTOS用的Systick和PendSV中斷優(yōu)先級(jí)#defineconfigKERNEL_INTERRUPT_PRIORITY(configLIBRARY_LOWEST_INTERRUPT_PRIORITY(8-configPRIO_BITS))//Systick和PendSV中斷配置的優(yōu)先級(jí)左移4位寫進(jìn)優(yōu)先級(jí)配置寄存器#defineconfigLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY2//可以使用RTOS函數(shù)的最高優(yōu)先級(jí)2~15優(yōu)先級(jí)中斷中可用RTOS接口#defineconfigMAX_SYSCALL_INTERRUPT_PRIORITY(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(8-configPRIO_BITS))//可以使用RTOS函數(shù)的最高優(yōu)先級(jí)左移4位寫進(jìn)優(yōu)先級(jí)配置寄存器RTOS管理的中斷會(huì)出現(xiàn)中斷延遲的可能對(duì)于實(shí)時(shí)性要求強(qiáng)的中斷不能被RTOS管理否則會(huì)出現(xiàn)中斷無(wú)法及時(shí)響應(yīng)的情況。FreeRTOS使用basepri寄存器uCOS使用primask寄存器。寄存器功能primask這是個(gè)只有 1 個(gè) bit 的寄存器。 在它被置 1 后就關(guān)掉所有可屏蔽的異常只剩下NMI 和硬 fault 可以響應(yīng)。它的缺省值是 0表示沒有關(guān)中斷faultmask這是個(gè)只有 1 個(gè) bit 的寄存器。當(dāng)它置 1 時(shí)只有 NMI 才能響應(yīng)所有其它的異常甚至是硬 fault也通通閉嘴。它的缺省值也是 0表示沒有關(guān)異常basepri這個(gè)寄存器最多有 9 位由表達(dá)優(yōu)先級(jí)的位數(shù)決定。它定義了被屏蔽優(yōu)先級(jí)的閾值。當(dāng)它被設(shè)成某個(gè)值后所有優(yōu)先級(jí)號(hào)大于等于此值的中斷都被關(guān)優(yōu)先級(jí)號(hào)越大優(yōu)先級(jí)越低。但若被設(shè)成 0則不關(guān)閉任何中斷 0 也是缺省值4. 內(nèi)存管理FreeRTOS提供5種內(nèi)存管理接口FreeRTOS API接口1. 任務(wù)創(chuàng)建函數(shù)描述xTaskCreate( )動(dòng)態(tài)創(chuàng)建一個(gè)任務(wù)從RTOS的堆上分配??臻gxTaskCreateStatic( )靜態(tài)創(chuàng)建一個(gè)任務(wù)用戶手動(dòng)分配??臻gxTaskCreateRestricted( )任務(wù)控制塊從RTOS堆上分配用戶手動(dòng)分配??臻g (和FreeRTOS-MPU一起使用)xTaskCreateRestrictedStatic( )用戶手動(dòng)分配任務(wù)控制塊和??臻g (和FreeRTOS-MPU一起使用)