FreeRTOS系列教程(前言):为什么要用FreeRTOS?

目录

一. 概要

二. 常用的裸机系统

2.1 前后台系统

2.2 时间片轮询系统

三. FreeRTOS系统介绍

四. 小结


一. 概要

在我们进入嵌入式这个领域的时候,往往最先接触的是裸机编程,即不带任何操作系统,程序在main函数中初始化完成以后就进入一个大的while(1)循环,这种架构适用于大多数的功能较少,单片机资源匮乏,并且对系统可靠性要求较高的场合,比如电机,电饭煲等设备的嵌入式系统。

但随着产品需要实现的功能的不断增加,这时候仅仅用一个while(1)循环来处理众多纷纷扰扰的任务已经显得越来越力不从心,多任务实时操作系统应运而生。

以下框图说明了嵌入式实时操作系统(RTOS)与裸机系统之间的差异:加入操作操作系统本身会对单片机带来一定的存储空间开销,但那些发明操作系统的天才工程师,已经对内核程序做了完备而稳定的开发,相当于已经给我们打了坚实的地基,我们只需要在地基的基础上,开发自己的应用程序,这样相比起裸机系统,RTOS使得应用程序开发可以更敏捷——迭代地添加特性和功能,而不必总得重构底层系统。

目前比较流行的实时操作系统包括黑莓QNX,FreeRTOS,uCOS,RT-Thread等。在所有操作系统中,除了Linux和Windows通用操作系统外,接下来便是FreeRTOS受到广大开发者的青睐。这里需要说明的是,和实时操作系统(Real Time Operating System)相对应的是通用操作系统(General Purpose Operating System)。通用操作系统包括Linux,Windows,Android等主流的操作系统。这些操作系统大家每天都在使用,功能也十分强大,只是它们有时为了保障系统的流畅运行,就不能保证每个程序都能实时响应,在易用性和实时性之间有所取舍。而且单片机有限的片上资源也不足以支撑通用操作系统的运行。

接下来几个小节,我们会从通用的裸机系统出发,总结裸机系统框架及其存在的不足,然后逐步过渡到为什么要使用FreeRTOS操作系统。

二. 常用的裸机系统

2.1 前后台系统

一般简单的裸机系统编程思路是下面这样的,即前后台系统:

int main(void)
{

   HardWareInit(); /* 硬件相关初始化 */
   
   while(1) 
   {
     if(flag1)
      {
        run_task_1(); /*执行任务1*/
        flag1 = 0;
      }   
    

     if(flag2)
      {
        run_task_2(); /*执行任务2*/
        flag2 = 0;
      }

    run_task_3; /*执行任务3*/
       
   }
}

void ISR1(void)
{
    flag1 = 1;  /*置位标志位1*/
}

void ISR2(void)
{
    flag2 = 1;  /*置位标志位2*/
}

在这个裸机架构里,while(1)里的程序不断顺序且循环执行,如果有中断1或者2来临,就置位标志位,然后在后台即while(1)里面执行相应任务,没有中断来临的时候,就不断执行任务3。这里面任务的响应和处理是分开的,确保了任务不会丢失,但是任务的处理还是在后台里面顺序执行的,这种系统在应用得当的情况下,具有良好的效果。

但是,我们假设出现了一个极端情况,任务3的执行需要足足1分钟,这时候就算中断1来临,但任务1也久久得不到执行,我们就会感觉到任务1的响应变得很迟缓。这时候有些读者可能会说,那我把任务1的执行放在中断中不就行了,比如下面这样:

void ISR1(void)
{
    flag1 = 1;  /*置位标志位1*/
    run_task_1; /*执行任务1*/    
}

这样确实可以保证任务1的快速执行,但可能引发另一个问题,在中断中我们要遵循快进快出的原则,如果任务1的执行过程太久,也需要足足1分钟,那么这时候,其他优先级比ISR1低的中断将难以得到执行,甚至可能引发中断丢失!这个后果有时候比响应迟缓更加严重。

2.2 时间片轮询系统

时间片轮询法的实质就是以一个定时器为基本时间片,然后在根据任务性质不同,在不同的时间轮询中执行相应任务。如下代码所示为一个典型的时间片轮询系统,也是我本人在裸机系统中经常使用的。当然也有其他表现形式的时间片轮询系统,但主体思想相同。

在定时器中设置不同的基本时间片,比如设置基本时间片为1ms,即代表每1ms进入定时器中断Timer_ISR,每1ms定时时间到,is_system_tick_arrive就置位,然后判断每个任务有没有到自己的周期,比如TASK1_PERIOD设置为100,即run_task_1每100ms执行一次。每个任务的执行周期根据任务的实时性要求确定,比如对实时性要求高的通信任务,执行周期可以定为1ms;比如对实时性要求低的数据采集任务,执行周期可以定为100ms。

通过这种方式,CPU不用频繁去做一些无意义的劳动,不同任务只有在自己的时间片到来后才会去执行,优化了系统资源分配,再加上对于中断的配合使用,可以达到良好的效果。这里需要注意的一点是,比如设置基本时间片为1ms,那么在基本时间片里的所有代码,都需要在1ms内执行完成,不然可能会影响任务周期的准确性。

int main(void)
{

   HardWareInit(); /* 硬件相关初始化 */   
   while(1) 
   {
     if(is_system_tick_arrive)
     {
        if(++task1_hander == TASK1_PERIOD) /*如果到了任务1的时间片*/
        {
          task1_hander = 0;
          run_task_1();  /*执行任务1*/
        }
        
        if(++task2_hander == TASK2_PERIOD) /*如果到了任务2的时间片*/
        {
          task2_hander = 0;
          run_task_2();  /*执行任务2*/
        }

     }
   }
}

