3.2 嵌入式 Linux🐧
与 FreeRTOS 的精简、专一不同,嵌入式 Linux 系统是将功能强大、生态成熟的桌面级 Linux 系统,经过裁剪、定制和优化后,应用于嵌入式设备。它更像一个功能完备的用户系统而非专用系统,能够处理复杂的网络通信、华丽的图形界面以及海量的第三方应用,是构建功能复杂智能设备(如路由器、网络摄像头、智能家居中控)的主流选择。
嵌入式 Linux 其实有着大量的应用,典型的例子包括:
- 车载信息娱乐系统:几乎所有现代汽车的中控大屏,从导航、音乐到车辆设置,都运行着一个高度定制的嵌入式 Linux GUI 系统。
- 智能家居中控面板:墙上的智能开关面板、温控器等。
- 销售终端(POS 机):餐厅点餐、商场收银的触摸屏设备。
- 医疗设备:B 超机、监护仪等需要显示波形和图像的设备。
- 工业人机界面(HMI):工厂流水线上用于监控和操作机器的触摸屏。
- 智能家电:带有触摸显示屏的高端冰箱、洗衣机等。 虽然实际上这块已经开始有点脱离嵌入式的范畴,魔改安卓之类的东西开始映入眼帘了,不过这类与硬件强交互的环境还是有嵌入式 Linux 的一席之地的
系统组成:三位一体的启动流程
一个完整的嵌入式 Linux 系统由三个核心部分组成,它们像接力赛一样,协同工作,完成从上电到系统运行的全过程。
引导加载程序 (Bootloader)
- 这是系统上电后运行的第一段代码,是整个系统的 “点火器”。它最核心的任务是进行基础的硬件初始化(如 DDR 内存),然后将存储在闪存(Flash)中的 Linux 内核镜像 “搬运” 到内存(RAM)中,最后像交接权杖一样,跳转到内核的入口地址,将 CPU 的控制权交给内核。最流行和功能最强大的 Bootloader 当属 U-Boot。
Linux 内核 (Kernel)
- 内核是操作系统的核心,是整个系统的 “引擎与底盘”。它接管 CPU 后,会全面地初始化和管理所有硬件,并负责所有核心的底层工作,包括:进程调度、内存管理、设备驱动、提供系统调用接口、以及一个强大的网络协议栈。
根文件系统 (Root Filesystem)
- 如果说内核是引擎,根文件系统就是 “驾驶舱和车身”。它包含了运行一个 Linux 系统所需的所有用户态的东西:C 库、各种系统命令(如
ls
,cd
)、应用程序、配置文件以及设备节点等。内核启动的最后一步,就是挂载(mount)这个根文件系统,并运行其中的第一个用户进程 ——init
进程(通常是/sbin/init
)。这个init
进程是所有后续用户进程的 “始祖”。
- 如果说内核是引擎,根文件系统就是 “驾驶舱和车身”。它包含了运行一个 Linux 系统所需的所有用户态的东西:C 库、各种系统命令(如
内核裁剪与定制方法
与动辄数 GB 的桌面版 Linux 发行版不同,嵌入式设备的存储和内存资源有限,因此必须对内核进行精细的 “瘦身”,这个过程就是裁剪与定制。
这通常通过在内核源码目录下执行 make menuconfig
命令来完成。它会启动一个基于文本的菜单界面,像一份 “自助餐菜单”,允许开发者:
- 选择平台:指定 CPU 架构(如 ARM, MIPS, RISC-V)和具体的目标开发板。
- 勾选功能:根据应用需求,自由启用或禁用网络协议栈、文件系统支持、内核调试等功能。
- 定制驱动:只编入项目中实际用到的硬件的驱动程序,移除所有无关的驱动。
- 编译方式:可以将驱动和功能直接静态编译进内核(
<*>
),也可以编译成可动态加载的内核模块(<M>
),或完全禁用(< >
)。
精细的裁剪不仅能极大地减小内核体积、节省存储空间,还能减少不必要的驱动初始化时间,从而加快系统启动速度,并因移除了不必要的功能而提升系统的安全性。
嵌入式 Linux 下的设备驱动开发
在 Linux “一切皆文件” 的设计哲学下,编写设备驱动的本质,就是去实现一系列与某个设备文件(如 /dev/mydevice
)相关联的回调函数,将用户态的 open
, read
, write
等操作,与底层的硬件行为关联起来。
一个典型的字符设备驱动模块,其核心就是 “注册” 与 “注销”:
init
函数:在通过insmod
命令加载驱动模块时被调用。它负责向内核 “注册” 自己,告诉内核:“我来了,我能驱动一种新设备,请为我分配一个主 / 次设备号,并把这个file_operations
结构体和我关联起来。”exit
函数:在通过rmmod
命令卸载模块时被调用。它负责 “注销” 设备,清理所有资源,向内核说 “我走了”。file_operations
结构体:这是驱动的 “能力清单”。它是一个函数指针的集合,将标准文件操作(如.read
,.write
,.ioctl
)与我们自己编写的驱动函数一一对应起来。当应用程序对设备文件进行read()
操作时,内核就会通过这个结构体,最终调用到我们驱动里对应的my_driver_read()
函数。
嵌入式 Linux 系统的应用程序开发
得益于完整的操作系统支持和丰富的开源生态,在嵌入式 Linux 上开发应用程序的选择非常多。
图形用户界面(GUI)应用
对于需要人机交互界面的设备(如智能家居中控、工业 HMI),有多种成熟的图形框架可供选择。
- Qt:一个功能强大的 C++ 跨平台 GUI 框架,提供现代、流畅的 UI 控件和强大的功能(如网络、多媒体),支持硬件加速渲染,是嵌入式 GUI 领域的领跑者。
- GTK:另一个经典的开源 GUI 工具包,是 GNOME 桌面环境的基础,在嵌入式领域也有应用。
- 直接操作帧缓冲 (Framebuffer):对于一些简单的界面需求,可以绕开复杂的图形系统,像操作一块画布一样,直接向 Linux 的帧缓冲设备(
/dev/fb0
)写入像素数据来绘图。这种方式最底层,但也最轻量。
非 GUI 应用
大量的嵌入式 Linux 设备并没有屏幕,它们以后台服务的形式默默工作。
- 后台守护进程 (Daemon):这是最常见的应用形式。程序在后台持续运行,执行网络监听、数据采集、逻辑控制等任务。
- Shell 脚本:利用系统自带的 Shell 和各种命令行工具,可以编写强大的脚本,用于系统管理、自动化任务和快速原型开发。