#include "modbus_rtu_master.h" MODBUS_MASTER mod_master; void modbus_rtu_master_init(void) { mod_master.target_id = 0x00; mod_master.command_code = 0x00; mod_master.start_address = 0x0000; mod_master.register_num = 0x0000; mod_master.crc16 = 0x0000; mod_master.byte_num = 0; memset(mod_master.data_tx_value, 0, TX_DATA_MAX); memset(mod_master.data_tx, 0, TX_BUFF_MAX); memset(mod_master.data_rx, 0, RX_BUFF_MAX); mod_master.data_tx_len = 0; mod_master.data_rx_len = 0; mod_master.rx_error_message = RX_ERROR_NONE; mod_master.tx_error_message = TX_ERROR_NONE; mod_master.timeout = 1000; mod_master.rx_flag = RX_NONE; mod_master.tx_flag = TX_NONE; memset(mod_master.result_display, 0, sizeof(mod_master.result_display)); } void modbus_rtu_master_load(void) { mod_master.data_tx[0] = mod_master.target_id; mod_master.data_tx[1] = mod_master.command_code; memset(mod_master.data_rx, 0, sizeof(mod_master.data_rx)); mod_master.tx_error_message = TX_ERROR_NONE; switch (mod_master.data_tx[1]) { //读四种寄存器的格式一致 case ReadCoilState: { //注释break,直接向下穿透 } //break; case ReadDisInputState: { //注释break,直接向下穿透 } //break; case ReadHoldReg: { //注释break,直接向下穿透 } //break; //【从站地址】【功能码】【起始地址高】【起始地址低】【数量高】【数量低】【CRC16校验低】【CRC16校验高】 case ReadInputReg: { mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8); mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF); mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8); mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF); mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6); mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF); mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8); mod_master.data_tx_len = 8; } break; //【从站地址】【功能码】【地址高】【地址低】【标志位高】【标志位低】【CRC16校验低】【CRC16校验高】 //标志位0xFF00表示ON,0x0000表示OFF,其他所有值均视作无效 case WriteSingleCoil: { mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8); mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF); mod_master.data_tx[4] = (mod_master.data_tx_value[0] == 0xFF)?(0xFF):(0x00); mod_master.data_tx[5] = 0x00; mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6); mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF); mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8); mod_master.data_tx_len = 8; } break; //【从站地址】【功能码】【地址高】【地址低】【数据高】【数据低】【CRC16校验低】【CRC16校验高】 case WriteSingleReg: { mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8); mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF); mod_master.data_tx[4] = mod_master.data_tx_value[0]; mod_master.data_tx[5] = mod_master.data_tx_value[1]; mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6); mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF); mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8); mod_master.data_tx_len = 8; } break; //【从站地址】【功能码】【起始地址高】【起始地址低】【数量高】【数量低】【写入字节数n】【写入值1】...【写入值n】【CRC16校验低】【CRC16校验高】 case WriteMultiCoil: { if( mod_master.register_num % 8 ) { //线圈数量不为8的倍数时,字节数 == (线圈数量/8 + 1) if( (mod_master.register_num/8 + 1) != mod_master.byte_num ) { mod_master.tx_error_message = TX_ERROR_COIL_NUM; return; } } else { //线圈数量为8的倍数时,字节数 == 线圈数量/8 if( (mod_master.register_num/8) != mod_master.byte_num ) { mod_master.tx_error_message = TX_ERROR_COIL_NUM; return; } } mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8); mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF); mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8); mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF); mod_master.data_tx[6] = mod_master.byte_num; for(uint8_t i = 1; i <= mod_master.byte_num; i++ ) { mod_master.data_tx[6 + i] = mod_master.data_tx_value[i - 1]; } mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 7 + mod_master.byte_num); mod_master.data_tx[7 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 & 0x00FF); mod_master.data_tx[8 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 >> 8); mod_master.data_tx_len = 8 + mod_master.byte_num + 1; } break; //【从站地址】【功能码】【起始地址高】【起始地址低】【数量高】【数量低】【写入字节数】【写入值1高】【写入值1低】...【写入值n高】【写入值n低】【CRC16校验低】【CRC16校验高】 case WriteMultiReg: { if( (mod_master.register_num * 2) != mod_master.byte_num ) { //字节数 == (寄存器数量*2) mod_master.tx_error_message = TX_ERROR_HOLDREG_NUM; return; } mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8); mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF); mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8); mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF); mod_master.data_tx[6] = mod_master.byte_num; for(uint8_t i = 1; i <= mod_master.byte_num; i++ ) { mod_master.data_tx[6 + i] = mod_master.data_tx_value[i - 1]; } mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 7 + mod_master.byte_num); mod_master.data_tx[7 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 & 0x00FF); mod_master.data_tx[8 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 >> 8); mod_master.data_tx_len = 8 + mod_master.byte_num + 1; } break; default: { mod_master.tx_error_message = TX_ERROR_WRONG_CMD; } break; } } void modbus_rtu_master_send(void) { if(mod_master.tx_error_message == TX_ERROR_NONE) { mod_master.rx_flag = TX_WAITING; //将准备好的数据发送至从设备 memcpy(scom2_rs485.tx_buff, mod_master.data_tx, mod_master.data_tx_len); scom2_rs485.tx_len = mod_master.data_tx_len; scom2_rs485.tx_flag = TRUE; if(scom2_rs485.tx_flag == TRUE) { scom2_rs485.tx_flag = FALSE; //将数据发送至上位机 HAL_UART_Transmit_DMA(&huart2, scom2_rs485.tx_buff, scom2_rs485.tx_len); } //在发送回调中判断发送是否完成 sig_trans = TRANS_MODBUS_SIG_TO_SLAVE; } } void modbus_rtu_master_analysis(void) { //收到的数据是否溢出 if(scom2_rs485.rx_len > RX_BUFF_MAX) { mod_master.rx_error_message = RX_ERROR_OVERFLOW; strcpy(mod_master.result_display, "ERROR: RX OVERFLOW"); return; } else { mod_master.data_rx_len = scom2_rs485.rx_len; memcpy(mod_master.data_rx, scom2_rs485.rx_buff, mod_master.data_rx_len); } //返回的从站地址与目标设备是否一致 if(mod_master.data_rx[0] != mod_master.target_id) { mod_master.rx_error_message = RX_ERROR_WRONG_ID; strcpy(mod_master.result_display, "ERROR: WRONG ID"); return; } //收到的是异常响应 if(mod_master.data_rx[1] > 0x80) { ex_message = (eMBException)mod_master.data_rx[2]; sprintf(mod_master.result_display, "Exceptional Response: %02x", mod_master.data_rx[2]); return; } //处理接收到的数据 modbus_rtu_master_data_process(); mod_master.rx_flag = RX_OK; } void modbus_rtu_master_data_process(void) { //获取功能码 uint8_t fun_cmd = mod_master.data_rx[1]; switch (fun_cmd) { //【从站地址】【功能码】【返回字节数n】【字节1~n】【CRC16校验低】【CRC16校验高】 case ReadCoilState: { if( mod_master.data_rx_len != (mod_master.data_rx[2] + 5) ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x Bytes:%02x Data: ", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2]); char num2str[2]; for(uint8_t i = 0; i < mod_master.data_rx[2]; i++) { sprintf(num2str, "%02x ", mod_master.data_rx[3 + i]); strcat(mod_master.result_display, num2str); } } break; //【从站地址】【功能码】【返回字节数n】【字节1~n】【CRC16校验低】【CRC16校验高】 case ReadDisInputState: { if( mod_master.data_rx_len != (mod_master.data_rx[2] + 5) ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x Bytes:%02x Data: ", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2]); char num2str[2]; for(uint8_t i = 0; i < mod_master.data_rx[2]; i++) { sprintf(num2str, "%02x ", mod_master.data_rx[3 + i]); strcat(mod_master.result_display, num2str); } } break; //【从站地址】【功能码】【返回字节数】【字1~n高】【字1~n低】【CRC16校验低】【CRC16校验高】 case ReadHoldReg: { if( mod_master.data_rx_len != (mod_master.data_rx[2] + 5) ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x Bytes:%02x Data: ", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2]); char num2str[2]; for(uint8_t i = 0; i < mod_master.data_rx[2]; i++) { sprintf(num2str, "%02x ", mod_master.data_rx[3 + i]); strcat(mod_master.result_display, num2str); } } break; //【从站地址】【功能码】【返回字节数】【字1~n高】【字1~n低】【CRC16校验低】【CRC16校验高】 case ReadInputReg: { if( mod_master.data_rx_len != (mod_master.data_rx[2] + 5) ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x Bytes:%02x Data: ", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2]); char num2str[2]; for(uint8_t i = 0; i < mod_master.data_rx[2]; i++) { sprintf(num2str, "%02x ", mod_master.data_rx[3 + i]); strcat(mod_master.result_display, num2str); } } break; //【从站地址】【功能码】【地址高】【地址低】【标志位高】【标志位低】【CRC16校验低】【CRC16校验高】 case WriteSingleCoil: { if( mod_master.data_rx_len != 8 ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x CoilAddress:0x%02x%02x Bits:0x%02x%02x", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2], mod_master.data_rx[3], mod_master.data_rx[4], mod_master.data_rx[5]); } break; //【从站地址】【功能码】【地址高】【地址低】【数据高】【数据低】【CRC16校验低】【CRC16校验高】 case WriteSingleReg: { if( mod_master.data_rx_len != 8 ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x RegAddress:0x%02x%02x Data:0x%02x%02x", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2], mod_master.data_rx[3], mod_master.data_rx[4], mod_master.data_rx[5]); } break; //【从站地址】【功能码】【地址高】【地址低】【数量高】【数量低】【CRC16校验低】【CRC16校验高】 case WriteMultiCoil: { if( mod_master.data_rx_len != 8 ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x CoilAddress:0x%02x%02x Num:0x%02x%02x", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2], mod_master.data_rx[3], mod_master.data_rx[4], mod_master.data_rx[5]); } break; //【从站地址】【功能码】【地址高】【地址低】【数量高】【数量低】【CRC16校验低】【CRC16校验高】 case WriteMultiReg: { if( mod_master.data_rx_len != 8 ) { mod_master.rx_error_message = RX_ERROR_WRONG_LENGTH; strcpy(mod_master.result_display, "ERROR: WRONG LENGTH"); return; } //数据解析 sprintf(mod_master.result_display, "Address:0x%02x Command:0x%02x RegAddress:0x%02x%02x Num:0x%02x%02x", mod_master.data_rx[0], mod_master.data_rx[1], mod_master.data_rx[2], mod_master.data_rx[3], mod_master.data_rx[4], mod_master.data_rx[5]); } break; default: { mod_master.rx_error_message = RX_ERROR_WRONG_CMD; strcpy(mod_master.result_display, "ERROR: WRONG COMMAND"); } break; } }