FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现
发表于:2025-11-08 作者:千家信息网编辑
千家信息网最后更新 2025年11月08日,这篇文章主要介绍"FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"FreeRTOS实时操作系统空闲任务的阻
千家信息网最后更新 2025年11月08日FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现
这篇文章主要介绍"FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现"文章能帮助大家解决问题。
什么是阻塞延时、为什么需要空闲任务
RTOS中的延时叫阻塞延时,即任务需要延时时,任务会放弃cpu使用权,cpu转而去做其他的事,当任务延时时间到后,任务重新请求获得cpu使用权。
但当所有的任务都处于阻塞后,为了不让cpu空闲没事干就需要一个空闲任务让cpu干活。
空闲任务的实现
空闲任务实现和创建普通任务没区别,空闲任务在调用vTaskStartScheduler函数内部创建,如下
//定义空闲栈 #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; //空闲任务任务控制块 TCB_t IdleTaskTCB; //设置空闲任务的参数 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;//空闲任务控制块指针 StackType_t *pxIdleTaskStackBuffer = NULL;//空闲任务栈指针 uint32_t ulIdleTaskStackSize; //空闲任务栈大小 //设置空闲任务参数 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中的一个成员,用于记录还要阻塞多久。
typedef struct tskTaskControlBlock{ volatile StackType_t * pxTopOfStack; ListItem_t xStateListItem; StackType_t * pxStack; · char pcTaskName[configMAX_TASK_NAME_LEN]; TickType_t xTicksToDelay; //用于延时}tskTCB;所以阻塞延时就是这样实现
void vTaskDelay(const TickType_t xTicksToDelay){ TCB_t *pxTCB = NULL; pxTCB = pxCurrentTCB; //设置延时时间 pxTCB->xTicksToDelay = xTicksToDelay; //进行一次任务切换 taskYIELD();}由于引入了阻塞延时,所以任务切换函数需要改写,因为当所有任务阻塞后,需要切换至空闲任务运行
void vTaskSwitchContext( void ){ //如果当前时空闲任务,尝试去执行任务1或任务2,如果他们延时时间都没到则继续执行空闲任务 if( pxCurrentTCB == &IdleTaskTCB ) { if(Task1TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task1TCB; } else if(Task2TCB.xTicksToDelay == 0) { pxCurrentTCB =&Task2TCB; } else { return; } } else //当前任务不是空闲任务会执行到这里 { //当前任务时任务1或任务2的话,检查另一个任务 //如果另外的任务不在延时中,会切换到该任务 //否则,判断当前任务是否在延时中,是则切换到空闲任务, //否则,不进行任何切换 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中设置了xTicksToDelay成员后,是通过SystTick中断来实现递减操作的
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; ixTicksToDelay > 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时钟源选择#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 ){ //重装载计数器值 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中
#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个task是同步运行的,且延时是20ms

关于"FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。
任务
空闲
阻塞
切换
运行
操作系统
实时
系统
时钟
时间
知识
控制
使用权
函数
参数
定时器
寄存器
成员
指针
行业
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
信息网络安全技术
服务器管理有必要吗
软件开发属于计算机应用技术吗
无锡电子网络技术哪家好
如何使橘子服务器更稳定
美国颁布的首份有关网络安全
域名服务器上存放着
mdb数据库查询慢
ps老头环连接不上服务器
关于网络安全作文提纲
智能硬件java服务器
网络安全启动仪式心得体会
小鹏汽车服务器挖矿
git 排除数据库文件
计算机网络技术讲座主题
数据库scn
广东dns服务器设置云主机
网络安全教育研究对象
网络安全架构师年薪
双流网络安全宣传周2021
服务器有没有作用
江湖x服务器
软件开发招投标报价
金动力显示服务器错误
茂名网络安全
三列成绩数据库
qq服务器域名
海康 连接服务器失败
我的世界服务器管理机器人
ios软件开发工程师要求