一、嵌入式 C++ 概述
嵌入式 C++ 在嵌入式系统开发中占据着至关重要的地位。它是 C++ 的一个子集,由日本 CPU 大厂于 1996 年提出,目标是在保持 C++ 面向对象特性的同时,减小代码体积、提升执行效率并简化编译器。
在嵌入式系统开发中,嵌入式 C++ 发挥着重要作用。一方面,它继承了 C++ 的面向对象特性,使得开发者能够以更加模块化和可维护的方式进行编程。这对于大型嵌入式项目来说尤为重要,能够提高代码的复用性和可扩展性。
另一方面,嵌入式 C++ 通过去除一些昂贵的特性,如多重继承、虚拟基础类别、执行期型态讯息、新式 C++ 转型、mutable 型别、命名空间和异常处理等,减小了代码体积和运行开销。这对于资源受限的嵌入式设备来说是非常关键的,能够提高系统的性能和稳定性。
随着嵌入式开发领域使用 C++ 作为开发语言的公司和项目越来越多,嵌入式 C++ 为那些从桌面开发领域加入嵌入式开发阵营的程序员提供了一个熟悉的编程环境。同时,一些较新的操作系统如 eCos、Symbian 等都采用 C++ 编写,这也进一步证明了嵌入式 C++ 在嵌入式系统开发中的重要地位。
总之,嵌入式 C++ 在嵌入式系统开发中具有不可替代的作用,它既保留了 C++ 的面向对象优势,又适应了嵌入式系统的资源限制,为嵌入式开发提供了一种高效、可靠的解决方案。
二、嵌入式 C++ 的应用场景
(一)嵌入式系统领域
在消费电子设备方面,嵌入式 C++ 可用于开发智能手机的底层系统软件、高性能图形处理模块以及游戏引擎等。例如,某些手机游戏的核心渲染部分可能会使用嵌入式 C++ 编写,以实现流畅的游戏体验。在数字相机中,嵌入式 C++ 可用于实现复杂的图像处理算法、控制相机的硬件接口以及高效的图像存储和压缩功能。对于智能手表,它可以开发操作系统内核、低功耗蓝牙通信模块以及各种传感器驱动程序,在有限资源下实现丰富功能并保持长续航。
在工业自动化控制领域,可编程逻辑控制器(PLC)编程中,嵌入式 C++ 可用于开发高级控制算法和与外部设备的通信接口,实现复杂的运动控制算法,精确控制机器人手臂运动轨迹,或实时监测和控制工业生产过程中的参数。在工厂自动化系统中,它可以开发监控软件和数据采集模块,高效处理大量实时数据并与各种工业传感器和执行器通信,确保生产过程稳定高效运行。在智能电网设备方面,嵌入式 C++ 可实现高效的电力数据采集、分析和通信功能,为智能电网稳定运行提供支持。
在汽车电子系统方面,嵌入式 C++ 可开发车载娱乐系统的图形界面、音频处理和多媒体播放功能,实现高性能图形渲染和音频解码,为用户提供流畅娱乐体验。在发动机控制系统中,可实现复杂的燃油喷射控制、点火 timing 控制等关键功能,提高发动机性能和燃油效率。在自动驾驶系统中,可用于开发传感器融合算法、路径规划模块以及实时控制软件,处理大量传感器数据并实现实时决策。
(二)物联网设备领域
在智能家居设备方面,嵌入式 C++ 可开发智能音箱的语音识别和处理软件以及与其他智能家居设备的通信模块,实现高效音频处理和网络通信,快速响应用户指令并协同工作。用于智能冰箱、洗衣机、空调等家电的控制系统,实现智能化控制、远程监控和能源管理功能,提高使用便利性和节能效果。在智能门锁中,可开发安全认证和控制软件,实现高强度加密算法和可靠通信协议,确保安全性和稳定性。
在智能医疗设备方面,嵌入式 C++ 可用于开发心电图仪、血压计、血糖仪等医疗监测设备的软件,实现高效的数据采集、分析和传输功能,为医生提供准确诊断依据。开发远程医疗设备的通信软件和数据处理模块,实现稳定的网络通信和高效的数据压缩,确保远程医疗的实时性和可靠性。用于可穿戴医疗设备的软件,实现低功耗的数据采集和处理功能,为用户提供长期健康监测服务。
在智能城市设施方面,嵌入式 C++ 可用于开发智能交通系统的交通信号控制器、车辆识别系统和交通流量监测设备,实现高效的实时数据处理和通信功能,提高交通系统运行效率和安全性。开发智能路灯的控制系统,实现自动调光、故障检测和远程监控功能,实现高效能源管理和通信功能,降低城市照明能耗和维护成本。用于智能垃圾桶的传感器驱动程序和通信模块,实现自动满溢检测、垃圾分类识别和远程监控功能,提高城市垃圾处理效率和环保性。
三、嵌入式 C++ 的项目案例
(一)适合嵌入式的 C++ 开源项目
- Workflow
-
- Workflow 是搜狗的服务器引擎,每日处理超百亿请求,非常适合在嵌入式应用上实现网络的框架设计。
-
- 适用于嵌入式的特点:
-
-
- 支持多平台、多体系结构,除了常见的操作系统外,还可以在树莓派、国产龙芯处理器等不同体系结构上运行。
-
-
-
- 编译快,除 OpenSSL 以外不依赖其他库,不到一分钟即可编出一个可用的 lib。
-
-
-
- 体积小、支持编译裁剪,Kafka 协议默认不编译,还可裁剪其他不常用模块,库文件可缩小到 400k 左右。
-
-
-
- 运行时内存小、调度快,默认配置下,tutorial 下的 helloworld server 服务占用物理内存仅 3824kb。
-
-
-
- 自定义协议非常方便,社区活跃,项目负责人积极回复问题。
-
-
- 框架能做的事情:
-
-
- 轻松搭建 server,以 http server 为例,只需简单几行代码即可。
-
-
-
- 轻松高效发起客户端请求,支持多种协议,解决传统 C++ server 访问 mysql 时的问题。
-
-
-
- 可建构异步任务流,支持串联、并联、串并联组合体及复杂的 DAG 结构。
-
-
-
- 异步 IO,在 Linux 系统下可作为文件异步 IO 工具使用,性能超过标准调用。
-
-
-
- 通信与计算一体化,自动对任务进行调度,适合网络通信的重计算模块。
-
- 其他嵌入式 C++ 开源项目推荐
-
- CuTest:微小的 C 语言单元测试框,代码不到一千行。
-
- cmockery:谷歌 C 单元测试框架。
-
- googletest:谷歌 C++ 测试框架。
-
- znfat:振南 fat,国产嵌入式文件系统方案。
-
- libu:一个 C 语言写的多平台工具库。
-
- LWIP:小型开源的 TCP/IP 协议栈。
-
- SQLite:开源的嵌入式关系数据库。
-
- OpenBLT:开源引导加载程序。
-
- Linux Lab:Linux 内核实验室,基于 Docker/Qemu 的极速 Linux 内核学习、开发和测试环境。
-
- airkissOpen:腾讯 airkiss 协议解析库。
-
- nr_micro_shell:shell for MCU,单片机命令行交互。
-
- FlexibleButton:基于标准 C 语言的小巧灵活的按键处理库。
-
- mbedtls:开源、便携、易使用、可读且灵活的 SSL 库。
-
- mosquitto:开源的 MQTT 代理。
-
- inih:C 语言编写的 INI 文件解析器。
-
- QP:QP 实时嵌入式框架。
-
- MS-RTOS:Micro Safe RTOS。
-
- protobuf-c:protobuf-c。
-
- eepromfs:基于 EEPROM 的简易类文件的数据读写库。
-
- gear-lib:适用于 IOT / 嵌入式 / 网络服务开发的 C 库。
-
- mult_timer:Linux 下的超级精简的多重定时器。
-
- EFSM:基于事件驱动的有限状态机。
-
- GuiLite:大道至简 - 5 千行 / 仅头文件 / 全平台 GUI 库。
-
- yoxios:基于 Linux 开发的轻量级物联网系统和硬件平台。
-
- ToughGFX:C++ 编写的 GUI 软件框架。
-
- emwin:老牌 GUI 库。
-
- littlevGL:免费的开源图形库。
-
- 野牛 LittlevGL demo:基于野牛开发板的 LittlevGL demo 程序。
-
- MonoGUI:黑白图形用户接口系统。
-
- MiniGUI:快速、稳定、跨操作系统的 GUI。
-
- QT:跨平台的应用程序和用户界面框架。
-
- Gtk:用于创造图形用户接口的图形库。
-
- AWTK:ZLG 倾心打造的基于 C 语言开发的 GUI 框架。
-
- HomeAssistant:基于 Python 的智能家居开源系统。
-
- Domoticz:开源的智能家居系统。
-
- Kaa IoT Platform:功能丰富的开放和高效的物联网云平台。
-
- RT-Thread IoT SDK:基于 RT-Thread IOT 开发板的各类例程。
-
- qt_2019_ncov:基于 Qt/C++ 实现的新冠肺炎疫情监控平台。
-
- H7-TOOL_STM32H7_App:H7-TOOL 多功能开发工具。
-
- DAPLink/CMSIS DAP:调试器,集成下载、调试和 USB 虚拟串口。
-
- mcush:MCU shell。
-
- DoST:Linux 下开发 STM32。
-
- Crazepony:Crazepony 开源四轴飞行器。
-
- MiniQ:迷你四轴飞行器。
-
- LiPow-Firmware:基于 STM32G0 采用 USB type-C 供电的开源锂电池充电器。
-
- Avem:轻量级无人机飞控。
-
- SoftWareSerial:STM32 IO 口模拟实现软件串口程序。
-
- 串口 ISP 程序:stm32 串口 ISP 程序。
-
- DSO_Nano:手持示波器。
-
- DSView:跨平台的逻辑分析仪。
-
- MCU-Development:基于 51、430、STM32F10X、STM32F407X、T4MC123G 平台的各常见硬件模块 demo。
-
- Arduino:开源电子原型平台。
-
- EWAHBoolArray:bitmap 算法。
(二)学习嵌入式可以做的项目案例
- 智能超市管理系统
-
- 功能包括业务员登录、一维码扫描录入商品价格、二维码付钱或手动输入付钱、支持刷卡、支持本地数据库管理、支持商品价格调整等。
-
- 系统组成有服务器(fs4412 芯片目标板)、扫描器、手机及 PC(QT 界面编写)等。
- WiFi 智能小车机器人
-
- 涉及 Android 应用程序编写和嵌入式系统开发流程,需熟悉 C、C++、Linux 系统编译机制和脚本,以及安卓系统运作方式、API 接口等。
- 智能医疗云平台
-
- 采用先进的诊疗传感器采集患者信息,将数据传输给医疗终端设备,再发送到远程医疗服务器,患者可通过医疗终端查看医师反馈结果。
四、嵌入式 C++ 的开发工具推荐
(一)常用开发工具
- Visual Studio Code
-
- 特点:微软开发的开源代码编辑器,支持多种操作系统。具有轻量级、快速响应的特点,占用系统资源少,启动速度快。提供丰富的插件生态系统,可通过安装 C/C++ 插件获得智能感知的自动补全、代码调试、语法高亮等功能。支持自定义主题、快捷键等,满足开发者个性化需求。
-
- 优势:跨平台能力强,无论在 Windows、Linux 还是 Mac OS 上都能提供一致的开发体验。内置的侧边栏 Git 命令和强大的调试功能,方便团队协作和代码版本管理。对于嵌入式开发,可通过安装特定插件支持多种开发工具链,提高开发效率。
- Eclipse
-
- 特点:最初用于 Java 编程,现在可用于多种编程语言,包括 C/C++。是一个简单易用的开源软件,支持 Windows、Linux 和 Mac OS。具有庞大的社区,开发者在遇到问题时可以在网站上提交 Bug 并获取帮助。提供智能代码补全、Git 集成、跨平台支持等功能。
-
- 优势:支持静态代码分析,有助于提高代码质量。丰富的插件可扩展软件功能,如安装特定插件可将 Eclipse 打造成强大的嵌入式开发环境。其简单高效的项目管理和智能的代码编辑功能,能提高开发效率。
- NetBeans
-
- 特点:用 Java 编写的免费开源 IDE,支持多种操作系统。可以创建具有动态和静态库的 C/C++ 应用程序,允许从现有代码创建项目。具有丰富的插件集,可远程监控项目开发。提供简单高效的项目管理、智能的代码编辑和社区支持。
-
- 优势:跨平台的支持使得开发者可以在不同操作系统上无缝切换开发环境。丰富的插件集满足不同开发需求,提高开发效率。社区支持强大,开发者可以在社区中获取帮助和分享经验。
(二)在线编译器
- rextester.com
-
- 特点:相对专业的在线编译器,可以显示编译时间、运行时间、内存占用等信息。支持多种编程语言,C 语言可选择 gcc、clang、vc 等编译器。用户界面简洁明了,方便使用。
-
- 优势:无需安装和复杂配置,打开浏览器即可使用。对于初学者或者本地没有编译环境又想快速验证代码的情况非常实用。
- tutorialspoint.com
-
- 特点:是一款比较全面的在线工具,支持前端技术、文档编辑、在线编译等丰富的功能。其中 C 语言(GCC)在线编译器功能强大,若代码有错误会提示错误位置,方便开发者快速定位问题。
-
- 优势:功能全面,不仅可以进行在线编译,还提供了丰富的学习资源和工具。适合边学习边实践,提高学习效率。
五、如何学习嵌入式 C++
(一)基本数据类型
嵌入式 C++ 的基本数据类型包括整型、浮点型、字符型等。在学习过程中,需要了解不同数据类型的特点和用途。例如,整型用于表示整数,浮点型用于表示实数,字符型用于表示单个字符或 ASCII 码值。
同时,要掌握数据类型之间的转换方法。C++ 支持自动类型转换和明确类型转换。在实际编程中,可能需要将一种数据类型转换为另一种数据类型,以满足特定的需求。例如,可以将整数转换为浮点数,或者将字符型转换为整数。
(二)引用数据类型
在嵌入式 C++ 中,引用数据类型有常规键值对的无序对象、数组及函数等。Object 类存储该对象在栈中引用,真实数据存放在堆内存中。这意味着栈中存储了指针,指针指向堆中该实体的起始地址。
引用数据类型的特点是可以通过引用的方式来操作对象,避免了复制对象的开销。在学习过程中,需要了解引用的用法和与指针的区别。引用必须在定义的同时进行初始化,且在程序运行期间不能改变引用所指向的对象。而指针可以在任何时候进行赋值和改变指向。
(三)struct 用法
- 自然对界:在嵌入式 C++ 中,struct 是一种复合数据类型,其构成元素既可以是基本数据类型的变量,也可以是一些复合数据类型的数据单元。自然对界即默认对齐方式,是指按结构体的成员中 size 最大的成员对齐。例如,如果结构体中的最大成员是 int 类型,长度为 4 字节,那么结构体中的其他成员会按照 4 字节的单位进行对齐。
- 指定对界:一般地,可以通过使用伪指令#pragma pack (n)来改变缺省的对界条件,编译器将按照 n 个字节对齐。如果#pragma pack (n)中指定的 n 大于结构体中最大成员的 size,则其不起作用,结构体仍然按照 size 最大的成员进行对界。例如,当 n 为 4、8、16 时,其对齐方式均一样,sizeof(naturalalign)的结果都等于 12。而当 n 为 2 时,其发挥了作用,使得sizeof(naturalalign)的结果为 6。
在学习嵌入式 C++ 时,要掌握 struct 的用法,包括结构体的定义、成员变量的访问和初始化等。同时,要了解结构体的对齐方式,以便在编程中合理地安排结构体的成员,提高程序的性能和可维护性。
六、嵌入式 C++ 的特点
(一)与 C 语言对比的优势
C++ 在嵌入式开发中相比 C 语言具有多方面的优势。在面向对象编程方面,C++ 支持类、对象和继承等概念,这使得代码复用性更高,组织结构更加清晰。例如,在开发复杂的嵌入式系统时,可以通过定义不同的类来封装各种功能模块,提高代码的可维护性。同时,模板编程是 C++ 的一大特色,它使得代码可以更加泛型化,提升了复用性。例如,通过模板可以实现通用的数据结构和算法,适用于不同的数据类型,减少了重复代码的编写。
(二)嵌入式开发注意事项
- 类与对象:在嵌入式开发中,使用 C++ 类虽然带来了面向对象的好处,但也需要注意一些问题。因为 C++ 类需要额外的存储空间来保存虚函数表、对象成员等,所以在资源受限的嵌入式环境中,应尽量避免使用虚函数和多重继承,除非必要。这样可以减少内存占用,提高系统性能。
- RTTI 和异常处理:RTTI(Run-Time Type Information)在嵌入式系统中通常不使用,因为它会增加代码的体积和运行时开销。同样,虽然 C++ 的异常处理机制很方便,但在嵌入式开发中,为了减少代码开销,通常会关闭异常处理功能(通过编译选项 - fno-exceptions)。
- 动态内存分配:动态内存管理是 C++ 的优势,但在嵌入式系统中,内存紧张且通常没有内存管理单元(MMU)。因此,建议在嵌入式系统中尽量避免使用 new 和 delete,使用静态内存分配或预先分配好的内存池,以确保系统的稳定性和可靠性。
(三)常用技巧
- 使用结构体模拟寄存器:嵌入式系统需要操作硬件寄存器,可以通过结构体定义寄存器的布局。例如:struct GPIO{volatile uint32_t MODER;volatile uint32_t OTYPER;volatile uint32_t OSPEEDR;volatile uint32_t PUPDR;volatile uint32_t IDR;volatile uint32_t ODR;};#define GPIOA (*((GPIO*)0x40020000)),这样可以直接使用GPIOA.MODER = 0x1;来设置寄存器,提高了代码的可读性和可维护性。
- 模板的高效利用:模板可以减少代码重复,提高代码的泛型性。例如,可以通过模板实现一个通用的环形缓冲区:template<typename T, size_t N>class CircularBuffer{public:void put(T item){buffer[head] = item;head = (head +1) % N;}T get(){T item = buffer[tail];tail = (tail +1) % N;return item;}private:T buffer[N];size_t head = 0;size_t tail = 0;};,这个环形缓冲区可以用于不同的数据类型,提高了代码的复用性。
(四)编译器配置优化
- 编译器优化选项:在嵌入式开发中,代码大小和性能非常关键,可以通过编译器选项进行优化。例如,GCC 中的常用优化选项有 - O1、-O2、-O3,不同级别的优化可以在运行速度和代码大小之间进行权衡。-Os 是针对代码大小的优化,可以减少程序占用的存储空间。同时,-fno-exceptions 可以禁用异常处理,减少代码体积;-fno-rtti 可以禁用运行时类型识别,减少不必要的开销。
- 手动内存对齐:嵌入式系统中的某些硬件对内存对齐有要求,可以使用 alignas 关键字进行手动对齐。例如:alignas(4) uint32_t buffer[10];,这样可以确保数组 buffer 在内存中的存储地址是 4 的倍数,满足硬件的对齐要求,提高程序的性能。