FreeRTOS的任务理论

news2024/10/6 12:30:53

文章目录

  • 2 FreeRTOS的任务理论
    • 2.1 任务及任务优先级
    • 2.2 任务状态理论
      • 2.2.1 任务状态的转换
      • 2.2.2 任务状态改变相关函数
      • 2.2.3 调度器相关函数
    • 2.3 FreeRTOS延时
      • 2.3.1 vTaskDelay延时
      • 2.3.2 vTaskDelayUntil延时
      • 2.3.3 pdMS_TO_TICKS(x)宏
    • 2.4 TCB任务控制块
    • 2.5 任务调度宏与任务调度算法

2 FreeRTOS的任务理论

2.1 任务及任务优先级

​ 简单来说,任务是指可独立运行的基本执行单元。任务是并发执行的最小单位,每个任务都有自己的代码逻辑和资源。FreeRTOS多任务执行其实是多任务交替执行实现的。实现多任务交替执行的基础是tick中断,滴答中断,周期性的定时器中断。类比Linux,我们可以类比的认为一个任务相当于一个线程,同时,任务也有不同的种类和实现方式,比如说定时器任务等等。

​ 在FreeRTOS中,任务具有不同的优先级,不过FreeRTOS中,优先级是与大多数操作系统相反的,其值越小,优先级越低,**反之越大,优先级越高。**和CubeMX中的配置也是相反的。关于优先级我们需要注意以下几点:

  • 优先级相同时,任务是可以交替进行的,但是需要同优先级正在运行的任务释放自己的资源,例如使用vTaskDelete(NULL)退出,taskYIELD()释放等。或使用vTaskDelay()等函数暂时的释放了CPU资源时,才会轮到另一个任务执行;
  • 优先级不同时,高优先级的任务先执行,执行结束后才轮到低优先级的任务。这里需要注意的是,高优先级的任务中如果也有vTaskDelete(NULL),或vTaskDelay()等暂时的释放CPU资源的函数存在,这时候调度器会自动执行低优先级的的任务。而不是等着高优先级的delay延迟结束。
  • 任务的优先级不可以无限制的高,在FreeRTOSConfig.h中有一个宏configMAX_PRIORITIES规定了能到达的最高的优先级,其优先级的取值范围是( 0 ~ configMAX_PRIORITIES-1 )。 ps:注意是最大值是 configMAX_PRIORITIES-1而不是 configMAX_PRIORITIES-1
  • 这里我要再次强调,任务的优先级不是中断的优先级,任务也不是中断,任务优先级的高低仅仅决定了在就绪态的队伍中的排队次序,若低优先级的任务一直不释放CPU资源,那么再高的优先级也无法执行!!!
/*
  @brief  设置任务的优先级
  @retval None
  @param  pxTask:要修改优先级的任务句柄,通过NULL改变任务自身优先级
          uxNewPriority:要修改的任务优先级 
*/
void vTaskPrioritySet(TaskHandle_t pxTask, UBaseType_t uxNewPriority);
 
/*
  @brief  获取任务优先级
  @retval 任务优先级
  @param  pxTask:要获取任务优先级的句柄,通过NULL获取任务自身优先级
*/
UBaseType_t uxTaskPriorityGet(TaskHandle_t pxTask);

2.2 任务状态理论

2.2.1 任务状态的转换

在通用操作系统中有5态(或3态),而在FreeRTOS中稍有不同,他拥有4个状态。同时要注意,FreeRTOS中的任务函数,是一个永远不会退出的C函数,是无法使用return来退出的,要彻底清除他我们必须使用vTaskDelete(NULL)删除它。

  1. (RUNNING)运行态:正在运行的任务,只能有一个。
  2. (Ready)就绪态:条件Event都满足了,只等待正在运行的任务释放CPU后就轮到他来执行了。
  3. (Block)阻塞态:相当于等待态,在等待IO或者条件。
  4. (Suspended)挂起态:将运行到一半的程序挂起(主动暂停),暂时脱离调度器的调度,但是不可以直接回到运行态,只能回到就绪态。

他们的转换关系如下:

在这里插入图片描述

2.2.2 任务状态改变相关函数

/*
  @brief  查询一个任务当前处于什么状态
  @retval 任务状态的枚举类型
  @param  pxTask:要查询任务状态的任务句柄,NULL查询自己
*/
eTaskState eTaskGetState(TaskHandle_t pxTask);
 
