为什么裸机开发人员转向操作系统
回顾“裸机时代”
我第一次知道嵌入式软件是在2008年左右,当时我是大二的,开始学习在51芯片上编程。因为我主修计算机科学,所以我的大部分程序都是在 PC 上执行的。看到程序在裸机板上运行是一种完全不同的体验,我仍然记得我的第一个自行车灯程序成功运行时的兴奋。然而,我写的裸机程序越多,我遇到的问题就越多。我总结如下:
并发
对于裸机程序,难免会有一个巨大的‘while(1)’循环,几乎包含了整个项目的所有事务逻辑。每个事务调用一个或多个延迟函数,它们在 CPU 运行延迟函数时串行执行,其余事务必须等待。这样一来,大部分CPU时间都浪费在了空循环上,并发性很低。
模块化
从软件项目的角度来看,在开发过程中始终强调高内聚、低耦合的原则。然而,裸机软件中的模块通常相互依赖严重,不便于设计低耦合的软件,这使得在裸机板上开发大型项目变得困难。例如:
- 如上所述,大多数函数都收集在一个巨大的“while (1)”循环中,并且难以划分模块。
- 再举一个例子,当涉及看门狗定时器时,开发人员必须小心使用延迟功能。如果延迟时间过长,主函数没有机会重置看门狗,那么在执行过程中就会触发看门狗。因此,对于裸机开发,即使调用延迟函数也有太多的事情需要考虑。项目越复杂,就越需要小心。
生态系统
许多高级软件组件必须依赖于较低级别操作系统的实现。例如:
- 我已经开发了一个基于‘FreeModbus’的开源项目,我计划移植到各种平台,甚至考虑到裸机板。但相对于适应不同操作系统的便利性,有些功能过于复杂,无法在所有裸机板上实现。另一方面,由于缺乏通用性,许多实现必须在不同的硬件平台上从头开始设计,这是一项无聊且耗时的任务。目前,我的 Modbus 堆栈实现仍然无法在裸机板上运行。
- Realteck、TI、联发科等大公司提供的很多WiFi软件开发包(SDK)只能在操作系统上运行。它们不公开固件的源代码供用户修改,因此您无法在裸机环境中使用它们。
实时
一些应用领域需要实时能力。在这种情况下,必须在特定时间触发软件的某些关键步骤。对于工业控制,机械设备必须按照预定的顺序和时间完成动作。如果不能保证实时性,就会引起故障,从而危及工人的生命。在裸机平台上,当所有的函数都被塞进一个大的“while(1)”循环中时,就不可能保持实时能力。
可重用性
可重用性直接取决于模块化。我相信没有人愿意一次又一次地做同样的工作,尤其是在编写代码时。但是在不同芯片的各种硬件平台上,相同的功能必须适应不同的硬件,其实现在很大程度上依赖于底层硬件。改造轮子是必然的。
操作系统的优势
我第一次使用这个操作系统大约是在 2010 年。 STM32 MCU 系列开始流行。凭借强大的功能,许多人在其上运行操作系统。我当时使用的是 RT-Thread 操作系统,其中有许多可用的、随时可用的组件。相比其他操作系统,我感觉更舒服,并且已经在上面开发了 10 年。
根据我的理解,我想谈谈操作系统的优势:
模块化
有了操作系统,整个软件就可以拆分成几个任务(称为线程),每个线程都有自己独立的执行空间。它们相互独立,提高了模块化。
并发
当一个线程调用延迟函数时,它会自动将CPU让给其他需要的线程,从而提高整个CPU的利用率,最终提高并发性。
实时
RTOS 的设计具有实时功能。每个线程都被分配了一个指定的优先级。更重要的线程被设置为更高的优先级,不太重要的线程被设置为更低的优先级。这样就保证了整个软件的实时性。
开发效率
操作系统提供统一的抽象接口层,便于可复用组件的积累,提高开发效率。
操作系统是一群软件极客的智慧结晶。许多常用的软件功能,如信号量、事件通知、邮箱、环形缓冲区、单向链表/双向链表等,都进行了封装和抽象,使这些功能随时可用。
Linux 和 RT-Thread 等操作系统为碎片化硬件实现了一组标准的硬件接口,称为设备驱动程序框架。因此,软件工程师只需专注于开发,不再需要关心底层硬件,也无需再造轮子。
软件生态系统
生态系统的丰富性带来了从量变到质变的过程。
操作系统的模块化和复用性的提升,让我们可以封装基于操作系统的、嵌入式友好的可复用组件,不仅可以在我们的项目中使用,还可以分享给更多有需要的嵌入式开发者——最大限度地发挥其价值软件。
我是一个开源极客,我在 GitHub 上开源了一些嵌入式软件。在创建开源软件之前,我很少和别人谈论我的项目,因为我认为由于人们使用不同的芯片或硬件平台,我的代码很难在他们的硬件上运行。有了操作系统,软件的复用性大大提高,很多专家可以就同一个项目相互交流。他们甚至来自不同的国家。这鼓励越来越多的人分享和谈论他们的项目。
嵌入式