STM32嵌入式平台移植Protobuf数据协议


前言

最近项目上有用到把传感器数据封装成Protobuf协议再上传到平台解析的需求,嵌入式这边用到的是SMT32L4平台,这就涉及到在STM32环境下移植和封装Protobuf协议了。之前使用过nanopb,nanopb是也是一个轻量的、支持C语言的Protobuf,但是使用过程极其麻烦,不同的数据有不同的处理方法,比如,string类型,分为固定长度和动态长度,不同的处理方法难度大不一样。后来使用protobuf-c翻译器成功实现了Protobuf封装协议和数据传输。
本文通过Protobuf封装数据,进行序列化之后,通过串口传到平台进行解析。


一、Protobuf简介

Protocol Buffers,是Google公司开发的一种数据格式,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。protobuf支持一些主流的语言,唯独没有支持C,所以诞生了第三方的protobuf-c。数据序列化协议用于将数据结构序列化成可方便存储、传输的格式,ProtoBuf是一个被广泛使用的序列化协议,它具有比json和xml体积小、使用方便、扩展性和兼容性好等特点。

二、使用步骤

2.1 Protobuf翻译器介绍

在这里插入图片描述

2.2 利用Protobuf.c编辑器生成.c和.h文件

将自己的.proto文件放在bin目录下,例如,我的.proto文件为lora.proto和mcs.proto。具体步骤如下:
在这里插入图片描述

注意:在命令行输入gen之后,有可能提示缺少.dll文件,这需要将该dll文件下载下来,在放入C:\Windows\System32中。
lora.proto和mcs.proto文件分别为:
lora.proto:

syntax = "proto3";
package proto;
option go_package = "./model/proto";
import "mcs/mcs.proto"; //引入的Data类型的结构体文件路径
message Sensor {
    string version = 1;                    // 协议版本,必填 v1 1.0
    MessageType  message_type = 2;         //消息类型,必填
    repeated SensorComponent type = 3;          // 传感器组成
    ProjectName name = 4;                   // 传感器名称,传感器型号和传感器名字至少填一个
    SensorModel model = 5;                  // 传感器型号, 传感器型号和传感器名字至少填一个
    string Sn = 6;                       // 传感器唯一标识,必填,只要可以唯一标识设备即可 3011310001 
    repeated SensorHealthStatus status = 7;    // 传感器状态,如果正常,不填写该字段
    int64  publish_time = 8;               //消息发布时间
    // 心跳包才发送
    string description = 9;              // 传感器描述
    double longitude = 10;                 // 经度
    double latitude = 11;                //纬度
    string software_version = 12;        // 传感器软件版本
    string hardware_version = 13;        // 传感器硬件版本
    // 数据包
    mcs.Data data = 14;                  // 数据信息
}
enum ProjectName {
    PROJECT_NAME_CUSTOM = 0;
    PROJECT_NAME_FQPL = 1;
    PROJECT_DLCGYMCS = 2;
}
enum SensorModel {
    SENSOR_MODEL_DEFAULT = 0;
    SENSOR_MODEL_MCS600 = 100;
    SENSOR_MODEL_MCS1000 = 110;
}
// 传感器类型
enum SensorComponent {
    SENSOR_TYPE_CUSTOM = 0;             // 自定义传感器
    SENSOR_TYPE_TEMPERATURE = 1;        // 温度传感器
    SENSOR_TYPE_HUMIDITY = 2;           // 湿度传感器
    SENSOR_TYPE_PRESSURE = 3;           // 压力传感器
    SENSOR_TYPE_LIGHT = 4;              // 光照传感器
    SENSOR_TYPE_CURRENT = 5;            // 电流传感器
    SENSOR_TYPE_VOLTAGE = 6;            // 电压传感器
    SENSOR_TYPE_POWER = 7;              // 功率传感器
    SENSOR_TYPE_ENERGY = 8;             // 电能传感器
    SENSOR_TYPE_POWER_FACTOR = 9;       // 功率因数传感器
    SENSOR_TYPE_POSITION = 10;          // 位置传感器
    SENSOR_TYPE_VELOCITY = 11;          // 速度传感器
    SENSOR_TYPE_MOTION = 12;            // 运动传感器
    SENSOR_TYPE_DISTANCE = 13;          // 距离传感器
    SENSOR_TYPE_ANGLE = 14;             // 角度传感器
    SENSOR_TYPE_ROTATION = 15;          // 旋转传感器
    SENSOR_TYPE_DIRECTION = 16;         // 方向传感器
    SENSOR_TYPE_ALTITUDE = 17;          // 海拔传感器
    SENSOR_TYPE_DEPTH = 18;             // 深度传感器
    SENSOR_TYPE_VOLUME = 19;            // 容量传感器
    SENSOR_TYPE_DENSITY = 20;           // 密度传感器
    SENSOR_TYPE_FORCE = 21;             // 力传感器,拉力应力等
    SENSOR_TYPE_ENERGY_STORED = 22;     // 储能传感器
    SENSOR_TYPE_FLOW = 23;              // 流量传感器
    SENSOR_TYPE_IMAGE = 24;             // 图像传感器
    SENSOR_TYPE_MAGNETIC = 25;          // 磁场传感器
    SENSOR_TYPE_INFRARED = 26;          // 红外传感器
    SENSOR_TYPE_COLOR = 27;             // 颜色传感器
    SENSOR_TYPE_SOUND = 28;             // 声音传感器
}
// 传感器状态
enum SensorHealthStatus {
    SENSOR_STATUS_CUSTOM = 0;                    // 自定义状态
    SENSOR_STATUS_LOW_BATTERY = 1;               // 低电量
    SENSOR_STATUS_NETWORK_WARNING = 2;           // 网络流量告警
    SENSOR_STATUS_TEMPERATURE_WARNING = 3;       // 温度告警
}
//消息类型
enum MessageType {
    HEARTBEAT = 0;//心跳
    DATA = 1;//数据
    CHECK_TIME = 2; //对时
}