/*任务状态枚举类型返回值*/
typedef enum
{
	eRunning = 0,		/* 任务正在查询自身的状态,因此肯定是运行状态 */
	eReady,				  /* 就绪状态 */
	eBlocked,		 		/* 阻塞状态 */
	eSuspended,			/* 挂起状态 */
	eDeleted,				/* 正在查询的任务已被删除,但其 TCB 尚未释放 */
	eInvalid				/* 无效状态 */
} eTaskState;
  1. (RUNNING)运行态:

    没有主动使得任务进入运行态的函数,同时要注意,单核处理器,那么同一时间只可能有一个任务再执行
    
  2. (Ready)就绪态:

  3. (Block)阻塞态:

    //vTaskDelay()和vTaskDelayUntil()这两个函数,都会使得任务进入阻塞状态。
      
    //当一个任务因为延时函数或者其他同步事件进入阻塞状态后,可以通过 xTaskAbortDelay() API 函数终止任务的阻塞状态,即使事件任务等待尚未发生,或者任务进入时指定的超时时间阻塞状态尚未过去,都会使其进入就绪状态,具体函数描述如下所述
    /*
      @brief  终止任务延时,退出阻塞状态
      @retval pdPASS:任务成功从阻塞状态中删除,pdFALSE:任务不属于阻塞状态导致删除失败
      @param  xTask:操作的任务句柄
    */
    BaseType_t xTaskAbortDelay(TaskHandle_t xTask);
    
  4. (Suspended)挂起态:

    /*
      @brief  将某个任务挂起
      @retval None
      @param  pxTaskToSuspend:被挂起的任务的句柄,通过传入NULL来挂起自身
    */
    void vTaskSuspend(TaskHandle_t pxTaskToSuspend);
     
    /*
      @brief  将某个任务从挂起状态恢复
      @retval None
      @param  pxTaskToResume:正在恢复的任务的句柄
    */
    void vTaskResume(TaskHandle_t pxTaskToResume);
     
    /*
      @brief  vTaskResume的中断安全版本
      @retval 返回退出中断之前是否需要进行上下文切换(pdTRUE/pdFALSE)
      @param  pxTaskToResume:正在恢复的任务的句柄
    */
    BaseType_t xTaskResumeFromISR(TaskHandle_t pxTaskToResume);
    

2.2.3 调度器相关函数

/*
  @brief  启动调度器
  @retval None
*/
void vTaskStartScheduler(void);
 
/*
  @brief  停止调度器
  @retval None
*/
void vTaskEndScheduler(void);
 
/*
  @brief  挂起调度器
  @retval None
*/
void vTaskSuspendAll(void);
 
/*
  @brief  恢复调度器
  @retval 返回是否会导致发生挂起的上下文切换(pdTRUE/pdFALSE)
*/
BaseType_t xTaskResumeAll(void);


/*
  @brief  让位于另一项同等优先级的任务
  @retval None
*/
void taskYIELD(void);
 
/*
  @brief  ISR 退出时是否执行上下文切换(汇编)
  @retval None
  @param  xHigherPriorityTaskWoken:pdFASLE不请求上下文切换,反之请求上下文切换
*/
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
 
/**
  @brief  ISR 退出时是否执行上下文切换(C语言)  
  @retval None
  @param  xHigherPriorityTaskWoken:pdFASLE不请求上下文切换,反之请求上下文切换
*/
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

2.3 FreeRTOS延时

​ 在裸机开发中,我们常常使用HAL_Delay()来实现延时功能,但FreeRTOS开发中,此时系统滴答是FreeRTOS主导的,所以我们应使用FreeRTOS中的延时函数来实现延迟。这两个函数都会使得当前的任务进入阻塞状态,使其他的任务有机会运行

2.3.1 vTaskDelay延时

/*			
		@brief:相对延时函数,宏定义INCLUDE_vTaskDelay必须定义为1,此函数才可用。相对延时,指的是从调用函数后开始计时,直到延时					 指定的时间结束。观察源代码发现,原来他只是把任务挂起(挂起态),等延时时间到,再把任务恢复(注意此时不是直接进入到					 运行态,而是就绪态)。
		@retval:None
		@param:const TickType_t xTicksToDelay:表示延时的时钟周期数(tick),configTICK_RATE_HZ配置FreeRTOS的内核时钟周期。																				 例如,如果内核时钟为1kHz,那么1tick对应的时间为1ms。																														  这个函数是仅仅通过tick数来计算延时持续的时间。
*/
void vTaskDelay(const TickType_t xTicksToDelay);

