嵌入式系统是一种将软件和硬件紧密结合的技术,首先我们要认识到,无论我们是专注于软件开发还是硬件开发,最终的目标都是为了更好的工作和职业发展。
根据企业的规模和需求,大公司更倾向于将职责分得更细,例如软件分为:驱动、应用和系统,有的还会有中间件;而小公司则希望你能够掌握更全面的技能,即一个人能够胜任多个职位的工作。
曾经有人对稚晖君所具有的技能做了总结,他的技能包括:
电子基础、电子元器件选型、电路原理图设计、高速电路 PCB 设计、电子元器件焊接技术、电路板调试、启动程序 UBOOT 裁剪移植、Linux 内核裁剪移植、文件系统、底层驱动程序(C语言、ARM 架构汇编、Linux 内核架构)、上层应用程序(C++、Qt、JAVA、Python等,深度学习,机器学习,OpenCV,神经网络,自然语言处理)、高等数学、线性代数、概率论、离散数学。
嵌入式的技能等级分为初级、中级和高级;但从工作内容上可以先分为两个方向:软件和硬件。在本文中,我们将探讨嵌入式软件工程师的学习路径,包括技能等级的划分和各方向的学习重点,以及如何根据个人的兴趣和职业规划来选择合适的学习路径。
嵌入式软件方向
在嵌入式软件工作的分类方法是多元和多样的。在这里,我们将简要介绍几种主要的分类方式:
1、根据代码面向的对象,嵌入式软件工作可以大致分为三大类:
2、从硬件使用的操作系统角度来分析,我们可以将其分为一下几类:
裸机 :直接在没有操作系统的硬件上进行编程,通常用于资源有限和对实时性要求高的系统。
RTOS(实时操作系统):例如FreeRTOS、RT-Thread、uCOS-III 等,这些系统提供了实时功能和简单的调度机制,常用于单片机开发。
Linux系统 :包括自定义裁剪的 Linux、Ubuntu、Raspberry Pi OS、Arch Linux ARM 等,这些系统通常运行在单板计算机(SBC:Single-Board Computer)上,提供了丰富的功能和强大的社区支持。
嵌入式相关的工作岗位描述,例如:
单片机工程师
嵌入式 Linux 软件工程师
Linux 驱动开发工程师
BSP 驱动开发工程师
嵌入式 QT 开发工程师
物联网开发工程师
通过了解嵌入式软件工作的这些分类,你可以更清晰地理解每个岗位的具体职责和要求。
接下来,我们就进入正题,说一下嵌入式工程师需要具备的开发技能,以及学习梯度。
1. 打好语言基础
在你着手学习嵌入式系统之前,首要任务是确立坚实的编程语言基础。
这一过程不仅仅涉及学习语法和编程技巧,更包括培养编程思维和逻辑分析能力。这个阶段为你建立了坚实的技术根基,为进一步的学习和发展奠定了基础。
同时随着学习的深入,除了C语言,你最好也有需要学 C++、Python、汇编。
库函数的使用 :学习常用库函数的使用和实现,理解库函数的工作原理。
数据类型 :深入理解基本数据类型和构造类型,“指针”没有谁能逃得过去。
关键字的使用和技巧 :熟悉C语言的关键字,并学会灵活运用它们来编写高效的代码。
调试方法和常见错误处理 :掌握基本的调试技巧,学会识别和处理常见的编程错误。
数据结构 :理解和掌握基本的数据结构,如栈、队列、链表和树,学会如何在实际项目中应用它们,比如链表其实可以是实现 RTOS 的一个基础的基础。
内存管理 :深入理解内存管理的基本原理和技术,学会编写内存安全的代码。
书籍:《C程序设计语言》、《数据结构与算法分析--C语言描述》
网站:C语言中文网(一个提供 C/ C++学习资源的网站,可以帮助你查漏补缺)
一旦你掌握了编程语言的基础,接下来的学习重点将是嵌入式 CPU 和开发平台的相关知识。
在这个阶段,你将学习如何使用C语言来控制硬件,并深入理解硬件的工作原理。此外,现在以及未来,RISC-V 架构正在逐渐崭露头角,并有望在某些领域取代 ARM。因此,我强烈建议你早日开始学习 RISC-V,以跟上这一潮流。
这个阶段的学习将为你提供更深入的硬件编程技能,这对于嵌入式系统开发至关重要。此外,了解不同的处理器架构也将有助于你在未来选择最合适的工具和平台,以满足不同项目的需求。
体系架构 :深入理解 ARM 和 RISC-V 的体系架构,学会如何在这些平台上进行编程。
工作模式和异常处理 :理解不同的工作模式和异常处理机制,学会如何编写稳定和高效的代码。
寄存器操作和汇编编码 :学会进行寄存器操作和汇编编码,理解它们在硬件控制中的重要性。
硬件驱动编写 :学会编写各种硬件驱动,如 GPIO、RTC、中断、TIMER、DMA、USART、I2C、SPI、LCD、ADC/DAC、WDG、SDIO、I2S、ETH、CAN 等,理解它们在嵌入式系统中的应用。
书籍:《ARM嵌入式系统开发--软件设计与优化》、《STM32 HAL库开发实战指南--基于野火F4系列开发板》
进入这一阶段,你已经具备了一定的基础知识和实践经验。现在是时候开始学习更高级的概念和技术,以帮助你成为一名中级嵌入式工程师。
在你有了裸机编程的经验,在工作和学习中,你可以会发现:大部分的物联网芯片、模块都是在使用 RTOS 的,比如:
ESP8266、ESP32 他们乐鑫的都在使用 FreeRTOS;
Cat4 里面的合宙他们也有自己的 LuatOS;
STM32、NXP 和 GD 之类的单片机可以使用 RT-Thread、Tencent OS。
这么多的 RTOS,我们是否需要每个都去学一遍?其实不需要,这个阶段,你可以开始学习 RTOS 的基本概念和原理。掌握了这些,就万变不离其宗了。
以下是你需要掌握的核心要点:
动态内存堆的使用 :理解和掌握动态内存堆的使用和管理。
线程创建与实例 :学会创建和管理线程,理解线程的轮询调度和临界区保护。
信号量和互斥量 :理解信号量和互斥量的工作原理,学会使用它们解决生产消费者问题和线程优先级翻转问题。
消息机制 :掌握邮箱和消息队列的使用,理解它们在线程通信中的作用。
软件定时器和内存池 :学会使用软件定时器和内存池,理解它们在资源管理中的重要性。
在 RTOS 的基础上,你可以进一步学习 Linux 系统的构建和管理。
以下是你需要掌握的核心要点:
交叉编译链的安装和使用 :理解交叉编译链的工作原理,学会安装和使用交叉编译链进行项目开发,这样你才能在比如 x86 架构下的 PC 编译 ARM 架构的程序。
uboot 和内核编译 :学会编译和裁剪 uboot 和 Linux 内核,理解它们在系统启动中的作用,同时你也会明白比如修改开机动画的方法。
根文件系统的制作 :学会制作根文件系统,理解不同工具(如 Buildroot、Openwrt、Yocto、BusyBox)的使用和特点,因为 Linux 可以是一切皆文件,所有文件系统的构建,以及在构建过程的设置,在这里就尤为重要,比如你的系统要如何支持 Python 语言。
书籍:《RT-Thread内核实现与应用开发实战指南》、《构建嵌入式Linux核心软件系统实战》
当你准备进阶学习嵌入式 Linux 系统开发时,你需要熟悉 Linux 环境下的开发工具和技术。
以下是你需要掌握的核心要点:
Linux 系统安装和基本命令 :学会安装 Linux 系统和使用常用的命令。
VI 编辑器和 GCC :掌握 VI 编辑器的使用和 GCC 的编译与连接技术。
Makefile 和 CMake 编写 :学会编写 Makefile 和 CMake 文件,掌握如何通过他们,实现项目的构建、编译和运行,其中 CMake 因为跨平台这个特性,现在是越来越多的开源项目都在使用它,而不是直接写 Makefile。
gdb 调试工具和 shell 编程 :学会使用 gdb 进行程序调试和编写基本的 shell 脚本。
企业C语言软件开发规范和标准 :理解和掌握企业级C语言软件开发的规范和标准。
VI 使用的书籍推荐《简明 VIM 练级攻略》陈皓 (R.I.P)
Makefile 使用的书籍推荐《跟我一起写Makefile》陈皓(R.I.P)
Linux基础入门:C语言中文网
随着你对 Linux 环境和工具的深入了解和熟悉,你即将步入一个新的学习阶段,专注于 Linux 环境下高效的应用程序开发。这一阶段的学习内容是多元化的,涵盖了多进程、多线程、网络编程、GUI 设计以及数据库编程等多个重要领域。
在当前的技术背景下,Linux 开发主要集中在应用开发领域,这是因为应用场景丰富多样,同时也存在着大量的需求。此时,你正处于一个知识融汇和实践的阶段,你所学到的前面的各种知识将在这里得到综合应用和实践。
例如,你可能需要设计一个系统,该系统能够接收外部数据,并通过 GUI 实时显示这些数据。
在这个过程中,你可能需要利用多进程或多线程通信技术来实现数据的实时传输和处理。同时,你还需要掌握如何将这些数据存储到数据库中,以便记录和跟踪系统的状态和变化
系统编程 :深入理解信号、系统调用、管道、FIFO、消息队列、共享内存等核心概念。
文件IO编程 :掌握文件描述符、文件读写接口、原子操作、阻塞与非阻塞IO等技术。
多任务和多进程编程 :学习进程表示、用户表述、fork与vfork、多线程概念、线程同步等技术。
网络编程 :掌握网络基本概念、套接口编程、网络字节序、Client、Server 结构、UDP 编程等。
数据库 :SQLite3 是一个非常受欢迎和常用的嵌入式数据库解决方案,它因其轻量级和高效性而被广泛采用。
GUI 开发环境搭建 :学习如何搭建 GUI 开发环境,例如 QT、LVGL、AWTK 等。
资源文件与布局管理 :理解资源文件的管理和布局的基本概念。
UI 常用控件编程 :学习如何使用和定制 UI 的常用控件。
消息机制 :理解消息机制的工作原理和应用。
异步和多线程 :掌握如何在 GUI 编程中使用异步和多线程技术。
网络编程 :学习如何在 GUI 应用中实现网络功能。
书籍:《UNIX环境高级编程》、《Unix网络编程》。
在你掌握了 Linux 应用程序开发的技术后,你可以进一步学习 Linux 设备驱动程序的开发。这一阶段的学习将涵盖底层硬件控制和驱动开发的核心技术。
实际上,在这里我想分享一些个人关于驱动开发和内核开发的职业道路的见解。
因为很多嵌入式的同学都是从裸机单片机这个阶段,进阶到 Linux 的,所以理所当然的认为,比起应用开发学习的内容,驱动开发可能会更容易些。虽然网络上有大量的资源和机会可以探索这些领域,但如果你不是在芯片原厂工作,这条路径可能对个人技术的提升有一定的限制。
事实上,除非你是在芯片原厂从事开发工作,否则你可能会发现,无论你的技术水平提高到什么程度,最终达到的高度和见识甚至都可能无法与原厂的 FAE 相媲美。原厂的开发和 FAE 通常具有更丰富的经验和更深入的理解,他们的知识储备和见识往往是通过长期累积和实践得来的。
因此,当你考虑职业发展和技术提升时,也许可以思考如何找到一个能够充分发挥你技能和知识的平台,同时也能为你提供更多学习和成长的机会。
当然了解驱动开发和内核开发仍然是重要的,因为在某些情况下,特别是在小型公司或初创公司,可能会要求你具备多方面的技能。对这些领域的了解不仅可以帮助你胜任工作,还可以提高你对嵌入式 Linux 开发的全面理解,从而更好地应对不同的工作需求。
这种多面性有助于你更好地适应不同的工作环境和项目,为你的职业生涯增加更多的机会和灵活性。
什么是内核模块 :理解内核模块的概念和作用,学习如何编写和加载内核模块。
高级IO操作 :深入学习高级 IO 操作的技术和应用。
中断和时间管理 :掌握中断处理和时间管理的基本技术。
互斥与同步 :学习如何在驱动开发中使用互斥和同步技术。
内存和DMA使用 :理解内存和 DMA 的管理和使用技术。
Linux 设备设备树 :学习设备树的概念和应用。
各种设备驱动开发 :掌握字符设备驱动、总线类设备驱动、块设备驱动、网络设备驱动等的开发技术。
内核调试技术 :学习使用各种内核调试工具和技术。
书籍:《Linux设备驱动程序》、《嵌入式Linux驱动开发教程》。
经过前面的学习和准备,你现在已经具备了嵌入式开发的基本技能。现在,你已经进入到项目实践阶段,这是一个验证和展示你所学知识应用能力及解决实际开发问题能力的时期。你可以选择从多个方向进行实践,包括但不限于物联网、机器人、音视频和 AI 方向。
额外提示,在项目实践过程中,你将遇到许多之前未曾接触过的传感器、操作系统和技术。例如:
物联网方向 :你可能会遇到 BLE、Mesh、Wi-Fi、Lora、NB-IOT、CAT4.0 等技术。你需要学会如何与这些模块通信,如何基于厂家的 SDK 进行二次应用开发,以及如何进行程序烧录和测试。
机器人方向 :你将需要学会区分不同种类的电机,并掌握电机控制技术。此外,你还需要理解和掌握 ROS 和 ROS2 的开发技术。
音视频方向 :你需要深入了解各种音频编解码协议,并学会如何处理相关数据。
AI 方向 :你将需要学会如何训练模型、调整参数,并学会如何将训练好的模型部署到嵌入式设备上。
在这个阶段,你可能会遇到很多从未听说过的概念和技术,这可能会让你感到不适或困惑。但请记住,知识可以分为两类:一类是你已经知道的,另一类是你知道在哪里可以找到答案和资源。在面对未知时,不要害怕寻求帮助和使用各种资源来扩展你的知识库。
在嵌入式工程师的成长道路上,我们需要的不仅仅是技术的积累和深化,更需要一个开放和探索的心态。正如稚晖君所言:
我们不能局限于自己的专业领域,而应该积极探索和学习新的技术和领域。同时,也要学会正确地利用各种资源和工具,提高我们解决问题的能力。我们所追求的不仅仅是技能的掌握,更是一种以问题为导向的学习方式。我们要学会在实践中不断寻找问题,然后再通过自学来寻找解决问题的方法和答案。只有这样,我们才能在嵌入式的世界里不断进步和成长,最终成为一名真正的专家。
笨鸟已经发布了两套高端教程:
C语言百万年薪修炼课程:https://www.54benniao.com/c_course/
Java 高薪就业课程:https://www.54benniao.com/java_course/