generic_io/EMAIN/modbus/Src/modbus_host.c

292 lines
8.7 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.h"
uint8_t uart3_rx_buf[MAX_SIZE]; //发送数据缓冲数组
uint8_t uart3_tx_buf[MAX_SIZE]; //接收数据缓冲数据
uint16_t uart3_rx_cnt = 0;
uint16_t uart3_rx_size = 0;
uint8_t uart3_rxbuf = 0;
uint8_t uart6_rx_buf[MAX_SIZE]; //发送数据缓冲数组
uint8_t uart6_tx_buf[MAX_SIZE]; //接收数据缓冲数据
uint16_t uart6_rx_cnt = 0;
uint16_t uart6_rx_size = 0;
uint8_t uart6_rxbuf = 0;
uint8_t HostTxdbuf[100];
void modbus_host_init(void)
{
HAL_UART_Receive_IT(&huart3, (uint8_t *)&uart3_rxbuf, 1); //开启接收中断
HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart6_rxbuf, 1); //开启接收中断
__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); //手动添加
HAL_TIM_Base_Start_IT(&htim4);
__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE); //手动添加
HAL_TIM_Base_Start_IT(&htim5);
}
void modbus_uart3_rx_cb(void)
{
if(uart3_rx_cnt >= MAX_SIZE-1) //接收数据量超限,错误
{
uart3_rx_cnt = 0;
memset(uart3_rx_buf, 0x00, sizeof(&uart3_rx_cnt));
HAL_UART_Transmit(&huart3, (uint8_t *)"数据溢出", 10, 0xFFFF);
}
else //接收正常
{
uart3_rx_buf[uart3_rx_cnt++] = uart3_rxbuf; //接收数据存储到rx_buf
HAL_TIM_Base_Stop_IT(&htim4);
__HAL_TIM_SET_COUNTER(&htim4, 0);
HAL_TIM_Base_Start_IT(&htim4); //将定时器7的计数值清零后重新计数
send_cnt = 0;
}
HAL_UART_Receive_IT(&huart3, (uint8_t *)&uart3_rxbuf, 1);
}
void modbus_uart6_rx_cb(void)
{
if(uart6_rx_cnt >= MAX_SIZE-1) //接收数据量超限,错误
{
uart6_rx_cnt = 0;
memset(uart6_rx_buf, 0x00, sizeof(&uart6_rx_cnt));
HAL_UART_Transmit(&huart6, (uint8_t *)"数据溢出", 10, 0xFFFF);
}
else //接收正常
{
uart6_rx_buf[uart6_rx_cnt++] = uart6_rxbuf; //接收数据存储到rx_buf
HAL_TIM_Base_Stop_IT(&htim5);
__HAL_TIM_SET_COUNTER(&htim5, 0);
HAL_TIM_Base_Start_IT(&htim5); //将定时器7的计数值清零后重新计数
send_cnt = 0;
}
HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart6_rxbuf, 1);
}
/*******************************************************************************
函数名称 ReadDisInputStateFUNC
功 能 功能码:0x02,读取离散量
参 数
返 回 值
*发送:[硬件地址][02][离散量起始地址高][离散量起始地址低][离散量数量高][离散量数量低][CRC低][CRC高]
*返回:[硬件地址][02][字节长度][离散量值][离散量值][离散量值][CRC低][CRC高]
*******************************************************************************/
void readdisinputstate_host(uint8_t local_addr, uint16_t star_addr, uint16_t reg_num)
{
uint16_t CRC16Temp;
HostTxdbuf[0] = local_addr;
HostTxdbuf[1] = 0x02;
HostTxdbuf[2] = (uint8_t)(star_addr >> 8);
HostTxdbuf[3] = (uint8_t)(star_addr & 0xFF);
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
uart_send(&huart6,HostTxdbuf,8);
}
/*******************************************************************************
函数名称 ReadInputRegFUNC
功 能 功能码:0x04,读取输入寄存器
参 数
返 回 值
*发送:[硬件地址][04][起始地址高][起始地址低][总寄存器数高][总寄存器数低][ CRC低 ][ CRC高 ]
*返回:[硬件地址][04][ 字节数 ][寄存器0高 ][ 寄存器0低 ][ 寄存器1高 ][ 寄存器1低 ][ 寄存器n高 ][ 寄存器n低 ][ CRC低 ][ CRC高 ]
*******************************************************************************/
void readinputreg_host(uint8_t local_addr, uint16_t star_addr, uint16_t reg_num)
{
uint16_t CRC16Temp;
HostTxdbuf[0] = local_addr;
HostTxdbuf[1] = 0x04;
HostTxdbuf[2] = (uint8_t)(star_addr >> 8);
HostTxdbuf[3] = (uint8_t)(star_addr & 0xFF);
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
uart_send(&huart6,HostTxdbuf,8);
}
/*******************************************************************************
函数名称 WriteSingleCoilFUNC
功 能 功能码:0x05 写单个线圈寄存器,写入0xFF00表示将线圈置为ON写入0x0000表示将线圈置为OFF
参 数
返 回 值
*发送:[硬件地址][05][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*返回:[硬件地址][05][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*******************************************************************************/
void writesinglecoil_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_data)
{
uint16_t CRC16Temp;
HostTxdbuf[0] = local_addr;
HostTxdbuf[1] = 0x05;
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
HostTxdbuf[4] = (uint8_t)(reg_data >> 8);
HostTxdbuf[5] = (uint8_t)(reg_data & 0xFF);
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
uart_send(&huart6,HostTxdbuf,8);
}
/*******************************************************************************
函数名称 WriteMultiCoilFUNC
功 能 功能码:0x0F,写多个线圈,此函数为特化版最多写8个线圈字节数固定为1
参 数
返 回 值
*发送:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][字节数][线圈值][CRC低][CRC高]
*返回:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
*******************************************************************************/
void writemulticoil_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_num, uint8_t reg_data)
{
uint16_t CRC16Temp;
HostTxdbuf[0] = local_addr;
HostTxdbuf[1] = 0x0F;
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
HostTxdbuf[6] = 0x01;
HostTxdbuf[7] = reg_data;
CRC16Temp = ModbusCRC16(HostTxdbuf, 8);
HostTxdbuf[8] = (uint8_t)(CRC16Temp & 0xFF);
HostTxdbuf[9] = (uint8_t)(CRC16Temp >> 8);
uart_send(&huart6,HostTxdbuf,10);
}
/*******************************************************************************
函数名称 WriteSingleRegFUNC
功 能 功能码:0x06 预设(写)单寄存器
参 数
返 回 值
*发送:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*返回:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*******************************************************************************/
void writesinglereg_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_data)
{
uint16_t CRC16Temp;
HostTxdbuf[0] = local_addr;
HostTxdbuf[1] = 0x06;
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
HostTxdbuf[4] = (uint8_t)(reg_data >> 8);
HostTxdbuf[5] = (uint8_t)(reg_data & 0xFF);
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
uart_send(&huart6,HostTxdbuf,8);
}
void modbus_analysis_host(uint8_t * HostRxdbuf, uint16_t wRxdLen)
{
uint8_t uSlaveAdd, uCmdCode;
if((HostRxdbuf == NULL) || (wRxdLen < 2)) return;
uSlaveAdd = HostRxdbuf[0];
uCmdCode = HostRxdbuf[1];
// 从机地址为本机地址或者是广播帧
if(1)
{
switch(uCmdCode)
{
case ReadDisInputState:// 读离散输入状态
{
if((uSlaveAdd % 5) == 2)
{
DisState[((uSlaveAdd - 2) / 5) * 2] = HostRxdbuf[3];
}
else if((uSlaveAdd % 5) == 3)
{
DisState[((uSlaveAdd - 3) / 5) * 2 + 1] = HostRxdbuf[3];
}
}
break;
case ReadInputReg:// 读取输入寄存器
{
InputReg[((uSlaveAdd / 5) - 1) * 8 + 0] = MAKEWORD(HostRxdbuf[4], HostRxdbuf[3]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 1] = MAKEWORD(HostRxdbuf[6], HostRxdbuf[5]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 2] = MAKEWORD(HostRxdbuf[8], HostRxdbuf[7]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 3] = MAKEWORD(HostRxdbuf[10], HostRxdbuf[9]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 4] = MAKEWORD(HostRxdbuf[12], HostRxdbuf[11]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 5] = MAKEWORD(HostRxdbuf[14], HostRxdbuf[13]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 6] = MAKEWORD(HostRxdbuf[16], HostRxdbuf[15]);
InputReg[((uSlaveAdd / 5) - 1) * 8 + 7] = MAKEWORD(HostRxdbuf[18], HostRxdbuf[17]);
}
break;
case WriteSingleReg:// 写单个保持寄存器
{
}
break;
case WriteSingleCoil:// 写单个线圈
{
}
break;
default:// 错误码处理
{
}
break;
}
}
}
void modbus_process_host(void)
{
uint16_t wFrameCRC, wCalCRC;
if(uart6_rx_size < 2) return; // 数据长度不是有效值
// 获取接收数据帧中的校验和
wFrameCRC = MAKEWORD(uart6_rx_buf[uart6_rx_size - 2], uart6_rx_buf[uart6_rx_size - 1]);
// 计算接收到的数据的校验和
wCalCRC = ModbusCRC16(uart6_rx_buf, uart6_rx_size - 2);
if(wFrameCRC != wCalCRC) return;
modbus_analysis_host(uart6_rx_buf, uart6_rx_size);// 协议处理
}