sggt/App/MODBUS/Src/modbus_rtu_master.c

453 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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));
memset(window_trx_num, 16, sizeof(window_trx_num));
}
void modbus_rtu_master_load(void)
{
//先清空之前的发送数据
memset(mod_master.data_tx, 0, sizeof(mod_master.data_tx));
mod_master.data_tx[0] = mod_master.target_id;
mod_master.data_tx[1] = mod_master.command_code;
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表示ON0x0000表示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)
{
//先清空之间的接收数据与显示内容
memset(mod_master.data_rx, 0, sizeof(mod_master.data_rx));
memset(mod_master.result_display, 0, sizeof(mod_master.result_display));
lv_label_set_text(guider_ui.screen_modbus_trx_value_Rx, "");
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] != mod_master.command_code)
{
mod_master.rx_error_message = RX_EEROR_WRONG_CMD;
strcpy(mod_master.result_display, "ERROR: WRONG COMMAND");
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;
}
//应答数据报的标志位是否与发送的一致
if( (mod_master.data_rx[4] != mod_master.data_tx[4])||(mod_master.data_rx[5] != mod_master.data_tx[5]) )
{
mod_master.rx_error_message = RX_ERROR_WRONG_DATA;
strcpy(mod_master.result_display, "ERROR: WRONG DATA");
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;
}
//应答数据报的数据是否与发送的一致
if( (mod_master.data_rx[4] != mod_master.data_tx[4])||(mod_master.data_rx[5] != mod_master.data_tx[5]) )
{
mod_master.rx_error_message = RX_ERROR_WRONG_DATA;
strcpy(mod_master.result_display, "ERROR: WRONG DATA");
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;
}
//应答数据报的寄存器数量是否与发送的一致
if( (mod_master.data_rx[4] != mod_master.data_tx[4])||(mod_master.data_rx[5] != mod_master.data_tx[5]) )
{
mod_master.rx_error_message = RX_ERROR_WRONG_NUM;
strcpy(mod_master.result_display, "ERROR: WRONG NUMBER OF REGISTERS");
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;
}
//应答数据报的寄存器数量是否与发送的一致
if( (mod_master.data_rx[4] != mod_master.data_tx[4])||(mod_master.data_rx[5] != mod_master.data_tx[5]) )
{
mod_master.rx_error_message = RX_ERROR_WRONG_NUM;
strcpy(mod_master.result_display, "ERROR: WRONG NUMBER OF REGISTERS");
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_INVALID_CMD;
strcpy(mod_master.result_display, "ERROR: INVALID COMMAND");
}
break;
}
}