在嵌入式设备上使用 Protocol Buffers (Protobuf) 进行数据序列化和解析
Protocol Buffers (Protobuf) 是 Google 开发的二进制序列化格式,适合嵌入式设备上的数据交换,因为它高效、紧凑。但在资源受限的嵌入式系统(如 ARM-based MCU)上,标准 Protobuf 库可能太大(内存占用高),推荐使用轻量版如 **nanopb**(C 语言实现,易移植到 C++)。如果你的设备资源充足(如运行 Linux 的嵌入式板,如 Raspbe
在嵌入式设备上使用 Protocol Buffers (Protobuf) 进行数据序列化和解析
Protocol Buffers (Protobuf) 是 Google 开发的二进制序列化格式,适合嵌入式设备上的数据交换,因为它高效、紧凑。但在资源受限的嵌入式系统(如 ARM-based MCU)上,标准 Protobuf 库可能太大(内存占用高),推荐使用轻量版如 nanopb(C 语言实现,易移植到 C++)。如果你的设备资源充足(如运行 Linux 的嵌入式板,如 Raspberry Pi),可使用标准 Protobuf C++ 库。下面我详细介绍整个流程:从 proto 文件生成 C++ 代码,到交叉编译和移植。假设你的主机是 Linux(如 Ubuntu),目标设备是 ARM 架构(如 Cortex-M 或 Cortex-A)。如果设备是无 OS 的 MCU,优先 nanopb;否则用标准版。
1. 准备工作
- 安装 Protobuf 工具:
- 在主机上安装 Protobuf 编译器(protoc)。用包管理器:
或从 GitHub 下载源码编译(https://github.com/protocolbuffers/protobuf)。sudo apt update sudo apt install protobuf-compiler libprotobuf-dev # Ubuntu/Debian
- 在主机上安装 Protobuf 编译器(protoc)。用包管理器:
- 安装交叉编译工具链:根据目标设备架构安装 toolchain。例如,对于 ARM Cortex-A(如 Raspberry Pi):
对于 Cortex-M(如 STM32),用 arm-none-eabi-gcc(从 ARM 官网下载)。sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf - 选择 Protobuf 变体:
- 标准 Protobuf C++:适合有 OS 的设备,功能全但体积大。
- nanopb:推荐嵌入式无 OS 设备,轻量(几 KB),支持 C++ 包装。下载:https://github.com/nanopb/nanopb。
2. 编写 Proto 文件
创建一个 .proto 文件定义数据结构。例如,名为 message.proto:
syntax = "proto3"; // 或 proto2,根据需求
package mypackage;
message SensorData {
int32 temperature = 1;
float humidity = 2;
string timestamp = 3;
repeated uint8 raw_data = 4; // 支持重复字段
}
- 保存为
message.proto。这定义了一个消息结构,用于序列化/解析传感器数据。
3. 根据 Proto 文件生成 C++ 文件
使用 protoc 生成 C++ 头文件(.pb.h)和源文件(.pb.cc)。生成的代码包含序列化(Encode)和解析(Decode)函数。
-
标准 Protobuf 生成:
protoc --cpp_out=. message.proto- 输出:
message.pb.h和message.pb.cc。 - 在 C++ 代码中使用:
#include "message.pb.h" #include <fstream> // 用于文件 I/O 测试 int main() { mypackage::SensorData data; data.set_temperature(25); data.set_humidity(60.5); data.set_timestamp("2026-02-05"); // 序列化到字符串 std::string serialized; data.SerializeToString(&serialized); // 解析回来 mypackage::SensorData parsed; parsed.ParseFromString(serialized); // 输出 parsed.temperature() 等 return 0; }
- 输出:
-
nanopb 生成(推荐嵌入式):
- 下载 nanopb 并解压到本地目录(如 ~/nanopb)。
- 用 nanopb 生成器:
python ~/nanopb/generator/nanopb_generator.py message.proto- 输出:
message.pb.h和message.pb.c(C 风格,但易用 C++ 包装)。
- 输出:
- 在 C++ 代码中使用(需包含 nanopb 头文件):
#include "message.pb.h" #include <pb_encode.h> // nanopb 库 #include <pb_decode.h> int main() { SensorData data = SensorData_init_zero; data.temperature = 25; data.humidity = 60.5; uint8_t buffer[128]; pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); pb_encode(&stream, SensorData_fields, &data); // 序列化 // 解析 SensorData parsed = SensorData_init_zero; pb_istream_t istream = pb_istream_from_buffer(buffer, stream.bytes_written); pb_decode(&istream, SensorData_fields, &parsed); return 0; }
- nanopb 支持选项文件(.options)自定义字段大小,优化内存。
4. 交叉编译源码
将生成的 .pb.cc/.pb.c 和你的应用代码交叉编译成目标设备的可执行文件或库。假设项目目录有 main.cpp、message.pb.h、message.pb.cc。
-
标准 Protobuf 交叉编译:
- 下载 Protobuf 源码(https://github.com/protocolbuffers/protobuf),交叉编译库:
./configure --host=arm-linux-gnueabihf --prefix=/usr/arm-linux-gnueabihf # 调整为你的 toolchain make -j4 make install - 编译你的应用:
arm-linux-gnueabihf-g++ -o app main.cpp message.pb.cc -lprotobuf -pthread # 链接 Protobuf 库- 如果是静态链接:加
-static避免运行时依赖。
- 如果是静态链接:加
- 下载 Protobuf 源码(https://github.com/protocolbuffers/protobuf),交叉编译库:
-
nanopb 交叉编译:
- nanopb 无需编译库(纯头文件),只需包含其源文件。
- 编译应用:
arm-none-eabi-g++ -o app.elf main.cpp message.pb.c ~/nanopb/pb_encode.c ~/nanopb/pb_decode.c ~/nanopb/pb_common.c \ -I~/nanopb -mcpu=cortex-m4 -mthumb # 调整 CPU 架构- 对于 MCU,生成 .elf 或 .bin 文件,用于烧录。
-
常见优化:
- 用
-Os优化大小,-g0去除调试信息。 - 处理依赖:确保 toolchain 有标准库(如 newlib for bare-metal)。
- 测试:在主机上先用本地 g++ 编译运行,验证序列化/解析正确。
- 用
5. 移植到嵌入式设备
- 传输文件:用 scp/rsync 或串口工具(如 minicom)将编译好的二进制(app 或 app.elf)传到设备。
- 示例:
scp app root@192.168.1.100:/usr/bin/
- 示例:
- 运行:
- 有 OS 设备:SSH 登录,
./app执行。 - 无 OS MCU:用烧录工具(如 OpenOCD、ST-Link)上传 .bin/.hex 文件,重启设备。
- 有 OS 设备:SSH 登录,
- 调试:
- 用 GDB 交叉调试:
arm-linux-gnueabihf-gdb app+target remote :3333(需 OpenOCD server)。 - 监控内存:嵌入式上 Protobuf 序列化后数据紧凑,检查 buffer 大小避免溢出。
- 用 GDB 交叉调试:
- 注意事项:
- 资源限制:标准 Protobuf 需 ~100KB+ 内存;nanopb 只需几 KB。测试动态分配(避免在 MCU 上用 new)。
- 端序:Protobuf 是小端序,确保设备一致或用 htonl/ntohl 处理。
- 依赖:无 OS 设备避免 STL,用纯 C。
- 安全:序列化数据易篡改,添加校验和。
- 如果设备是特定平台(如 ESP32),用平台 SDK 集成(如 Arduino-Protobuf)。
这个流程适用于大多数嵌入式场景。如果你的设备具体型号(如 STM32F4),或遇到错误,提供更多细节我可以细化!
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)