一、协议转换核心架构
// 协议转换器数据结构定义
typedef struct {uint8_t modbus_addr; // Modbus从站地址uint8_t mb_func_code; // Modbus功能码uint16_t mb_start_addr; // Modbus起始地址uint16_t mb_data_count; // Modbus数据长度uint8_t iec103_type; // IEC103信息类型uint16_t iec103_addr; // IEC103信息地址uint8_t iec103_ctrl; // IEC103控制域
} ProtocolMapping;// 双缓冲队列结构
typedef struct {uint8_t rx_buffer[256]; // Modbus接收缓冲区uint8_t tx_buffer[256]; // IEC103发送缓冲区volatile uint16_t rx_len; // 实际接收长度
} DualBuffer;
二、关键功能实现
1. Modbus数据解析
// 解析Modbus RTU帧
int parse_modbus_frame(uint8_t *frame, uint16_t len, ProtocolMapping *map) {if(len < 5) return -1; // 最小帧长度验证map->modbus_addr = frame[0];map->mb_func_code = frame[1];if(map->mb_func_code != 0x03 && map->mb_func_code != 0x04) return -2; // 仅支持读线圈/寄存器map->mb_start_addr = (frame[2]<<8) | frame[3];map->mb_data_count = (frame[4]<<8) | frame[5];return 0;
}
2. IEC103帧构建
// 构建IEC103启动帧
void build_iec103_start(uint8_t *buf) {buf[0] = 0x68; // 启动字符buf[1] = 0x02; // 控制域:U帧buf[2] = 0x01; // 地址域buf[3] = 0x01; // 地址域buf[4] = 0x68; // 启动字符
}// 添加信息元素
void add_iec103_element(uint8_t *buf, uint8_t type, uint16_t addr, uint8_t *data, uint16_t len) {buf[0] = type; // 信息类型(如0x01=单点信息)buf[1] = (addr>>8); // 地址高字节buf[2] = addr&0xFF; // 地址低字节memcpy(buf+3, data, len);
}
3. 协议转换核心逻辑
void protocol_convert(uint8_t *modbus_rx, uint16_t modbus_len, uint8_t *iec103_tx, uint16_t *iec103_len) {ProtocolMapping map;if(parse_modbus_frame(modbus_rx, modbus_len, &map) < 0) return;// 构建IEC103帧头build_iec103_start(iec103_tx);// 数据映射处理switch(map.mb_func_code) {case 0x03: // 读线圈add_iec103_element(iec103_tx, 0x01, map.mb_start_addr, modbus_rx+6, map.mb_data_count);break;case 0x04: // 读寄存器add_iec103_element(iec103_tx, 0x03, map.mb_start_addr, modbus_rx+6, map.mb_data_count*2);break;}// 添加CRC校验uint16_t crc = crc16(iec103_tx, *iec103_len);iec103_tx[(*iec103_len)++] = crc&0xFF;iec103_tx[(*iec103_len)++] = (crc>>8)&0xFF;*iec103_len += 4; // 添加帧尾
}
三、通信接口实现
1. 串口配置(RS-485)
// 串口初始化(Linux示例)
int init_serial_port(const char *device) {int fd = open(device, O_RDWR | O_NOCTTY);if(fd < 0) return -1;struct termios opts;tcgetattr(fd, &opts);cfsetispeed(&opts, B9600);cfsetospeed(&opts, B9600);opts.c_cflag |= (CLOCAL | CREAD);opts.c_cflag &= ~PARENB; // 无校验opts.c_cflag &= ~CSTOPB; // 1位停止位opts.c_cflag &= ~CSIZE;opts.c_cflag |= CS8; // 8位数据tcsetattr(fd, TCSANOW, &opts);return fd;
}
2. 双工通信处理
// 多线程通信处理
void *modbus_rx_thread(void *arg) {int fd = *(int*)arg;uint8_t rx_buf[256];while(1) {int len = read(fd, rx_buf, sizeof(rx_buf));if(len > 0) {uint8_t tx_buf[256];uint16_t tx_len = 0;protocol_convert(rx_buf, len, tx_buf, &tx_len);write(iec103_fd, tx_buf, tx_len);}}
}
四、关键算法实现
1. CRC-16校验(Modbus标准)
uint16_t crc16(uint8_t *buf, uint16_t len) {uint16_t crc = 0xFFFF;for(int i=0; i<len; i++) {crc ^= (uint16_t)buf[i] << 8;for(int j=0; j<8; j++) {if(crc & 0x8000) crc = (crc << 1) ^ 0xA001;else crc <<= 1;}}return crc;
}
2. 数据对时同步
// IEC103时钟同步实现
void sync_iec103_time(uint8_t *buf) {time_t now = time(NULL);struct tm *tm = localtime(&now);buf[0] = 0x68; // 启动字符buf[1] = 0x14; // 控制域:总召唤buf[2] = 0x01; // 地址域buf[3] = 0x01; // 地址域// 时间数据填充(BCD码)buf[4] = (tm->tm_year%100)/10 + 0x30;buf[5] = tm->tm_year%10 + 0x30;// ... 其他时间字段填充// 添加CRC校验uint16_t crc = crc16(buf, 10);buf[10] = crc&0xFF;buf[11] = (crc>>8)&0xFF;
}
参考代码 协议转换器,modbus转103协议 www.youwenfan.com/contentcnj/72685.html
五、工程实现要点
-
内存管理 使用环形缓冲区处理连续数据流 动态内存分配需考虑嵌入式系统限制
-
异常处理
void handle_protocol_error(uint8_t error_code) {switch(error_code) {case 0x01: // 功能码错误send_iec103_alarm(0x0101);break;case 0x02: // 地址错误send_iec103_alarm(0x0102);break;} }
-
性能优化 使用DMA传输减少CPU负载 开启硬件CRC加速(如STM32的CRC模块)
六、测试方案
-
功能测试矩阵
测试项 输入Modbus帧 预期IEC103输出 读线圈(03) 01 03 00 00 00 01 84 0A 68 02 01 01 68 01 01 00 00 00 01 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00