控制/MCU
实时系统有各种各样的实现方式和使用情况。本书的重点是如何使用实时操作系统(RTOS)在微控制器单元(MCU)上创建实时应用程序。
在这一章中,我们将首先概述什么是RTOS,并了解可能有实时要求的广泛系统。从那里,我们将看看实现实时性能的一些不同方法,以及可能使用的系统类型(如硬件、固件和软件)的概述。最后,我们将讨论什么时候在MCU应用中使用RTOS是明智的,什么时候可能完全没有必要。
任何对特定事件有确定响应的系统都可以被认为是 "实时 "的。如果一个系统在不符合时间要求时被认为是失败的,它一定是实时的。如何定义故障(以及故障系统的后果)可以有很大不同。认识到实时性要求可以有很大的不同,这一点极其重要,既包括时间要求的速度,也包括如果没有达到所要求的实时期限,后果的严重性。
为了说明可能遇到的定时要求的范围,让我们考虑从模数转换器(ADC analog-to-digital converters)获取读数的几个不同系统。
我们要看的第一个系统是一个控制系统,它被设置为控制烙铁的温度(如下图所示)。我们所关注的系统部分是MCU、ADC、传感器和加热器。
MCU负责以下工作:
由于焊头的温度变化不是非常快,MCU可能只需要每秒获取50个ADC样本(50Hz)。负责调整加热器的控制算法(以保持恒定的温度)以更慢的速度运行,5赫兹:
ADC将断言硬件线路,表示转换已经完成,并准备让MCU将读数转移到其内部存储器。读取ADC的MCU有多达20毫秒的时间将数据从ADC传输到内部存储器,然后才需要进行新的读取。MCU还需要运行控制算法来计算加热器输出的更新值,频率为5赫兹(200毫秒)。这两种情况(虽然不是特别快)都是实时要求的例子:
现在,在ADC读数的另一端,我们可能有高带宽的网络分析仪或示波器,它将以几十GHz的速率读取ADC!在这种情况下,ADC的原始读数很可能是在几百个小时内完成!原始ADC读数可能会被转换成频域,并在高分辨率前面板上以图形方式显示,每秒几十次。像这样的系统需要进行大量的处理,必须遵守极其严格的时间要求,如果它要正常运作的话。
在光谱的中间位置,你会发现诸如闭环运动控制器等系统,它们通常需要在数百赫兹至数十千赫兹之间执行其PID控制回路,以便在快速移动的系统中提供稳定性。那么,实时性有多快?嗯,仅从ADC的例子就可以看出,这取决于。
在前面的一些例子中,如示波器或电烙铁,如果不能满足计时要求,就会导致性能不佳或报告错误的数据。在电烙铁的情况下,这可能是温度控制不佳(这可能导致组件损坏)。对于测试设备来说,错过最后期限可能导致错误的读数,这就是失败。这对一些人来说可能不是什么大问题,但对该设备的用户来说,他们依赖所报告数据的准确性,这可能是非常重要的。一些用于标准验证的实验室设备对产品的一致性进行检查。如果设备中存在未被发现的故障,导致测量不准确,就可能报告出不正确的数值。可能有可能重新进行可疑的测试。然而,最终,如果重新测试的频率过高,可靠的读数不能指望,那么测试设备将开始变得可疑,并被视为不可靠,销售将下降--所有这些都是因为一个实时要求没有得到持续满足。
在其他系统中,如无人机的飞行控制或工业过程控制中的运动控制,如果不能及时运行控制算法,可能会导致更多的物理灾难,如崩溃。在这种情况下,其后果有可能危及生命。
值得庆幸的是,可以采取一些措施来避免所有这些故障情况的发生。
确保一个系统做它要做的事情的最简单的方法之一是确保它在满足要求的同时尽可能的简单。这意味着要抵制将简单的任务过度复杂化的冲动。如果烤面包机是用来烤面包的,就不要在上面加一个显示屏,让它也告诉你天气情况;只要让它在适当的时间内打开加热元件即可。这个简单的任务已经完成了多年,不需要任何代码或可编程设备。
作为程序员,如果我们遇到一个问题,我们倾向于立即伸手去拿最近的MCU并开始编码。然而,产品的一些功能(尤其是当产品有电子机械部件时)最好不用代码来处理。车窗其实不需要带轮询循环的MCU来运行,通过驱动器打开电机,观察传感器的反馈来关闭它们。这项任务实际上可以由一些机械开关和二极管来处理。如果给定的系统需要一个反馈报告机制--比如在窗口卡住的情况下需要断言错误--那么可能别无选择,只能使用一个更复杂的解决方案。然而,作为工程师,我们的目标应该始终是相同的--尽可能简单地解决问题,不增加额外的复杂性。
如果一个问题可以单独通过硬件来解决,那么在拿出MCU之前,先与团队一起探讨这种可能性。如果问题可以通过使用简单的while循环来执行一些传感器状态的轮询来处理,那么就简单地轮询传感器的状态;可能没有必要开始编码中断服务程序(ISRs)。如果设备的功能是单一用途的,那么在很多情况下,完整的实时操作系统可能会妨碍工作--所以不要使用它!
有许多不同的方法来实现实时行为。下面的部分是关于你可能遇到的各种类型的实时系统的讨论。还要注意的是,有可能出现以下系统的组合,作为子系统一起工作。这些不同的子系统可以出现在产品、板卡、甚至是芯片层面(这种方法在第16章多处理器和多核系统中讨论)
最初的实时系统,即硬件,仍然是满足极其严格的公差和/或快速定时要求的首选。它可以用离散数字逻辑、模拟组件、可编程逻辑或特定应用集成组件(ASIC application-specific integrated component)来实现。可编程逻辑器件(PLD Programmable logic devices)、复杂可编程逻辑器件(CPLD complex programmable logic devices)和域可编程门阵列(FPGA field-programmable gate arrays)是该解决方案中可编程逻辑器件部分的不同成员。基于硬件的实时系统可以涵盖从模拟滤波器、闭环控制和简单的状态机到复杂的视频编解码器的任何东西。当实施时考虑到省电,可以使ASIC比基于MCU的解决方案消耗更少的功率。一般来说,硬件的优点是可以即时并行地进行操作(当然,这是过度简化),而单核MCU则只能给人以并行处理的假象。
实时硬件开发的缺点一般包括以下几点:
裸机固件被认为是(为我们的目的)不是建立在某种类型的预先存在的内核/调度器之上的任何固件。一些工程师更进一步,认为真正的裸机固件不能使用任何预先存在的库(如供应商提供的硬件抽象库),这种观点也有一定的道理。裸机实现的好处是,用户的代码可以完全控制硬件的所有方面。主循环代码执行被打断的唯一方法是中断发生时。在这种情况下,其他东西控制CPU的唯一方法是让现有的ISR完成,或让另一个更优先的中断启动。
当有少量相对简单的任务需要执行时,或者有单一的任务时,裸机固件解决方案就很出色。如果固件保持专注并遵循最佳实践,由于ISR(或在某些情况下,缺乏ISR)之间的相互作用相对较少,确定的性能通常容易测量和保证。在一些极端的情况下,对于高负载的MCU(或在ROM/RAM方面受到高度限制的MCU),裸机是唯一的选择。
随着裸机实现在异步处理事件时变得更加复杂,它们开始与实时操作系统提供的功能重叠。要记住的一个重要考虑是,通过使用RTOS--而不是试图推出你自己的线程安全系统--你会自动受益于RTOS供应商所做的所有测试。你也有机会使用具有事后分析能力的代码--今天所有的RTOS都已经存在了好几年了。作者一直在调整和增加功能,以使它们在不同的应用中变得强大和灵活。
在MCU上运行调度内核的固件是基于RTOS的固件。调度器和一些RTOS原件的引入允许任务在它们自己拥有处理器的假象下运行(在第2章,了解RTOS任务中详细讨论)。使用RTOS可以使系统在后台执行其他复杂任务的同时保持对最重要事件的响应。
所有这些任务的运行都有一些弊端。共享数据的任务之间可能会出现相互依赖的情况--如果处理不当,这种依赖性会导致任务意外地阻塞。虽然有处理这种情况的规定,但它确实增加了代码的复杂性。中断一般会使用任务信令来尽快处理中断,并将尽可能多的处理推迟到任务中。如果处理得当,这种解决方案对于保持复杂系统的响应是非常好的,尽管有许多复杂的互动。然而,如果处理不当,这种设计范式会导致更多的时间抖动和更少的确定性。
运行在包含内存管理单元(MMU)和中央处理单元(CPU)的完整操作系统上的软件被认为是基于RTOS的软件。用这种方法实现的应用程序可能非常复杂,需要在各种内部和外部系统之间进行许多不同的交互。使用完整的操作系统的好处是伴随着它的所有能力--包括硬件和软件。
在硬件方面,通常有更多的CPU核心以更高的时钟速率运行。可以有数千兆字节的内存和持久性存储器。增加外围硬件可以像增加一块卡一样简单(只要有预先存在的驱动程序)。
在软件方面,有大量用于网络堆栈、用户界面开发、文件处理等的开源和供应商专有解决方案。在所有这些能力和选项之下,内核仍然以这样一种方式实现,即关键任务不会被无限期地阻断,这在传统的操作系统中是可能的。正因为如此,获得确定性的性能仍然是可以做到的,就像RTOS固件一样。
与基于RTOS的软件类似,一个标准的操作系统拥有开发者可以要求的所有库和功能。然而,缺少的是对满足时间要求的严格关注。一般来说,用传统操作系统实现的系统会有更少的确定性行为(在安全关键的情况下,没有一个可以真正指望的)。如果在没有灾难性后果的情况下,有一个宽松的实时性要求,如果没有按时完成一个踌躇满志的最后期限,只要在选择运行什么软件堆栈和控制它们的资源使用方面谨慎行事,标准的操作系统就可以发挥作用。带有PREEMPT_RT补丁的Linux内核是这种类型的实时系统的一个很好的例子。
所以,现在实现实时系统的所有选项都已被列出,现在是时候准确定义我们说的RTOS,特别是基于MCU的RTOS是什么意思。
操作系统(如Windows、Linux和macOS)的创建是为了提供一个一致的编程环境,将底层硬件抽象化,使其更容易编写和维护计算机程序。它们为应用程序员提供了许多不同的基元(如线程和互斥),可以用来创建更复杂的行为。例如,可以创建一个多线程程序,提供对共享数据的保护性访问:
前面的应用程序并没有实现线程和互斥基元,它只是利用了它们。线程和互斥的实际实现是由操作系统处理的。这有几个优点:
在前面的例子中,mutex被用来确保每次只有一个线程可以访问共享数据。在通用操作系统的情况下,每个线程都会很高兴地等待突变体无限期地可用,然后再去访问共享数据。这是实时操作系统与通用操作系统不同的地方。在RTOS中,所有阻塞的系统调用都是有时间限制的。RTOS不允许无限期地等待mutex,而是允许指定一个最大延迟。例如,如果线程1试图获取Mutex,但在100毫秒(或1秒)后仍未得到它,它将继续等待Mutex变得可用。
在RTOS的实现中,要指定等待Mutex变得可用的最大时间。如果线程1指定它必须在100毫秒内获取Mutex,并且在101毫秒后仍未收到Mutex,线程1将收到通知,说Mutex没有被及时获取。指定这个超时是为了帮助创建确定性的系统。
任何提供执行给定代码的确定性方式的操作系统都可以被认为是实时操作系统。这个实时操作系统的定义涵盖了相当多的系统。
有几个特征倾向于将RTOS应用与另一RTOS应用区分开来:不满足实时截止日期的频率是可以接受的,以及不满足实时截止日期的严重程度。不同范围的RTOS应用通常被归纳为三类--硬、固和软实时系统。
不要太纠结于固和软实时系统之间的区别。这些术语的定义在我们的行业内甚至没有一致的意见。重要的是,你要知道你的系统的要求,并设计一个解决方案来满足这些要求!
如果故障会导致生命或重大财产的损失,那么故障的严重程度一般被认为是安全关键型的。有一些硬实时系统与安全无关。
硬实时系统必须在100%的时间内满足其最后期限。如果系统没有达到最后期限,那么它就被认为是失败了。这并不一定意味着如果故障发生在硬实时系统中就会伤害到人,只是说如果系统错过了一个截止日期,它就失败了。
硬实时系统的一些例子可以在医疗设备中找到,如心脏起搏器和具有极其严格控制参数的控制系统。在心脏起搏器的情况下,如果心脏起搏器错过了在正确的时间点进行电脉冲的最后期限,它可能会杀死病人(这就是为什么心脏起搏器被定义为安全关键型系统)。
相反,如果计算机数控(CNC)铣床上的运动控制系统没有及时对指令做出反应,它可能会将刀具插入正在加工的零件的错误部位,从而毁掉它。在我们提到的这些案例中,故障造成了生命损失,而另一个则把一些金属变成了废品,但这两个故障都是由错过的最后期限造成的。
与硬实时系统相比,固实时系统几乎在所有时间都需要达到其最后期限。如果视频和音频瞬间失去同步,可能不会被认为是系统故障,但可能会使视频的消费者感到不安。
在大多数控制系统中(类似于前一个例子中的烙铁),稍微超出规定时间的几个样本的读取不太可能完全破坏系统控制。如果控制系统有ADC,可以自动获取新的样本,如果MCU没有及时读取新的样本,它将被新的样本覆盖。这种情况可能偶尔发生,但如果发生得太频繁或太频繁,温度稳定性就会被破坏。在要求特别高的系统中,可能只需要错过几个样本,整个控制系统就会失灵。
当涉及到系统必须满足其最后期限的频率时,软实时系统是最宽松的。这些系统通常只提供一个遵守最后期限的最大努力的承诺。
汽车中的巡航控制是软实时系统的很好的例子,因为对它没有硬性规定或期望。驾驶员通常不期望他们的速度能收敛到设定速度的+/- x mph/kph之内。他们期望在合理的情况下,例如没有大的坡度,控制系统最终会让他们在大多数时间内接近他们的理想速度。
实时操作系统的功能各不相同,它们最适合的处理器架构和尺寸也各不相同。在较小的方面,我们有较小的以8-32位MCU为重点的RTOS,如FreeRTOS、Keil RTX、Micrium µC、ThreadX,以及更多。 这类RTOS适合在微控制器上使用,并提供一个紧凑的实时内核作为最基本的产品。当从MCU转向32位和64位应用处理器时,你会倾向于找到RTOS,如Wind River VxWorks和Wind River Linux、Green Hills的Integrity OS,甚至是带有PREEMPT_RT内核扩展的Linux。这些完整的操作系统提供了大量的软件选择,为实时调度要求以及一般计算任务提供了解决方案。即使有了我们刚刚提到的操作系统,我们也只是触及了可用的表面。在所有级别的实时操作系统中,无论大小,都有免费和付费的解决方案(有些价格远远超过10000美元)。
那么,既然有免费的解决方案,你为什么还要选择付费呢?免费提供的RTOS解决方案和付费解决方案之间的主要区别因素是安全批准、中间件和客户支持。 因为实时操作系统提供了高度确定的执行环境,它们经常被用于复杂的安全关键型应用。我们所说的安全关键,一般是指一个系统,其故障可能会伤害人或造成重大损失。这些系统需要确定性的操作,因为它们必须一直以可预测的方式行事。保证代码在固定的时间内对事件做出反应是确保它们行为一致的重要一步。这些安全关键型应用中的大多数都受到监管,并有自己的一套管理机构和标准,如飞机的DO-178B和DO-178C或工业应用的IEC 61508 SIL 3和ISO 26262 ASILD。为了使安全关键型认证更经济实惠,设计者通常会保持这些系统的代码极其简单(因此有可能从数学上证明系统将稳定运行,不会出错),或者转向已经通过认证的商业RTOS解决方案,作为一个起点。威腾斯丁公司的SafeRTOS是FreeRTOS的衍生产品,已获得工业、医疗和汽车领域的认证。
中间件也可以是复杂系统中的一个极其重要的组成部分。中间件是运行在用户代码(你,应用程序员编写的代码)和较低层,如RTOS或裸机(无RTOS)之间的代码。付费解决方案的另一个价值主张是,生态系统提供了一套预集成的高质量中间件(如文件系统、网络堆栈、GUI框架、工业协议等),最大限度地减少了开发,降低了整体项目风险。使用中间件而不是自己开发的原因是为了减少内部开发团队编写的原始代码量。这既降低了风险,也减少了团队花费的总时间--因此,根据项目复杂性和进度要求等因素,这可能是一项值得的投资。
付费解决方案通常也会直接由固件供应商提供某种程度的客户支持。雇佣和保留工程师的成本很高。管理人员最害怕的莫过于走进一个满是工程师的房间,这些人正在为他们的工具而困惑,而不是为需要解决的真正问题而工作。有了专家的帮助,只需一封电子邮件或一个电话,就可以大大提高团队的生产力,从而缩短周转时间,使每个人的工作环境更加愉快。
FreeRTOS有付费的支持和培训选项,以及付费的中间件解决方案,这些都可以被整合。然而,也有开放源码和/或免费提供的中间件组件,其中一些将在本书中讨论。
什么这本书只涉及一个MCU模型上的一个RTOS?有几个原因,其中一个原因是我们要讲的大部分概念几乎适用于任何可用的RTOS,就像良好的编码习惯超越了你碰巧要编码的语言一样。通过专注于一个RTOS和一个MCU的单一实现,我们将能够更深入地探讨一些话题,而不是在尝试讨论所有的替代方案时才有可能。
FreeRTOS是最流行的用于MCU的RTOS实现之一,而且非常广泛。它已经存在了15年之久,并且已经被移植到几十个平台。如果你曾经与熟悉RTOS编程的真正的底层嵌入式系统工程师交谈过,他们肯定听说过FreeRTOS,而且很可能至少使用过一次。通过把注意力集中在FreeRTOS上,你将有能力迅速地把你的FreeRTOS知识迁移到其他硬件上,或者在情况需要时过渡到其他RTOS。
我们使用FreeRTOS的另一个原因?嗯,它是免费的! FreeRTOS是在MIT许可下发布的。
下面的图表显示了FreeRTOS在一个典型的ARM固件堆栈中的位置。堆栈指的是构成系统的所有不同层的固件组件,以及它们是如何堆叠在一起的。这里的用户是指使用FreeRTOS的程序员(而不是嵌入式系统的终端用户):
一些值得注意的项目如下:
偶尔,当有人第一次了解到实时操作系统这个术语时,他们会错误地认为实时操作系统是在嵌入式系统中实现实时行为的唯一方法。这当然是可以理解的(尤其是考虑到这个名字),但这与事实相去甚远。有时,最好把RTOS看作是一种潜在的解决方案,而不是用于一切的解决方案。一般来说,对于一个基于MCU的RTOS来说,要成为一个特定问题的理想解决方案,它需要有Goldilocks级别的复杂性--不要太简单,但也不要太复杂。
如果有一个极其简单的问题,例如监测两个状态并在它们同时出现时触发警报,那么解决方案可能是一个直接的硬件解决方案(例如一个AND门)。在这种情况下,可能没有理由使事情进一步复杂化,因为AND门的解决方案将是非常快的,具有高度的确定性和极端的可靠性。它也将需要很少的开发时间。
现在,考虑一下只有一两个任务需要执行的情况,如控制电机的速度和观察编码器以确保正确的距离被穿越。这当然可以用离散的模拟和数字硬件来实现,但有可配置的距离会增加一些复杂性。此外,调整控制环路的系数很可能需要调整电位器的设置(可能是针对每个单独的板子),按照今天的制造标准,这在某些或大多数情况下是不可取的。因此,在硬件解决方案方面,我们只能用CPLD或FPGA来实现运动控制算法和跟踪行走的距离。这恰好是一个非常合适的选择,因为它有可能小到可以装入CPLD,但在某些情况下,FPGA的成本可能是不可接受的。这个问题也是由MCU经常处理的。如果现有的内部资源不具备硬件语言或工具链所需的专业知识,那么裸机MCU固件解决方案可能是一个不错的选择。
假设问题更加复杂,例如控制几个不同执行器的设备,从传感器中读取数据,并将这些值存储在本地存储器中。也许该设备还需要坐在某种网络上,如以太网、Wi-Fi、控制器区域网络(CAN),等等。一TOS可以很好地解决这种类型的问题。事实上,有许多不同的任务需要完成,或多或少地相互异步,这使得我们很容易认为RTOS带来的额外复杂性将得到回报。实时操作系统帮助我们确保低优先级的、更复杂的任务,如网络和文件系统堆栈,不会干扰时间更紧迫的任务(如控制执行器和读取传感器)。在许多情况下,可能会有某种形式的控制系统,通常会从在明确的时间间隔内运行中受益,这是实时操作系统的优势。
现在,考虑一个与前面类似的系统,但现在有多种网络要求,例如为网页提供服务,处理复杂的企业环境中的用户认证,以及将文件推送到需要基于不同网络文件协议的各种共享目录。这种复杂程度可以用RTOS来实现,但同样,根据可用的团队资源,这可能最好留给完整的操作系统来处理(无论是RTOS还是通用的),因为许多所需的复杂软件堆栈已经存在。有时,可以采取多核方法,其中一个核心运行RTOS,另一个运行通用操作系统。
现在,可能很明显,没有确切的方法来确定哪种实时解决方案对所有情况都是正确的。每个项目和团队都有自己独特的要求、背景、技能组合和背景,为这个决定提供了舞台。选择一个问题的解决方案有很多因素;重要的是要保持开放的心态,选择在那个时间点上最适合你的团队和项目的解决方案。
全部0条评论
快来发表一下你的评论吧 !