2.3.2 vTaskDelayUntil延时

/*			
		@brief:绝对延时函数,允许任务在指定的绝对时间再次激活。
		@retval:None
		@param:TickType_t *pxPreviousWakeTime:一个指针,指向一个变量,这个变量存储着上次任务唤醒的时刻。
					 TickType_t xTimeIncrement:每次唤醒后,需要延时的时间。
*/
void vTaskDelayUntil(TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement);

2.3.3 pdMS_TO_TICKS(x)宏

//是一个宏而不是函数,前面所使用的Delay函数是使用tick来计时的,但是我们人更喜欢用ms,s来作为延时的单位,而这个宏就是用来将毫秒数转化为相应的时钟滴答数(tick次数)的。
#ifndef pdMS_TO_TICKS
    #define pdMS_TO_TICKS( xTimeInMs ) 																																\
( (TickType_t) ( ( (TickType_t) (xTimeInMs) * (TickType_t) configTICK_RATE_HZ) / (TickType_t)1000U ) )
#endif

2.4 TCB任务控制块

​ 对于每一个task任务来讲,都有一个TCB_t结构体。这个结构体就叫做任务控制块。我们创建任务时最后的句柄handle就是指向的这个结构体。这个控制块里面包含的是任务的一些基本信息,例如任务状态,任务的优先级,任务栈的头指针,尾指针,任务的标识符等。(下面我们只看一些最重要的变量,重要的变量我将用中文进行标注)

