巧妙利用结构体解析协议数据

巧妙利用结构体解析协议数据

预备知识

1. 大小端

STM32属于小端模式

小技巧:记住大端模式符合人的阅读习惯。

2. 位域

3. 结构体字节对齐

4. 联合体

实例一:根据电池BMS协议解析电池数据(小端模式)

这里的小端模式是指:对于超过一个字节的数据传输时,低位字节在前高位字节在后。

电池应答消息包含的电池数据

:这里只是为了说明,对协议内容进行了简化。

1. 电池状态信息

由3个字节组成:

  • 第1字节:
    • Bit0:充电标志,置 1 表示检测到充电电流。
    • Bit1:充电过流标志,置 1 表示检测到充电过流。
    • Bit4:放电标志,置 1 表示检测到有效放电电流。
    • Bit5:放电过流标志,置 1 表示发生放电过流。
    • Bit6:放电短路标志,置 1 表示发生放电短路。
  • 第2字节:
    • Bit0:电芯侦测线开路标志,置 1 表示检测到电芯侦测线开路。
    • Bit1:温感侦测线开路标志,置 1 表示检测到温感侦测线开路。
    • Bit4:电芯过压标志,置 1 表示电芯过压。
    • Bit5:电芯欠压标志,置 1 表示电芯欠压。
    • Bit6:总压过高标志,置 1 表示电池组总压过高。
    • Bit7:总压过低标志,置 1 表示电池组总压过低。
  • 第3字节:
    • 保留
2. 电流值
  • “电流值”为 16 位整型数(int16_t),单位为 0.1A,充电为正、放电
    为负。
3. 电芯串数
  • “电芯串数”为 8 位无符号整型数(uint8_t),表示当前 BMS 所管理
    的电芯串联数量。
4. 电芯电压
  • “电芯电压”为 16 位无符号整型数的数组,数组的元素个数由“电
    芯串数”指定。数组元素的所表示的单位为 mV。
5. 循环次数
  • 循环次数” 为 16 位无符号整型数(uint16_t),表示当前电池组
    己经过的充、放电次数。
6. 剩余电量
  • “剩余电量”为 16 位无符号整型数(uint16_t),单位为 0.1AH。
7. 总容量
  • “总容量” 为 16 位无符号整型数(uint16_t),单位为 0.1AH。
8. 开关状态
  • “开关状态”为 8 位无符号整型数(uint8_t),各 bit 意义如下:
  • Bit6:充电开关状态, 1 表示开关闭合,允许充电。
  • Bit7:放电开关状态, 1 表示开关闭合,允许放电。

根据电池应答消息格式定义电池数据结构

#define BATTERY_CELL_NUM 7 //7串电芯

#pragma pack(push)
#pragma pack(1)
typedef struct {
  union {
    struct {
      uint8_t charge_flag:1;                           //充电标志
      uint8_t charge_overcurrent_flag:1;               //充电过流标志
      uint8_t :2;                                
      uint8_t discharge_flag:1;                        //放电标志
      uint8_t discharge_overcurrnet_flag:1;            //放电过流标志
      uint8_t discharge_shortcircuit_flag:1;           //放电短路标志
      uint8_t :1;
    }bit;
    uint8_t byte;
  }status1;
  union {
    struct {
      uint8_t cell_detect_line_open_circuit:1;           //电芯侦测线开路标志
      uint8_t temp_sensor_detect_line_open_circuit:1;    //温感侦测线开路标志
      uint8_t :2;                                        
      uint8_t cell_overvoltage:1;                        //电芯过压标志
      uint8_t cell_undervoltage:1;                       //电芯欠压标志
      uint8_t overvoltage:1;                             //总电压过高标志
      uint8_t undervoltage:1;                            //总电压过低标志
    }bit;
    uint8_t byte;
  }status2;
//  uint8_t status1;
//  uint8_t status2;
  uint8_t status3;
  int16_t current;
  uint8_t cell_num;
  uint16_t cell_voltage[BATTERY_CELL_NUM];
  uint16_t cycles;
  uint16_t remaining_capacity;
  uint16_t total_capacity;
  //uint8_t switch_status;
  union {
    struct {
      uint8_t :6; //bit0-5
      uint8_t charge_switch_status:1; //bit6
      uint8_t discharge_switch_status:1; //bit7
    }bit;
    uint8_t byte;
  }switch_status;
}BatteryRawData_t;
#pragma pack(pop)

分析

  1. 通过接收到的电池报文数据,在符合包头、长度、校验等信息后便可以将对应字段的数据直接复制到BatteryRawData_t类型的结构体数据中,通过该结构体便可以直接获取需要的变量信息。这样的处理方式极大的简化了报文的解包处理。
  2. 当然这里的应用还有一个前提:超过1个字节的变量传输的时候是按照小端模式(低位字节先传输,高位字节后传输)进行传输的。如果当前协议不符合该格式,是不能够直接应用这种方式的。

实例二:根据电池BMS协议解析电池数据(大端模式)

这里的大端模式是指:对于超过一个字节的数据传输时,高位字节在前低位字节在后。

电池应答消息包含的电池数据

省略。。。

根据电池应答消息格式定义电池数据结构

#define BigtoLittle16(A)   ((((uint16)(A) & 0xff00) >> 8)    | \  
                            (((uint16)(A) & 0x00ff) << 8))

#define BATTERY_NTC_NUM 2

#pragma pack(push)
#pragma pack(1)

typedef struct {
  uint16_t voltage_bigendian;
  uint16_t current_bigendian;
  uint16_t remain_capacity_bigendian;
  uint16_t total_capacity_bigendian;
  uint16_t cycles_bigendian;
  uint16_t date_of_production_bigendian;
  uint16_t balance_status_low_bigendian;
  uint16_t balance_status_high_bigendian;
  uint16_t protect_status_bigendian;
  uint8_t software_version;
  uint8_t rosc;
  uint8_t fet_control_status;
  uint8_t cell_num;
  uint8_t ntc_num;
  uint16_t ntc_data_bigendian[BATTERY_NTC_NUM]; 
}BatteryRawData_t;
#pragma pack(pop)

使用

BatteryRawData_t battery_raw_data;
//假设电池数据已经存储到了battery_raw_data中

//获取原始的电压数据
uint16_t voltage_raw = BigtoLittle16(battery_raw_data.voltage_bigendian);

分析

这里同样可以使用结构体的方式来直接将电池反馈的报文数据的对应位置复制到相应的结构体变量中,但需要注意的时,结构体中的变量并不能直接使用,必须进行大端模式转换成小端模式才是正常的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值