FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现
发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,这篇文章主要介绍"FreeRTOS实时操作系统空闲任务的阻塞延时怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"FreeRTOS实时操作系统空闲任务的阻
千家信息网最后更新 2025年01月18日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安全错误
数据库的锁怎样保障安全
穿越火线各大外国服务器
中国货车数据库数据下载
平顶山erp软件开发
网络和网络技术
数据库可以装几个版本吗
地下城堡2更新服务器出错
frp服务器连接
广汇网络安全吗
黑龙江数据库安全审计
游戏软件开发报价
各地地磁数据库
网络技术的国外研究现状
免费专业资源数据库有哪些
商丘k3金蝶软件开发
成都 服务器
深圳卓越软件开发公司
游戏服务器日志打不开
合肥企业管理软件开发
篮球数据库
乐高无限怎么转服务器
昆明软件开发基地
威海浩维网络技术有限公司
数据库聚合有关的安全问题
固原分销系统软件开发
提高服务器伸缩性
关于网络安全重要论述摘编
各种网络安全防护知识
冒险岛2015数据库
长沙蔬菜配送软件开发
选定数据库的命令