void ISR1(void)
{
    run_isr_task;  /*处理中断*/
}

uint8_t is_system_tick_arrive(void)
{
   uint8_t flag;
   flag = system_timer_flag;
   system_timer_flag = 0;
   return flag;
}

void Timer_ISR(void)
{
  system_timer_flag = 1;  /*置位标志位2*/
}

在单片机系统资源不足,且任务不多的情况下,使用时间片轮询系统是一个比较好的选择,但它也有一些固有的弊端,比如:

  • 缺乏优先级管理:所有任务都被平等地对待,无法对任务设置优先级。这意味着,高优先级的任务(如需要快速响应的中断处理程序的任务)可能无法及时得到执行。比如一个中断来临,需要我们快速执行中断相关的任务run_task_2,如果还没到task_1的时间片,run_task_2可以快速得到执行,这是相比前后台系统的改进;但当到了task_1的时间片就需要执行run_task_1,不巧run_task_1需要的执行时间又很久,这时候run_task_2就久久得不到执行。
  • 响应时间不确定:在每一个基本时间片1ms里,所有任务都是轮流执行,同样的,假如到了task_1的时间片,不巧run_task_1需要的执行时间又很久需要10ms,超过了1ms,这时候下一个1ms来临时,而上一个1ms里的任务还没执行完,下一个1ms只能委屈的等着上一个1ms执行完才能得到执行,极大影响任务周期的准确性。
  • 复杂的同步和通信:在时间片轮询系统中,任务间的同步和通信可能会变得复杂,因为我们需要确保在任务切换时,数据的一致性和完整性。

三. FreeRTOS系统介绍

在上一节的基础上,若想对时间片轮询系统的固有弊端进行改进,就需要在每次进入时钟中断前,保存CPU的当前状态和当前事务用到的一些数据,然后我们进入时钟中断进行时间片处理,若发现有新的更紧急的事务的时间片到来了,则我们改变中断的返回的地址,并在CPU中恢复这个更紧急的事务的现场,然后返回中断开始执行这个更紧急的事务。

然后我们惊奇的发现,这些事,操作系统都已经帮我们做好了!而且,RTOS的用处远不止帮我们完成这个“事务时间片的处理”,它还能帮我们处理各种超时,进行内存管理,完成任务间的通信等。

到这里,我们终于知道了为什么我们需要RTOS了。

作为RTOS大家庭中重要的一员,FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。其主要特性有:

  1. 轻量级和实时性:FreeRTOS 的内核非常小,通常只需要大约 6KB 到 12KB 的内存空间(取决于平台和编译选项),适合资源受限的系统,并且具有实时任务调度能力。
  2. 可移植性:FreeRTOS 支持多种处理器和编译环境,使得开发人员可以在不同的硬件平台上使用它。
  3. 丰富的 API:FreeRTOS 提供了一套丰富的 API,开发人员可以用来创建任务、管理内存、同步任务和通信等。
  4. 可伸缩性:FreeRTOS 可以根据需要定制和扩展,以满足不同的系统需求。
  5. 开源和社区支持:FreeRTOS 是开源的,有一个活跃的社区提供支持。

FreeRTOS的官网地址如下,在里面可以看到完整的内核源码文件,我们可以根据需求方便的加入到自己的工程中。                                   https://www.freertos.org/zh-cn-cmn-s/icon-default.png?t=N7T8https://www.freertos.org/zh-cn-cmn-s/

在FreeRTOS中,根据程序的功能,把程序主体分割成一个个独立的,无限循环且不能返回的子程序,称之为任务。每个任务都是独立的,互不干扰的,且具备自身的优先级,它由操作系统调度管理。加入操作系统后,我们不需要关注每个功能模块之间的冲突,重心放在应用程序的实现即可。其执行框架如下图所示。

四. 小结

本文重点讲述了从裸机系统到FreeRTOS的过渡,以及为什么我们要学习FreeRTOS操作系统,并不能武断的说FreeRTOS相比裸机系统就更有优势,裸机系统有裸机系统适合的情况,FreeRTOS有FreeRTOS适合的情况。我们需要知道的是,在接到一个项目的时候,如何根据项目需求,选择出合适的系统用来开发。

裸机系统更合适的情况有:

  1. 项目规模较小:如果我们的项目只需要执行一些简单的、线性的任务,并且不需要进行多任务处理,那么裸机系统可能是一个更好的选择。
  2. 对性能要求高:裸机系统没有操作系统的开销,因此在需要极高性能或实时响应的应用中可能更有优势。比如电机驱动程序等。
  3. 资源限制严格:如果系统资源(如内存、处理器速度等)非常有限,裸机系统可以最小化资源使用。

FreeRTOS更合适的情况有:

  1. 需要多任务处理:如果我们的项目需要同时处理多个复杂的任务,FreeRTOS的任务调度器可以轻松管理这些任务。
  2. 需要内存管理:FreeRTOS提供了动态内存管理功能,这在处理大量数据或动态数据时非常有用。
  3. 需要互斥和同步:如果你的项目中有多个任务需要访问共享资源,FreeRTOS提供了互斥量和信号量等同步机制。

在接下来的系列文章中,我将层层递进,带大家一起揭开FreeRTOS的神秘面纱。

 FreeRTOS系列教程(一):内核关键概念icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor?spm=1011.2124.3001.6192

原创不易,欢迎交流。大家可以关注我的微信公众号,里面不定期会有干货知识分享和项目实战经验总结,

  • 62
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值