typedef struct tskTaskControlBlock //TCB_T的旧名字      
{
    volatile StackType_t * pxTopOfStack; //一个指针,指向当前栈的栈顶,必须位于控制块的第一项

    #if ( portUSING_MPU_WRAPPERS == 1 )
        xMPU_SETTINGS xMPUSettings;//MPU设置,必须位于结构体的第二项
    #endif

    ListItem_t xStateListItem;       //该任务的任务状态列表项,该任务是运行态,还是就绪态,阻塞态,挂起态,就存在这里。
    ListItem_t xEventListItem;       //事件列项表,将任务以引用方式挂到事件列表中
    UBaseType_t uxPriority;          //任务的优先级
    StackType_t * pxStack;           //栈的起始位置
    char pcTaskName[ configMAX_TASK_NAME_LEN ]; //任务的名字

    #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
        StackType_t * pxEndOfStack; //指向栈最深的有效地址,也就是栈底。
    #endif

    #if ( portCRITICAL_NESTING_IN_TCB == 1 )
        UBaseType_t uxCriticalNesting; 
    #endif

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxTCBNumber; //存储一个特定的值来标识这个TCB任务块
        UBaseType_t uxTaskNumber; //对于任务,存储了一个特殊的值来表示任务,方便我们进行追踪,错误的定位等。
    #endif

    #if ( configUSE_MUTEXES == 1 )
        UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
        UBaseType_t uxMutexesHeld;
    #endif

    #if ( configUSE_APPLICATION_TASK_TAG == 1 )
        TaskHookFunction_t pxTaskTag;
    #endif

    #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
        void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
    #endif

    #if ( configGENERATE_RUN_TIME_STATS == 1 )
        configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
    #endif

    #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
        configTLS_BLOCK_TYPE xTLSBlock; /*< Memory block used as Thread Local Storage (TLS) Block for the task. */
    #endif

    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
        volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    #endif

    /* See the comments in FreeRTOS.h with the definition of
     * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
    #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
        uint8_t ucStaticallyAllocated;                     /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
    #endif

    #if ( INCLUDE_xTaskAbortDelay == 1 )
        uint8_t ucDelayAborted;
    #endif

    #if ( configUSE_POSIX_ERRNO == 1 )
        int iTaskErrno;
    #endif
} tskTCB;

typedef tskTCB TCB_t;

2.5 任务调度宏与任务调度算法

FreeRTOS的调度算法一般有三种,是否启用的宏定义在FreeRTOSConfig.h文件夹下可以看到,他们分别是:

#define configUSE_PREEMPTION //是否允许高优先级抢占 1允许 0不允许
#define configUSE_TIME_SLICING //是否允许时间片轮转 1允许 0不允许
#define configIDLE_SHOULD_YIELD	//是否允许空闲任务让步 1允许 0不允许

接下来我们来介绍这三种调度方式:

  1. 优先级抢占:即高优先级的任务是否可以优先抢占,其实对应的就是在就绪态任务中任务排队的次序,优先级越高,排队越靠前,越优先抢占。
  2. 时间片轮转:即同优先级的任务是否可以轮流运转,当宏定义为1时,可以轮流运行。
  3. 空闲任务让步:如果配置了让步的宏,空闲函数可以执行时,空闲函数只触发一次调度,调度后,又主动让出CPU资源让用户task执行。如果未配置的话,将会在空闲函数的while循环里多次循环,也就是说一直处于空闲任务执行的状态。

PS:我们一般使用的是111,也就是全使能的模式,允许高优先级抢占,允许时间片轮转,允许空闲任务让步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1885519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓微商大师V3.4.0/高级版一键群发僵尸粉检测

一款高效获取客源&#xff0c;备受好评的微商工具&#xff0c;资源丰富&#xff0c;秒速获得客源&#xff0c;大量群客源&#xff0c;都是散客&#xff0c;携手创业&#xff0c;是做微商生意的首选工具。打开即是黑钻高级会员 赶快体验吧 很强大 链接&#xff1a;https://pan.…

【实践总结】Python使用Pandas 读取Excel文件,将其中的值转换为字符串的方法

假设你的Excel的列有一行是这个样子的; 如果直接解析就会按照float字段处理&#xff0c;所以现在需要将他们按照字符串去读取出来。正确的做法如下说生意 import pandas as pddf pd.read_excel(ExcelPath, sheet_nameSHEET,dtype{Version: str})在这里我们使用的方法就是dtyp…

专门看电视的app有什么?9款免费看片追剧神器,尽享电视乐趣!(亲测有效)

今天又来跟大家聊聊那些让人眼前一亮的追剧app和电视直播软件&#xff0c;宅家必备呀&#xff01; 咱们这回不聊那些老掉牙的&#xff0c;来点新鲜的&#xff0c;让咱们的看剧电视屏幕也能跟上潮流&#xff0c;享受一下科技带来的便利和乐趣。 首先&#xff0c;得提一提央视频…

配电智能网关赋能电力系统智能化运行维护

随着智能电网和物联网技术的不断发展&#xff0c;两者之间的融合应用成为电力行业的重要趋势。配电智能网关作为连接两者的关键设备&#xff0c;在智能电网的物联网应用中发挥着重要作用。 配电智能网关能够实现对电力系统的实时监控、数据采集、远程控制等功能&#xff0c;为…

注意!!2024《信息系统监理师》易混淆知识点来了,赶紧收藏

宝子们&#xff0c;在复习软考信息系统监理师中&#xff0c;是不是觉得有很多知识点含义比较相近&#xff0c;很多友友刚看的时候估计会像我一样迷迷糊糊的&#xff0c;作为一个软考老鸟&#xff0c;在这里给大家整理了信息系统监理师学习过程中易混淆的知识点&#xff0c;大家…

山东益康,聚焦绿葆医院场景媒体,用爱服务人类健康

山东益康集团创建于1983年&#xff0c;发展成为集药品研发生产、销售、特医功能食品、精细化工、医疗防护产品等多产业经营为一体的省级企业集团。益康集团紧跟国家发展战略&#xff0c;满足民众日益增长的健康需求&#xff0c;将食品生产向特医保健功能食品转型升级&#xff0…

Windows PowerShell 添加新配置文件(打开对应的目录,并执行命令)

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe ./redis-server.exe %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe yarn dev 人工智能学习网站 https://chat.xutongbao.top

【C语言】刷题笔记 Day1

多刷题 多思考 【题目1】 实现字母的大小写转换&#xff0c;实现多组输入输出 1. getchar 为输入函数&#xff0c;EOF&#xff08;end of file&#xff09;为文件结束标志&#xff0c;通常为文件结束的末尾。 2. 题目中要求实现多组输入输出&#xff0c;那我们用 while 循…

2024 年江西省研究生数学建模竞赛题目 B题投标中的竞争策略问题---完整文章分享(仅供学习)

问题&#xff1a; 招投标问题是企业运营过程中必须面对的基本问题之一。现有的招投标平台有国家级的&#xff0c;也有地方性的。在招投标过程中&#xff0c;企业需要全面了解招标公告中的相关信息&#xff0c;在遵守招投标各种规范和制度的基础上&#xff0c;选择有效的竞争策…

武汉凯迪正大—冲击电流成套试验设备 雷电冲击电流发生器 成套雷电冲击装置

适用范围 本发生器适用于36kV及以下避雷器大电流试验、避雷器雷电流残压试验。 技术指标 1. 系统技术参数 1.标称电压&#xff1a;300kV 2.额定级电压&#xff1a;150kV 3.额定能量&#xff1a;45kJ 4.冲击电容量&#xff1a;75k/2uF*8台 5.总级数&#xff1a;2级 6.输…

指哪打哪,重绘神器!我已出手…

最近AI界又爆出了一个大新闻&#xff0c;阿里巴巴、香港大学和蚂蚁集团的研究人员联合推出了一款超厉害的AI工具——MimicBrush&#xff0c;它的问世&#xff0c;无疑给图像编辑领域带来了一场革命&#xff0c;它就像魔法师手中的魔杖&#xff0c;轻轻一挥&#xff0c;就能让图…

持续部署的7个陷阱及其避免方法

什么是持续部署&#xff1f; 持续部署是一种软件开发实践&#xff0c;其中代码更改会自动部署到生产中&#xff0c;无需开发人员或运营团队的明确批准。这实现了从开发到部署的完全自动化流程&#xff0c;确保新功能、错误修复和更新能够快速提供给最终用户。通过将此流程集成…

工业数据分析要用FusionInsight MRS IoTDB ?

随着工业互联网逐步兴起&#xff0c;在加速工业自动化、智能化的同时&#xff0c;也进一步加速工业生产时间序列数据的产生速度。但对于工业生产中的数据分析&#xff0c;仍然存在重复样本多&#xff0c;数据膨胀率大&#xff0c;缺乏专业易用的平台&#xff0c;这些问题成为阻…

2018年全国大学生数学建模竞赛A题高压油管的压力控制(含word论文和源代码资源)

文章目录 一、部分题目二、部分论文三、部分源代码问题1&#xff08;1&#xff09;绘制弹性模量与压力函数图&#xff08;2&#xff09;求最优单次开阀时间 问题二&#xff08;1&#xff09;极径与极角关系&#xff08;2&#xff09;求最优凸轮角速度 四、完整word版论文和源代…

数据库管理-第213期 HaloDB-Oracle兼容性测试03(20240625)

数据库管理213期 2024-06-25 数据库管理-第213期 HaloDB-Oracle兼容性测试03&#xff08;20240625&#xff09;1 索引1.1 B-Tree索引1.2 Hash索引1.3 复合索引1.4 唯一索引1.5 表达式索引1.6 部分索引 2 视图3 表连接3.1 内连接3.2 左/右外连接3.3 全连接清理环境&#xff1a; …

OpenSearch的演进与语义检索技术革新

周末听了一场关于Open Search的技术分析&#xff0c;整理如下&#xff0c;供大家参考。OpenSearch&#xff0c;作为ElasticSearch的一个分支&#xff0c;不仅继承了其强大的搜索和分析能力&#xff0c;更在开源社区的驱动下&#xff0c;不断演进和创新。本文将介绍OpenSearch的…

年轻人「入侵」厂货电商:泼天的富贵or甜蜜的烦恼?

【潮汐商业评论/原创】 “明天我们带个黑色塑料袋&#xff0c;假装是批发拿货的&#xff0c;看看能不能淘到好货。这个批发‘黑话’你也学一下&#xff0c;别到时候露馅。” Paula正兴冲冲地跟Grace计划去服装批发市场“消费”。 只不过&#xff0c;与以往普通进店客人身份不…

免费分享一套SpringBoot+Vue校园求职人才招聘(企业招聘)网站系统【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue校园求职人才招聘(企业招聘)网站系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue校园求职人才招聘网站(企业招聘)网站系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBo…

Dockerhub无法拉取镜像配置阿里镜像加速器

打开阿里镜像加速地址&#xff1a; https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 根据平台类型按照对应方式进行配置&#xff1a;Dokcer Desktop是在右上角点开配置 找到Docker Engine 进行设置JSON结构&#xff1a; 记得要重启Docker服务才会生效&#xff01…

甜蜜诱惑:红酒与巧克力的天作之合,双重美味引爆味蕾狂欢

在味蕾的世界里&#xff0c;有一种组合总能轻易勾起人们的无限遐想——那便是红酒与巧克力的搭配。它们一个是液态的宝石&#xff0c;一个是固态的柔情&#xff0c;两者交织在一起&#xff0c;便成了一场关于甜蜜诱惑的味蕾之旅。今天&#xff0c;就让我们一起探索雷盛红酒与巧…