sggt/App/MODBUS/Src/modbus_rtu_master.c

396 lines
16 KiB
C
Raw 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));
}
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表示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)
{
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;
}
}