# 嵌入式操作系统freeRTOS的内核多任务调度的原理 **Repository Path**: allankun/freertos ## Basic Information - **Project Name**: 嵌入式操作系统freeRTOS的内核多任务调度的原理 - **Description**: 我对freeRTOS的内核的多任务调度的总结,希望对小伙伴们有所帮助。 - **Primary Language**: C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-03-26 - **Last Updated**: 2022-03-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # freeRTOS的内核多任务调度的原理 ### 介绍 本文是我对freeRTOS的多任务调度的应用总结,干货满满,非常实用。 ### 什么是任务 我认为任务就是正在执行的一个函数,任务在RAM中有自己栈,并且有自己的任务结构体。 通过任务结构体可以访问到这个任务的栈 ![输入图片说明](%E4%BB%BB%E5%8A%A1.png) ### 任务是如何执行的呢 程序(函数/任务)存储在FLASH上,CPU从FLASH上读取编译后的机器码,然后开始执行,包括初始化寄存器,寄存器很重要,它是程序执行过程中的数据(我管它叫现场), 如果执行过程中有调用其他函数的话,就会对本任务的栈进行压栈和出栈处理。但是如果任务被中断,比如有高优先级的任务进入就绪队列等待的话,当前任务执行中的CPU寄存器(现场)就会被压入这个任务的栈中,等待再次轮转到它的时候,就可以出栈(恢复现场)接着刚才的位置再次执行了。 ![输入图片说明](%E6%89%A7%E8%A1%8C%E9%95%9C%E5%83%8F.png) ### 为什么要保护现场 比如说一个任务被切换,切换时它还没有执行完成,下一次再次进入执行的时候,需要接着刚才的位置继续执行,并且还要继续使用刚才执行的CPU寄存器的结果,因此在freeRTOS在做切换调度的时候,会把被切换的任务的CPU寄存器先压入它的栈中,然后再切换到新的任务。 这个过程就是保护现场 ![输入图片说明](%E4%BF%9D%E6%8A%A4%E7%8E%B0%E5%9C%BA.png) ### 内核如何调度 每个任务被创建出来后,由内核的按着他们的优先级放入各个优先级的队列中,freeRTOS有5个优先级,所以内核有5个优先级的就绪队列,这个队列是由链表实现的。 执行调度函数后,内核就开始从高优先级队列取出一个任务,开始执行,执行周期为1ms, 时间一到开始切换下个任务,如果没有更高的有先级任务的话,就会从低优先级的任务队列中执行任务,循环执行。 ![输入图片说明](%E4%BB%BB%E5%8A%A1%E9%98%9F%E5%88%97.png) 调度: ![输入图片说明](%E8%B0%83%E5%BA%A6.png) ### 任务的状态 就绪态(ready):随时可以执行。 阻塞态(delay):本质是任务想执行,无奈有更高的优先级任务在执行。 暂停态(suspend):本质是任务不想执行,比如说让任务sleep一段时间。 ### freeRTOS的队列情况 ![输入图片说明](%E9%98%9F%E5%88%97.png) ### 阻塞和唤醒 阻塞:要想阻塞一个任务,只需把这个任务从就绪队列中放入阻塞队列里。 唤醒:要想唤醒一个任务,只需把这个任务从阻塞队列中放入就绪队列里。 ### freeRTOS任务调度要注意的地方 启动内核调度器的时候会创建一个空闲任务 优先级是0 空闲任务的作用是做一些清理工作。把其他任务的栈来释放掉 启动内核调度器的时候,对于多个同一优先级的任务在就绪队列中时,先执行最后追加的那个任务 因为在创建任务的时候,内核的当前任务结构体指针一直在比较当前和后来的任务的优先级,如果相等,指向后来的任务 执行时候的顺序是跟队列的顺序依次执行 任务1 优先级1 任务2 优先级2 任务3 优先级3 开始执行顺序 任务3 -> 任务1 -> 任务2 任务1 优先级0 任务2 优先级0 任务3 优先级0 空闲任务 优先级0 开始执行顺序 空闲 -> 任务1 -> 任务2 -> 任务3 空闲任务礼让: 如果有同是优先级0的其他就绪任务,空闲任务主动放弃一次运行机会。