mcs.proto文件:

syntax = "proto3";
package mcs;
option go_package = "./model/proto";
message Data {
    int64 sample_time = 1;         //采样时间
    float ground_current_a_amplitude  = 2;    //A相地线电流幅值
    float ground_current_a_phase = 3;  //A相地线电流相位
    float ground_current_b_amplitude  = 4;    //B相地线电流幅值
    float ground_current_b_phase  = 5;    //B相地线电流相位
    float ground_current_c_amplitude  = 6;    //C相地线电流幅值
    float ground_current_c_phase  = 7;    //C相地线电流相位
    float conductor_current_a_amplitude = 8; //A相芯线电流幅值
    float conductor_current_a_phase = 9; //A相芯线电流相位
    float conductor_current_b_amplitude = 10; //B相芯线电流幅值
    float conductor_current_b_phase = 11; //B相芯线电流相位
    float conductor_current_c_amplitude = 12; //C相芯线电流幅值
    float conductor_current_c_phase = 13; //C相芯线电流相位
}

2.3 Keil5配置与编写

在自己的工程目录下创建一个Protobuf文件夹:
在这里插入图片描述
将2.2第4步中生成的.c和.h文件以及2.1中protobuf-c文件夹中的protobuf-c.c和protobuf-c.h文件一起复制到Protobuf文件夹中。
打开MDK5:
1.按照如下步骤操作:
在这里插入图片描述

2.之后再加入路径:
在这里插入图片描述
3.添加头文件

#include "lora.pb-c.h"
#include "protobuf-c.h"
#include "mcs.pb-c.h"

4.再编译
5.程序编写

Proto__Sensor Sen = PROTO__SENSOR__INIT;
Proto__Sensor *msg = NULL;
Mcs__Data Data = MCS__DATA__INIT;
uint8_t sensor_pack_buffer[512];
uint32_t Sen_len;
static void init_data(Mcs__Data* p)
{
//	p->sample_time = (int)buf;
}
static void init_sensor(Proto__Sensor* p)
{
	p->version = "1.0";
	p->message_type = PROTO__MESSAGE_TYPE__DATA;
//	p->type = Type;
//	p->n_type = PROTO__SENSOR_COMPONENT__SENSOR_TYPE_CURRENT;
	p->name = PROTO__PROJECT_NAME__PROJECT_NAME_FQPL;
	p->sn = "3011310001";
	p->publish_time = (int)buf;
	
	p->data = &Data;

    int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_RTC_Init();

  while (1)
  {
    /* USER CODE END WHILE */
     init_data(&Data);
     init_sensor(&Sen);
     Data.ground_current_a_amplitude = 1.3;
	 Data.ground_current_a_phase = 2.4;
     Sen_len = proto__sensor__get_packed_size(&Sen);
	 proto__sensor__pack(&Sen,sensor_pack_buffer);
     printf(sensor_pack_buffer);
	 HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
}

2.4 结果与分析

2.4.1 Protobuf封装序列化之后结果(16进制hex)

在这里插入图片描述

2.4.2 hex数据解码结果

在这里插入图片描述

2.4.3 分析

通过解码发现,Protobuf封装的数据经过通信协议传输到平台与解码得到的数据一样,则Protobuf移植成功。

有需要Protobuf编译器或代码的朋友可私信联系我!

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值