FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
什么是阻塞延時(shí)、為什么需要空閑任務(wù)
RTOS中的延時(shí)叫阻塞延時(shí),即任務(wù)需要延時(shí)時(shí),任務(wù)會放棄cpu使用權(quán),cpu轉(zhuǎn)而去做其他的事,當(dāng)任務(wù)延時(shí)時(shí)間到后,任務(wù)重新請求獲得cpu使用權(quán)。
但當(dāng)所有的任務(wù)都處于阻塞后,為了不讓cpu空閑沒事干就需要一個(gè)空閑任務(wù)讓cpu干活。
空閑任務(wù)的實(shí)現(xiàn)
空閑任務(wù)實(shí)現(xiàn)和創(chuàng)建普通任務(wù)沒區(qū)別,空閑任務(wù)在調(diào)用vTaskStartScheduler
函數(shù)內(nèi)部創(chuàng)建,如下
//定義空閑棧 #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; //空閑任務(wù)任務(wù)控制塊 TCB_t IdleTaskTCB; //設(shè)置空閑任務(wù)的參數(shù) void vApplicationGetIdleTaskMemory( TCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer=&IdleTaskTCB; *ppxIdleTaskStackBuffer=IdleTaskStack; *pulIdleTaskStackSize=configMINIMAL_STACK_SIZE; } void vTaskStartScheduler(void) { TCB_t *pxIdleTaskTCBBuffer = NULL;//空閑任務(wù)控制塊指針 StackType_t *pxIdleTaskStackBuffer = NULL;//空閑任務(wù)棧指針 uint32_t ulIdleTaskStackSize; //空閑任務(wù)棧大小 //設(shè)置空閑任務(wù)參數(shù) vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize); //創(chuàng)建空閑任務(wù) xIdleTaskHandle = xTaskCreateStatic((TaskFunction_t)prvIdleTask, (char *)"IDLE", (uint32_t)ulIdleTaskStackSize, (void*)NULL, (StackType_t*)pxIdleTaskStackBuffer, (TCB_t*)pxIdleTaskTCBBuffer); //將空閑任務(wù)添加到就緒列表 vListInsertEnd(&(pxReadyTasksLists[0]),&(((TCB_t *)pxIdleTaskTCBBuffer)->xStateListItem)); //手動(dòng)指定第一個(gè)要運(yùn)行的任務(wù) pxCurrentTCB = &Task1TCB; //啟動(dòng)調(diào)度器 if(xPortStartScheduler()!=pdFALSE) { //啟動(dòng)成功則不會運(yùn)行到這里 } }
阻塞延時(shí)的實(shí)現(xiàn)
阻塞延時(shí)需要用xTicksToDelay
,這個(gè)時(shí)TCB中的一個(gè)成員,用于記錄還要阻塞多久。
typedef struct tskTaskControlBlock { volatile StackType_t * pxTopOfStack; ListItem_t xStateListItem; StackType_t * pxStack; · char pcTaskName[configMAX_TASK_NAME_LEN]; TickType_t xTicksToDelay; //用于延時(shí) }tskTCB;
所以阻塞延時(shí)就是這樣實(shí)現(xiàn)
void vTaskDelay(const TickType_t xTicksToDelay) { TCB_t *pxTCB = NULL; pxTCB = pxCurrentTCB; //設(shè)置延時(shí)時(shí)間 pxTCB->xTicksToDelay = xTicksToDelay; //進(jìn)行一次任務(wù)切換 taskYIELD(); }
由于引入了阻塞延時(shí),所以任務(wù)切換函數(shù)需要改寫,因?yàn)楫?dāng)所有任務(wù)阻塞后,需要切換至空閑任務(wù)運(yùn)行
void vTaskSwitchContext( void ) { //如果當(dāng)前時(shí)空閑任務(wù),嘗試去執(zhí)行任務(wù)1或任務(wù)2,如果他們延時(shí)時(shí)間都沒到則繼續(xù)執(zhí)行空閑任務(wù) if( pxCurrentTCB == &IdleTaskTCB ) { if(Task1TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task1TCB; } else if(Task2TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task2TCB; } else { return; } } else //當(dāng)前任務(wù)不是空閑任務(wù)會執(zhí)行到這里 { //當(dāng)前任務(wù)時(shí)任務(wù)1或任務(wù)2的話,檢查另一個(gè)任務(wù) //如果另外的任務(wù)不在延時(shí)中,會切換到該任務(wù) //否則,判斷當(dāng)前任務(wù)是否在延時(shí)中,是則切換到空閑任務(wù), //否則,不進(jìn)行任何切換 if (pxCurrentTCB == &Task1TCB) { if (Task2TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task2TCB; } else if (pxCurrentTCB->xTicksToDelay != 0) { pxCurrentTCB = &IdleTaskTCB; } else { return; } } else if (pxCurrentTCB == &Task2TCB) { if (Task1TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task1TCB; } else if (pxCurrentTCB->xTicksToDelay != 0) { pxCurrentTCB = &IdleTaskTCB; } else { return; } } } }
xTicksToDelay 遞減
vTaskDelay中設(shè)置了xTicksToDelay成員后,是通過SystTick中斷來實(shí)現(xiàn)遞減操作的
void xPortSysTickHandler( void ) { int x = portSET_INTERRUPT_MASK_FROM_ISR(); xTaskIncrementTick(); portCLEAR_INTERRUPT_MASK_FROM_ISR(x); } void xTaskIncrementTick( void ) { TCB_t *pxTCB = NULL; BaseType_t i = 0; const TickType_t xConstTickCount = xTickCount + 1; xTickCount = xConstTickCount; for (i=0; i<configMAX_PRIORITIES; i++) { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &pxReadyTasksLists[i] ) ); if (pxTCB->xTicksToDelay > 0) { pxTCB->xTicksToDelay --; //這里遞減 } } portYIELD(); }
SysTick初始化
//systick控制寄存器 #define portNVIC_SYSTICK_CTRL_REG (*((volatile uint32_t *) 0xe000e010 )) //systick重裝載寄存器 #define portNVIC_SYSTICK_LOAD_REG (*((volatile uint32_t *) 0xe000e014 )) //systick時(shí)鐘源選擇 #ifndef configSYSTICK_CLOCK_HZ #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #else #define portNVIC_SYSTICK_CLK_BIT ( 0 ) #endif #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) void vPortSetupTimerInterrupt( void ) { //重裝載計(jì)數(shù)器值 portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; //設(shè)置systick時(shí)鐘使用內(nèi)核時(shí)鐘 //使能systick定時(shí)器中斷 //使能systick定時(shí)器 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); }
在FreeRTOSConfig.h
中
#define configCPU_CLOCK_HZ (( unsigned long ) 25000000) #define configTICK_RATE_HZ (( TickType_t ) 100)
configSYSTICK_CLOCK_HZ是沒有定義的,所以configSYSTICK_CLOCK_HZ使用的是configCPU_CLOCK_HZ
仿真
portCHAR flag1; portCHAR flag2; TaskHandle_t Task1_Handle; StackType_t Task1Stack[128]; TCB_t Task1TCB; TaskHandle_t Task2_Handle; StackType_t Task2Stack[128]; TCB_t Task2TCB; void Task1_Fntry(void *arg) { while(1) { flag1=1; vTaskDelay( 2 ); flag1=0; vTaskDelay( 2 ); } } void Task2_Fntry(void *arg) { while(1) { flag2=1; vTaskDelay( 2 ); flag2=0; vTaskDelay( 2 ); } } int main(void) { prvInitialiseTaskLists(); Task1_Handle = xTaskCreateStatic(Task1_Fntry,"task1",128,NULL,Task1Stack,&Task1TCB); vListInsertEnd(&pxReadyTasksLists[1],&((&Task1TCB)->xStateListItem)); Task2_Handle = xTaskCreateStatic(Task2_Fntry,"task2",128,NULL,Task2Stack,&Task2TCB); vListInsertEnd(&pxReadyTasksLists[2],&((&Task2TCB)->xStateListItem)); vTaskStartScheduler(); for(;;) {} }
可以看到2個(gè)task是同步運(yùn)行的,且延時(shí)是20ms
以上就是FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS空閑任務(wù)阻塞延時(shí)的資料請關(guān)注腳本之家其它相關(guān)文章!
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建與任務(wù)切換
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建和刪除
- FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
- FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)應(yīng)用函數(shù)詳解
- FreeRTOS任務(wù)控制API函數(shù)的功能分析
- FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_5示例
這篇文章主要為大家介紹了FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_5示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場合示例
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場合示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理基礎(chǔ)知識
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理的基礎(chǔ)知識,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系列之任務(wù)通知的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04freertos實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)開關(guān)中斷及進(jìn)入退出
這篇文章主要介紹了freertos實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)開關(guān)中斷及進(jìn)入退出,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南
這篇文章主要為大家介紹了FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)判斷
這篇文章主要為大家介紹了FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)的判斷,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04