本篇文章从FreeRTOS10.0说明书,以及操作系统原理相关论文中,整合而成。 从操作系统原理本身去认识FreeRTOS,适合新手或者已入门的朋友进阶。
一、为什么使用实时多任务操作系统?
RTOS,real-time Operate System。有很多成熟的技术可以在不使用内核的情况下编写好的嵌入式软件,但是在复杂情况下,RTOS有如下的好处:
1)用户无需关心时间信息
内核负责计时,并由相关的API完成,从而使得用户的应用程序代码结构更简单。
2)模块化、可拓展性强
也正是由于第一点的原因,程序性能不易受底层硬件更改的影响。并且,各个任务是独立的模块,每个模块都有明确的目的,降低了代码的耦合性。
3)效率高
内核可以让软件完全由事件驱动,因次,轮询未发生的事件是不浪费时间的。相当于用中断来进行任务切换。
4)中断进程更短
通过把中断的处理推迟到用户创建的任务中,可以使得中断处理程序非常短。 二、FreeRTOS的核心功能
![83783963f5bf87d8bfb016d13ac848b4.png](https://i-blog.csdnimg.cn/blog_migrate/e4277be433dbf06e9084e0ad02b8cc82.jpeg)
接下来,就按顺序介绍以上的4种核心功能。 三、内存管理
![237c1d5762c2b82d7de696dc848c0911.png](https://i-blog.csdnimg.cn/blog_migrate/b5d4437e12117ffb74f0f7a54667931f.jpeg)
下图为heap2内存分配方式
![3b21c1e151fb844e05f7892af74ba666.png](https://i-blog.csdnimg.cn/blog_migrate/cb7f3d5241d2b2fe03c6fb74e0e25c57.jpeg)
下图为heap4内存分配方式
![b703478ed959fc16ab899fc7ade0cf83.png](https://i-blog.csdnimg.cn/blog_migrate/2b0c04eebcb8a339aebfa1b0834e3fe2.jpeg)
其中,heap4:我们主要用到的是动态内存分配的heap4。相比于heap2的链表式内存块结构,heap4是按照物理地址来进行排序。这样设计的目的是方便合并相邻物理地址中空闲的内存块。但是,当在嵌入式系统中,频繁的创建与释放内存,还是会导致空闲块物理地址相对分散,依然会产生较多内存碎片。
补充:μS/OS采用的是静态分割成多个块。
四、任务管理
1.如何创建一个任务(接下来我会举一个实例)
用到的函数:xTaskCreate(如下图)
![26454e50b838744b87e2afae5e7f6e9e.png](https://i-blog.csdnimg.cn/blog_migrate/40017de902195c80a23e2ca94992c397.jpeg)
如何创建两个不同的任务,并让他们都能够执行呢?
首先,声明任务1和任务2(如下图)
![07aebcea2539ec9d477b40935fad35ab.png](https://i-blog.csdnimg.cn/blog_migrate/15d2d1f1b9aa34ce4a90168b22302dd9.jpeg)
接着,在主函数中创建任务1和任务2(如下图)
![3d7ccbb01eec47f918a75dff24b0a69c.png](https://i-blog.csdnimg.cn/blog_migrate/9c3e1c8d402eef14b46c4e0280425fdf.jpeg)
最后,通过串口打印能看出两个任务在轮流执行。(下图)
![a5f51ffcda1e712f49024165b3e4b98e.png](https://i-blog.csdnimg.cn/blog_migrate/52a4db12fcabdf0dee66e5e29259a6fa.jpeg)
2.优先级
优先级0是最低优先级,可以通过在FreeRTOSConfig.h文件中,设置configMAX_priorities来配置最高优先级数。
特别要注意,不同任务可以共用同一个优先级。
3.你知道为什么要用vTaskDelay吗
在有两个任务的情况下,不用delay的时候,每执行完一个任务,需要等到Tick中断,才能让调度器选择运行下一个任务(如下图)。
![53233419df1173fcc892ce2b33180af7.png](https://i-blog.csdnimg.cn/blog_migrate/b8d70075c0761cf4709d84d91398bc16.jpeg)
当使用了delay之后,两个任务能够在一个周期内依次运行(如下图),毕竟处理1个任务不需要占用整一个时间周期,之前不用delay的做法太浪费了。
![cc556151a727e8ade50058b869292e66.png](https://i-blog.csdnimg.cn/blog_migrate/03e7a26a602d2b6efa526f5ceec05756.jpeg)
4.任务在不同的状态间调度
![f15c4e4f71b930b58430b03ab0f72fe7.png](https://i-blog.csdnimg.cn/blog_migrate/1a2b915002501b3efe8c73d394b89d97.jpeg)
5.vTaskDelay和VTaskDelayUntil的区别
第一个delay是相对的延时,第2个delayuntil是绝对的延时,适合需要固定频率执行的任务
。
6.对于空闲任务来说,它一直都处于就绪态,只有当其他优先级比它高的任务,都执行完了,都在阻塞态里,空闲任务idle task才会执行。
五、(任务间)通信管理
1.队列的原理
队列,可以容纳有限数量固定大小的数据。一般采用FIFO存储方式(First in First Out)。而在freertos中,队列的传输用的是copy的方式。
队列传输数据方式(过程如下图)
![bbd97fa0b7817202b8ca575f81d54fbe.png](https://i-blog.csdnimg.cn/blog_migrate/1d7c63af273bccf94151e216d345f241.jpeg)
采用copy传递的优势有:堆栈中的变量也可以直接发送到队列中,而不用担心是否会被释放掉。因次,发送和接收任务也不用去关心是哪一个任务“拥有”数据。
2.创建一个队列
![21e54b3b4ee6dc32f1c5eb9b06c4345e.png](https://i-blog.csdnimg.cn/blog_migrate/d2060c917b8d6f451a2470ffc4716c1f.png)
3.接收队列
![321cb03c30f0cb7924794bf3f4001e70.png](https://i-blog.csdnimg.cn/blog_migrate/642fe98a18b95d8c0f9eb2bd600a864e.png)
4.利用指针传输特大变量。
5.可能有人问,队列有什么用处呢?
确实,用全局变量直接很多。但在中断的时候,如果中断执行的时间很长,数据处理量很大,会影响正常任务的运行。因次我们通过把数据转移到任务里面再作处理,减小中断开销。 六、其他功能
还有软件时钟管理、事件管理、解决互斥问题的内存管理方法等等,可以先不管,还未看到过有人用,感觉事件管理还不如来个全局变量flag。七、数据类型
freertos有自己的命名规格,在portmarco.h文件里。
今天就先介绍到这里,吐血整理,希望对你有帮助。