目录
前言:
做嵌入式开发,如果没有好的框架以及架构,写出来的程序实时性以及扩展性不满足可维护性以及可移植性,那么程序写的就是失败的,所以强烈建议做嵌入式开发的朋友学习好的框架,学习架构知识!如果觉得认同,可以关注我,可以带你实现高级框架,优美的嵌入式系统框架!
另外,我的资源中上传了一本书:《从入职到架构师,嵌入式软件成长之路》,强烈建议下载阅读,学习如何更好的做架构设计!
正文:
在软件层面减少 CAN 通信的消息长度,核心思路是通过数据压缩、格式优化、冗余消除等手段,在不丢失关键信息的前提下,最大限度减少每帧数据的字节数。这不仅能降低总线负载,还能缩短传输时间,提升实时性。以下是具体实现方法:
一、数据类型优化:用最小存储单元表示信息
CAN 消息的每个字段应使用 “刚好满足需求” 的数据类型,避免冗余字节。
-
缩小数值类型
- 用
uint8_t代替uint16_t/uint32_t:如表示 0-100 的温度值(无需 32 位整数,1 字节足够)。 - 用有符号类型代替无符号类型:如表示 ±50 的偏差值,
int8_t(范围 - 128~127)比uint16_t更节省空间。 - 示例:
// 优化前:用4字节表示0-100的湿度值(冗余) uint32_t humidity = 65; // 优化后:1字节足够 uint8_t humidity = 65;
- 用
-
位域(Bit-fields)压缩状态信息
对开关量、枚举值等离散信息,用位域打包到 1-2 字节中,避免每个状态占用 1 字节。
示例:// 优化前:4个状态各占1字节(共4字节) uint8_t motor_running = 1; // 电机运行状态(0/1) uint8_t error_flag = 0; // 错误标志(0/1) uint8_t mode = 2; // 模式(0-3,2位足够) uint8_t sensor_state = 1; // 传感器状态(0-1) // 优化后:用1字节打包所有状态(共1字节) typedef struct { uint8_t motor_running : 1; // 1位(0/1) uint8_t error_flag : 1; // 1位(0/1) uint8_t mode : 2; // 2位(0-3) uint8_t sensor_state : 1; // 1位(0/1) uint8_t reserved : 3; // 预留3位(可扩展) } DeviceStatus; DeviceStatus status = {1, 0, 2, 1, 0}; // 总占1字节
二、数据编码:用高效格式替代原始数据
对连续量(如温度、电压)或复杂信息,通过编码压缩数据长度。
-
偏移 + 缩放(Offset-Scaling)
对有固定范围的物理量,用 “原始值 = (编码值 - 偏移) × 缩放因子” 转换,减少存储位数。
示例:表示 - 40~85℃的温度(精度 0.5℃)- 物理范围:-40℃ ~ 85℃ → 总跨度 125℃,按 0.5℃精度共需 250 个刻度(0~249)。
- 编码:用 1 字节(0~255)即可覆盖,原始温度 = (编码值 × 0.5) - 40。
// 温度值25.5℃ → 编码:(25.5 + 40) / 0.5 = 131 → 用1字节存储0x83 uint8_t encoded_temp = (temp + 40) / 0.5; float decoded_temp = encoded_temp * 0.5 - 40;
-
差分编码(针对周期性数据)
对周期性发送的连续量(如转速、位置),若相邻帧变化量小,仅传输与上一帧的差值(而非绝对值)。
示例:电机转速从 1000RPM 变为 1002RPM- 优化前:传输 1002(用 2 字节
uint16_t)。 - 优化后:传输 + 2(用 1 字节
int8_t,范围 - 128~127),接收端根据上一帧值还原。
- 优化前:传输 1002(用 2 字节
-
枚举映射(针对离散值)
对字符串或长枚举(如 “故障类型”),用 1 字节枚举值映射,而非传输完整字符串。
示例:// 优化前:传输"OVER_VOLTAGE"字符串(12字节) char error_str[] = "OVER_VOLTAGE"; // 优化后:用1字节枚举值映射 typedef enum { ERROR_NONE = 0x00, ERROR_OVER_VOLTAGE = 0x01, ERROR_OVER_CURRENT = 0x02, // ... 其他故障 } ErrorCode; ErrorCode error = ERROR_OVER_VOLTAGE; // 仅1字节
三、消息结构优化:减少冗余字段
通过合并消息、移除冗余标识,精简每帧的固定开销。
-
合并同类消息
将多个高频小消息合并为一帧,减少帧头(ID、控制位等)的重复开销(CAN 每帧固定开销约 13 字节,合并后帧头只算一次)。
示例:- 优化前:分别发送 “温度”(1 字节)和 “湿度”(1 字节),两帧总数据量 2 字节,总传输量 = 2×(13 + 数据)=2×14=28 字节。
- 优化后:合并为一帧(温度 + 湿度,共 2 字节),总传输量 = 13+2=15 字节,节省 46%。
-
复用 ID 传递上下文
CAN 的 ID 字段(标准帧 11 位,扩展帧 29 位)可复用为 “消息类型标识”,减少数据段中的 “类型字段”。
示例:- 优化前:数据段首字节表示消息类型(如 0x01 = 温度,0x02 = 湿度),再跟数据(总占 2 字节)。
- 优化后:用 ID 区分类型(如 ID=0x101 表示温度,ID=0x102 表示湿度),数据段直接放数值(仅 1 字节)。
-
移除固定默认值
若某字段多数情况下为默认值(如 “状态正常 = 0”),可省略该字段,接收端默认按 0 处理;仅当值为非默认时才传输。
示例:设备状态默认 “无故障”,仅当出现故障时,在消息中携带故障码(正常时不传输该字段)。
四、变长消息与按需传输:只传必要数据
根据实际需求动态调整消息长度,避免固定长度导致的冗余。
-
变长数据段(DLC 优化)
CAN 的 DLC(数据长度码)支持 1-8 字节(标准 CAN)或 1-64 字节(CAN FD),按需设置 DLC,不浪费字节。- 错误示例:无论数据长度,固定用 8 字节(如填充 0x00)。
- 正确做法:3 字节数据就设 DLC=3,减少 5 字节冗余。
-
事件触发传输(而非周期触发)
非关键状态(如设备在线标识)无需周期性发送,仅当状态变化时才传输(如从 “离线”→“在线” 时发送一次),减少无效数据。
示例:设备正常运行时不发送 “心跳”,仅在重启或故障恢复时发送一次 “上线通知”。
五、数据压缩算法:针对大数据块
对超过 8 字节的大数据(如固件升级、日志),用轻量级压缩算法减少分片数量。
-
RLE(Run-Length Encoding,行程编码)
适合重复数据较多的场景(如日志中的连续空格、固件中的 0x00 填充区),用 “值 + 重复次数” 表示连续序列。
示例:连续 5 个 0xAA → 编码为 0xAA + 0x05(2 字节,原始 5 字节)。 -
霍夫曼编码(Huffman Coding)
对频率高的值用短码表示(如传感器数据中常见的 “0” 用 1 位表示),适合非重复但分布不均的数据。
注意:嵌入式场景需预先生成编码表,避免实时计算开销。 -
自定义轻量化压缩
针对特定数据格式设计压缩规则,例如:- 日志数据:仅传输变化的字段,相同字段用 “占位符” 表示。
- 坐标数据:若 X/Y 坐标变化量小,仅传输低 12 位(舍弃高位冗余)。
六、协议层约定:减少解析开销
通过预先约定规则,避免在数据段中传输解析所需的额外信息。
-
预定义数据格式
收发双方预先约定消息 ID 对应的数据结构(如 ID=0x200 固定为 “温度 (1 字节)+ 湿度 (1 字节)+ 状态 (1 字节)”),无需在数据中包含字段标识(如 “温度:xx”)。 -
固定位置字段
将高频字段放在固定字节位置(如第 1 字节固定为 “命令码”),避免用 “键值对”(如 0x01 = 温度,0x02 = 湿度)浪费字节。
实例对比:优化前后的消息长度
以 “电机控制指令” 为例,原始消息结构:
ID=0x300,数据段(8字节):
[0x01] [0x00 0x04] [0x00 0x00 0x0F 0x40] [0x01]
↑ ↑ ↑ ↑
指令类型 转速(1024) 目标位置(100000) 使能标志
总数据量 8 字节,其中存在冗余(如转速用 2 字节但实际范围 0-2000,位置用 4 字节但实际范围 0-200000)。
优化后:
- 指令类型:用 ID 区分(ID=0x301 固定为 “电机控制”),数据段移除该字节。
- 转速:0-2000 → 用 1 字节(0-255)×8 缩放(255×8=2040 ≥2000)。
- 目标位置:0-200000 → 用 2 字节(0-65535)×3 缩放(65535×3=196605,接近 200000)。
- 使能标志:用 1 位(位域),与其他状态打包到 1 字节。
优化后数据段:
[0x80] [0x86 0x13] [0x01]
↑ ↑ ↑
转速(128×8=1024) 位置(0x1386=3206 → 3206×3=9618) 状态位域(含使能)
总数据量 3 字节,相比原始 8 字节减少 62.5%。
总结
软件层面减少 CAN 消息长度的核心是 “精准表达”:通过数据类型压缩、编码优化、结构精简等手段,在保证信息完整的前提下,剔除所有冗余字节。实际应用中需结合业务场景(如数据类型、更新频率、精度要求)选择合适的方法,同时确保收发双方的解析规则一致。优化后的消息不仅能降低总线负载,还能减少传输延迟,提升整个 CAN 网络的实时性。

被折叠的 条评论
为什么被折叠?



