FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现(FreeRTOS,开发技术)

时间:2024-05-09 05:21:43 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

什么是阻塞延时、为什么需要空闲任务

RTOS中的延时叫阻塞延时,即任务需要延时时,任务会放弃cpu使用权,cpu转而去做其他的事,当任务延时时间到后,任务重新请求获得cpu使用权。
但当所有的任务都处于阻塞后,为了不让cpu空闲没事干就需要一个空闲任务让cpu干活。

空闲任务的实现

空闲任务实现和创建普通任务没区别,空闲任务在调用vTaskStartScheduler函数内部创建,如下

//定义空闲栈#defineconfigMINIMAL_STACK_SIZE((unsignedshort)128)StackType_tIdleTaskStack[configMINIMAL_STACK_SIZE];//空闲任务任务控制块TCB_tIdleTaskTCB;//设置空闲任务的参数voidvApplicationGetIdleTaskMemory(TCB_t**ppxIdleTaskTCBBuffer,StackType_t**ppxIdleTaskStackBuffer,uint32_t*pulIdleTaskStackSize){*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;}voidvTaskStartScheduler(void){ TCB_t*pxIdleTaskTCBBuffer=NULL;//空闲任务控制块指针 StackType_t*pxIdleTaskStackBuffer=NULL;//空闲任务栈指针 uint32_tulIdleTaskStackSize; //空闲任务栈大小 //设置空闲任务参数 vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize); //创建空闲任务 xIdleTaskHandle=xTaskCreateStatic((TaskFunction_t)prvIdleTask, (char*)"IDLE", (uint32_t)ulIdleTaskStackSize, (void*)NULL, (StackType_t*)pxIdleTaskStackBuffer,(TCB_t*)pxIdleTaskTCBBuffer);//将空闲任务添加到就绪列表vListInsertEnd(&(pxReadyTasksLists[0]),&(((TCB_t*)pxIdleTaskTCBBuffer)->xStateListItem)); //手动指定第一个要运行的任务 pxCurrentTCB=&Task1TCB; //启动调度器 if(xPortStartScheduler()!=pdFALSE) { //启动成功则不会运行到这里 }}

阻塞延时的实现

阻塞延时需要用xTicksToDelay,这个时TCB中的一个成员,用于记录还要阻塞多久。

typedefstructtskTaskControlBlock{ volatileStackType_t*pxTopOfStack; ListItem_txStateListItem; StackType_t*pxStack;· charpcTaskName[configMAX_TASK_NAME_LEN]; TickType_txTicksToDelay;//用于延时}tskTCB;

所以阻塞延时就是这样实现

voidvTaskDelay(constTickType_txTicksToDelay){ TCB_t*pxTCB=NULL; pxTCB=pxCurrentTCB; //设置延时时间 pxTCB->xTicksToDelay=xTicksToDelay; //进行一次任务切换 taskYIELD();}

由于引入了阻塞延时,所以任务切换函数需要改写,因为当所有任务阻塞后,需要切换至空闲任务运行

voidvTaskSwitchContext(void){//如果当前时空闲任务,尝试去执行任务1或任务2,如果他们延时时间都没到则继续执行空闲任务 if(pxCurrentTCB==&IdleTaskTCB) { if(Task1TCB.xTicksToDelay==0) { pxCurrentTCB=&Task1TCB; }elseif(Task2TCB.xTicksToDelay==0) { pxCurrentTCB=&Task2TCB; }else{return;}}else//当前任务不是空闲任务会执行到这里{//当前任务时任务1或任务2的话,检查另一个任务//如果另外的任务不在延时中,会切换到该任务//否则,判断当前任务是否在延时中,是则切换到空闲任务,//否则,不进行任何切换 if(pxCurrentTCB==&Task1TCB) { if(Task2TCB.xTicksToDelay==0) { pxCurrentTCB=&Task2TCB; } elseif(pxCurrentTCB->xTicksToDelay!=0) { pxCurrentTCB=&IdleTaskTCB; } else { return; } } elseif(pxCurrentTCB==&Task2TCB) { if(Task1TCB.xTicksToDelay==0) { pxCurrentTCB=&Task1TCB; } elseif(pxCurrentTCB->xTicksToDelay!=0) { pxCurrentTCB=&IdleTaskTCB; } else { return; } }}}

xTicksToDelay 递减

vTaskDelay中设置了xTicksToDelay成员后,是通过SystTick中断来实现递减操作的

voidxPortSysTickHandler(void){intx=portSET_INTERRUPT_MASK_FROM_ISR();xTaskIncrementTick();portCLEAR_INTERRUPT_MASK_FROM_ISR(x);}voidxTaskIncrementTick(void){ TCB_t*pxTCB=NULL; BaseType_ti=0; constTickType_txConstTickCount=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控制寄存器#defineportNVIC_SYSTICK_CTRL_REG(*((volatileuint32_t*)0xe000e010))//systick重装载寄存器#defineportNVIC_SYSTICK_LOAD_REG(*((volatileuint32_t*)0xe000e014))//systick时钟源选择#ifndefconfigSYSTICK_CLOCK_HZ #defineconfigSYSTICK_CLOCK_HZconfigCPU_CLOCK_HZ#defineportNVIC_SYSTICK_CLK_BIT(1UL<<2UL)#else#defineportNVIC_SYSTICK_CLK_BIT(0)#endif#defineportNVIC_SYSTICK_INT_BIT(1UL<<1UL)#defineportNVIC_SYSTICK_ENABLE_BIT(1UL<<0UL)voidvPortSetupTimerInterrupt(void){//重装载计数器值 portNVIC_SYSTICK_LOAD_REG=(configSYSTICK_CLOCK_HZ/configTICK_RATE_HZ)-1UL;//设置systick时钟使用内核时钟//使能systick定时器中断//使能systick定时器 portNVIC_SYSTICK_CTRL_REG=(portNVIC_SYSTICK_CLK_BIT| portNVIC_SYSTICK_INT_BIT| portNVIC_SYSTICK_ENABLE_BIT);}

FreeRTOSConfig.h

#defineconfigCPU_CLOCK_HZ((unsignedlong)25000000)#defineconfigTICK_RATE_HZ((TickType_t)100)

configSYSTICK_CLOCK_HZ是没有定义的,所以configSYSTICK_CLOCK_HZ使用的是configCPU_CLOCK_HZ

仿真

portCHARflag1;portCHARflag2;TaskHandle_tTask1_Handle;StackType_tTask1Stack[128];TCB_tTask1TCB;TaskHandle_tTask2_Handle;StackType_tTask2Stack[128];TCB_tTask2TCB;voidTask1_Fntry(void*arg){ while(1) { flag1=1; vTaskDelay(2); flag1=0; vTaskDelay(2); }}voidTask2_Fntry(void*arg){ while(1) { flag2=1; vTaskDelay(2); flag2=0; vTaskDelay(2); }} intmain(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个task是同步运行的,且延时是20ms

FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:vue+F2怎么生成折线图下一篇:

5 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18