基于 C++ 的 IEC60870-5-104 规约的主从站模拟数据通信

基于 C++ 的 IEC60870-5-104 规约的主从站模拟数据通信。包括了报文的组织和解析,以及主从站之间的通信流程。

1. 报文组织与解析

IEC60870-5-104 规约定义了多种类型的帧,包括 U 帧、S 帧和 I 帧。以下是一些关键的报文组织和解析函数。

1.1 U 帧组织

U 帧用于控制链路状态,例如启动和停止数据传输。

void buildUFrame(uint8_t* buffer, uint8_t controlByte) {
    buffer[0] = 0x68; // 启动字节
    buffer[1] = 0x04; // 长度
    buffer[2] = controlByte; // 控制字节
    buffer[3] = 0x00; // 保留字节
    buffer[4] = 0x00; // 发送序号
    buffer[5] = 0x00; // 接收序号
}

1.2 S 帧组织

S 帧用于确认接收到的 I 帧。

void buildSFrame(uint8_t* buffer, uint16_t sendSeq, uint16_t recvSeq) {
    buffer[0] = 0x68; // 启动字节
    buffer[1] = 0x04; // 长度
    buffer[2] = 0x01; // 控制字节
    buffer[3] = 0x00; // 保留字节
    buffer[4] = sendSeq & 0xFF; // 发送序号
    buffer[5] = recvSeq & 0xFF; // 接收序号
}

1.3 I 帧组织

I 帧用于传输应用层数据。

void buildIFrame(uint8_t* buffer, uint16_t sendSeq, uint16_t recvSeq, uint8_t* data, uint16_t dataLen) {
    buffer[0] = 0x68; // 启动字节
    buffer[1] = dataLen + 6; // 长度
    buffer[2] = (sendSeq >> 8) & 0xFF; // 发送序号
    buffer[3] = sendSeq & 0xFF;
    buffer[4] = (recvSeq >> 8) & 0xFF; // 接收序号
    buffer[5] = recvSeq & 0xFF;
    memcpy(buffer + 6, data, dataLen); // 数据
}

2. 主从站通信流程

主站和从站之间的通信流程包括启动链路、数据传输和停止链路。

2.1 主站启动链路

主站发送 STARTDT 帧,从站响应 STARTDT 帧。

void masterStartLink(uint8_t* buffer) {
    buildUFrame(buffer, 0x07); // STARTDT
}

void slaveRespondStartLink(uint8_t* buffer) {
    buildUFrame(buffer, 0x0B); // STARTDT 确认
}

2.2 主站发送总召唤命令

主站发送总召唤命令,从站响应总召唤命令。

void masterSendTotalCall(uint8_t* buffer) {
    uint8_t data[] = {0x65, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45};
    buildIFrame(buffer, 1, 0, data, sizeof(data));
}

void slaveRespondTotalCall(uint8_t* buffer) {
    uint8_t data[] = {0x65, 0x01, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45};
    buildIFrame(buffer, 1, 1, data, sizeof(data));
}

2.3 主站停止链路

主站发送 STOPDT 帧,从站响应 STOPDT 帧。

void masterStopLink(uint8_t* buffer) {
    buildUFrame(buffer, 0x13); // STOPDT
}

void slaveRespondStopLink(uint8_t* buffer) {
    buildUFrame(buffer, 0x23); // STOPDT 确认
}

3. 报文解析

解析从站发送的报文,提取数据。

void parseUFrame(uint8_t* buffer) {
    uint8_t controlByte = buffer[2];
    if (controlByte == 0x0B) {
        // 从站确认启动链路
    } else if (controlByte == 0x23) {
        // 从站确认停止链路
    }
}

void parseSFrame(uint8_t* buffer) {
    uint16_t recvSeq = (buffer[4] << 8) | buffer[5];
    // 处理接收序号
}

void parseIFrame(uint8_t* buffer) {
    uint16_t sendSeq = (buffer[2] << 8) | buffer[3];
    uint16_t recvSeq = (buffer[4] << 8) | buffer[5];
    uint16_t dataLen = buffer[1] - 6;
    uint8_t* data = buffer + 6;
    // 处理数据
}

4. 主从站模拟

模拟主站和从站之间的通信。

int main() {
    uint8_t masterBuffer[1024];
    uint8_t slaveBuffer[1024];

    // 主站启动链路
    masterStartLink(masterBuffer);
    // 从站响应启动链路
    slaveRespondStartLink(slaveBuffer);

    // 主站发送总召唤命令
    masterSendTotalCall(masterBuffer);
    // 从站响应总召唤命令
    slaveRespondTotalCall(slaveBuffer);

    // 主站停止链路
    masterStopLink(masterBuffer);
    // 从站响应停止链路
    slaveRespondStopLink(slaveBuffer);

    return 0;
}

参考代码 104规约C++实例,主从站模拟数据通信 youwenfan/contentalb/72801.html

通过以上代码,可以实现基于 IEC60870-5-104 规约的主从站模拟数据通信。

专注于matlab/simulink,电子电路,编程