张银峰的编程课堂

与Modbus设备交换32位数据

基于Modbus的设备在发送多字节数据时,遵循以寄存器为单位的小端模式。

对接收到的数据0xAABBCCDD而言,在小端模式的桌面应用下,如果用2个uint16结构体接收并解析此数据流,结果如下:

struct Foo
{
    uint16 r1;
    uint16 r2;
};

char buffer[] = {0xCC, 0xDD, 0xAA, 0xBB};
struct Foo fo = *(struct Foo*)(buffer);

assert(fo.r1 = 0xDDCC);
assert(fo.r2 = 0xBBAA);

而如果用uint32接收,因为低位地址在前,结果如下:

uint32 r = *(uint32*)(buffer)
assert(r == 0xBBAADDCC);

显然这两种方式都没有获得正确的结果,要得到原数,就需要调节字节顺序。

// 将由Modbus转换而来的32位数,转换到本机表示。
inline uint32 SwapByteInt32(uint32 v)
{
    // BBAADDCC => AABBCCDD
    return ((v & 0xFF000000) >> 8) |
           ((v & 0x00FF0000) << 8) |
           ((v & 0x0000FF00) >> 8) |
           ((v & 0x000000FF) << 8);
}

同样,如果要向写入一个32位值给Modbus设置,也要合适的整理数据(这里值写入一个缓冲区):

void writeInt32(uint32 v)
{
    // AABBCCDD => [CC DD AA BB]
    buf[0] = (uint8)((v & 0x0000FF00) >> 8);
    buf[1] = (uint8)((v & 0x000000FF));
    buf[2] = (uint8)((v & 0xFF000000) >> 24);
    buf[3] = (uint8)((v & 0x00FF0000) >> 16);
}