3、核心通信协议(一):Modbus RTU 协议原理、寄存器映射、CRC校验
各位工程师朋友,咱们今天聊聊充电桩的“神经系统”——Modbus RTU协议。说实话,我入行那会儿,第一次调试充电桩,就是被这个协议给“教育”了一顿。当时桩子死活连不上后台,我折腾了一整天,最后发现是CRC校验码算错了。嗯,从那以后,我对这个协议就格外上心。
Modbus RTU在充电桩领域,可以说是“老黄牛”级别的存在。它简单、可靠、成本低,很多充电桩的主控板与充电模块之间,用的就是它。你想想看,一个充电桩里,可能有四五个充电模块,每个模块都要实时上报电压、电流、温度,主控板还要下发指令控制输出。这么多数据,全靠Modbus RTU在背后默默传递。
3.1 协议原理:主从问答,简单粗暴
Modbus RTU的核心思想,说白了就是“一问一答”。主设备(比如充电桩主控板)发出请求,从设备(比如充电模块)收到后,必须回复。没有主设备问,从设备绝对不能主动说话。这个规矩,我在项目中遇到过好几次有人想打破,结果就是总线冲突,数据全乱套。
一个完整的Modbus RTU报文,长这样:
| 地址码 (1字节) | 功能码 (1字节) | 数据区 (N字节) | CRC校验 (2字节) |
举个例子,主控板想读取1号充电模块的当前输出电压(寄存器地址0x0001),它会发:
01 03 00 01 00 01 CRC_H CRC_L
这里:
- 01:从设备地址,就是1号模块
- 03:功能码,表示“读取保持寄存器”
- 00 01:起始寄存器地址,从0x0001开始读
- 00 01:读取1个寄存器
- CRC_H CRC_L:校验码,后面细说
如果模块正常,它会回复:
01 03 02 0B B8 CRC_H CRC_L
其中02表示数据长度是2字节,0B B8就是电压值(十进制3000,代表300.0V)。
3.2 寄存器映射:充电桩的“内存地图”
寄存器映射,就是给每个数据分配一个固定的“门牌号”。主控板要知道,想读电压就去0x0001,想读电流就去0x0002。这个映射表,是充电桩厂家必须提供的核心文档。
我见过最坑的一次,是某厂家给的映射表里,把电压和电流的地址写反了。结果现场调试,主控板读到的“电压”其实是电流值,差点把充电模块烧了。所以,拿到映射表后,第一件事就是拿万用表实测验证。
一个典型的充电模块寄存器映射表,大概长这样:
| 寄存器地址 | 数据类型 | 描述 | 单位/说明 |
|---|---|---|---|
| 0x0000 | U16 | 模块状态 | 0=待机, 1=运行, 2=故障 |
| 0x0001 | U16 | 输出电压 | 0.1V/bit, 如3000=300.0V |
| 0x0002 | U16 | 输出电流 | 0.1A/bit, 如500=50.0A |
| 0x0003 | U16 | 模块温度 | 0.1℃/bit, 如450=45.0℃ |
| 0x0010 | U16 | 输出电压设定值 | 写操作, 0.1V/bit |
| 0x0011 | U16 | 输出电流设定值 | 写操作, 0.1A/bit |
3.3 CRC校验:数据完整性的“守门员”
CRC校验,是Modbus RTU协议里最容易被忽视,但又最关键的部分。为什么?因为充电桩工作环境恶劣,电磁干扰大。没有CRC,你收到的数据可能早就被“篡改”了。
CRC-16 Modbus的算法,其实不复杂。我直接给你看代码,这是我用了好几年的实现,没出过问题:
// 计算Modbus RTU CRC16
// 输入:数据指针,数据长度
// 输出:16位CRC值
uint16_t Modbus_CRC16(uint8_t *data, uint16_t len)
{
uint16_t crc = 0xFFFF; // 初始值
uint16_t i, j;
for (i = 0; i < len; i++)
{
crc ^= data[i]; // 异或数据字节
for (j = 0; j < 8; j++)
{
if (crc & 0x0001) // 检查最低位
{
crc >>= 1;
crc ^= 0xA001; // 多项式
}
else
{
crc >>= 1;
}
}
}
// 注意:Modbus RTU发送时,低字节在前,高字节在后
return crc;
}
这段代码的核心逻辑,就是逐字节异或,然后逐位处理。多项式0xA001是Modbus标准规定的,不能改。
接收端怎么校验?很简单:把收到的整个报文(包括CRC本身)重新算一遍CRC。如果结果是0,说明数据没问题。否则,直接丢弃,请求重发。
好了,关于Modbus RTU的核心三要素——协议原理、寄存器映射、CRC校验,我就讲到这里。下一节,咱们聊聊Modbus TCP,看看它和RTU有什么不同,以及怎么在充电桩远程运维中选型。