You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

324 lines
9.8 KiB

#include "stm32g4xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
#include "modbus.h"
#include "usart.h"
void Modbus_Master_Send(uint8_t *data, uint8_t length);
uint16_t holdingRegisters[REGISTER_COUNT] = { 0x0032, 0x0032, 0x0032, 0x0032,
0x0032, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
// 寄存器可写标志位(1:可写,0:只读)
uint8_t registerWritable[REGISTER_COUNT] = { registerWritable_0,
registerWritable_1, registerWritable_2, registerWritable_3,
registerWritable_4, registerWritable_5, registerWritable_6,
registerWritable_7,
registerWritable_8, registerWritable_9, registerWritable_10,
registerWritable_11 };
/* 全局变量 */
uint8_t modbusBuffer[MODBUS_BUFFER_SIZE];
uint8_t modbus_master_Buffer[MODBUS_BUFFER_SIZE];
uint8_t modbus_master_BufferIndex = 0;
uint32_t last_master_ByteTime = 0;
uint8_t modbusBufferIndex = 0;
uint32_t lastByteTime = 0;
bool messageComplete = false;
uint8_t master_tx_buf[256];
uint8_t response[256];
uint8_t RS485_1_RX = 0;
uint8_t RS485_1_Host_Existed = 0;
char dmk_read_state=0;
/* 函数声明 */
void Modbus_Init(void);
void Modbus_Process(void);
void Modbus_SendResponse(uint8_t *data, uint8_t length);
void Modbus_HandleFunction03(uint16_t startAddress, uint16_t registerCount);
void Modbus_HandleFunction06(uint16_t registerAddress, uint16_t value);
void Modbus_HandleFunction10(uint16_t startAddress, uint16_t registerCount,
uint8_t *data);
void Modbus_SendExceptionResponse(uint8_t exceptionCode);
uint16_t CalculateCRC(uint8_t *data, uint8_t length);
/* 初始化函数 */
void Modbus_Init(void) {
/* 初始化UART */
/* 配置RS485方向控制引脚 */
HAL_UART_Receive_IT(&huart1, (uint8_t*) &modbusBuffer[modbusBufferIndex],
1);
HAL_UART_Receive_IT(&huart2,
(uint8_t*) &modbus_master_Buffer[modbus_master_BufferIndex], 1);
}
/* Modbus处理函数 - 应在主循环中调用 */
void Modbus_Process(void) {
uint16_t startAddress = 0;
uint16_t registerCount = 0;
if (modbusBufferIndex
> 0&& (HAL_GetTick() - lastByteTime) > MODBUS_TIMEOUT_MS) {
/* 超时,标记消息完成 */
messageComplete = true;
}
if (messageComplete) {
uint16_t crcReceived = (modbusBuffer[modbusBufferIndex - 1] << 8)
| modbusBuffer[modbusBufferIndex - 2];
uint16_t crcCalculated = CalculateCRC(modbusBuffer,
modbusBufferIndex - 2);
if (MODBUS_CRC_OFF || crcReceived == crcCalculated) {
RS485_1_Host_Existed = 1;
if (modbusBuffer[0] == MODBUS_SLAVE_ADDRESS) {
RS485_1_RX = 1;
switch (modbusBuffer[1]) {
case MODBUS_FUNCTION_CODE_03:
startAddress = (modbusBuffer[2] << 8) | modbusBuffer[3];
registerCount = (modbusBuffer[4] << 8) | modbusBuffer[5];
Modbus_HandleFunction03(startAddress, registerCount);
break;
case MODBUS_FUNCTION_CODE_06:
startAddress = (modbusBuffer[2] << 8) | modbusBuffer[3];
uint16_t value = (modbusBuffer[4] << 8) | modbusBuffer[5];
Modbus_HandleFunction06(startAddress, value);
break;
case MODBUS_FUNCTION_CODE_10:
startAddress = (modbusBuffer[2] << 8) | modbusBuffer[3];
registerCount = (modbusBuffer[4] << 8) | modbusBuffer[5];
uint8_t byteCount = modbusBuffer[6];
// 检查数据长度是否正确
if (byteCount == registerCount * 2
&& modbusBufferIndex - 2 >= 7 + byteCount) { // 7是功能码10的固定头部长度
Modbus_HandleFunction10(startAddress, registerCount,
&modbusBuffer[7]);
} else {
Modbus_SendExceptionResponse(0x03); // 数据长度错误
}
break;
default:
Modbus_SendExceptionResponse(0x01); // 不支持的功能码
break;
}
}
}
/* 重置缓冲区 */
modbusBufferIndex = 0;
messageComplete = false;
}
}
/* 处理功能码03 */
void Modbus_HandleFunction03(uint16_t startAddress, uint16_t registerCount) {
/* 检查地址和数量是否合法 */
if (startAddress < REGISTER_START_ADDRESS
|| startAddress + registerCount
> REGISTER_START_ADDRESS + REGISTER_COUNT
|| registerCount > 0x7D) {
Modbus_SendExceptionResponse(0x02); // 地址错误
return;
}
uint8_t byteCount = registerCount * 2;
uint8_t index = 0;
response[index++] = MODBUS_SLAVE_ADDRESS;
response[index++] = MODBUS_FUNCTION_CODE_03;
response[index++] = byteCount;
for (uint16_t i = 0; i < registerCount; i++) {
uint16_t regValue = holdingRegisters[(startAddress
- REGISTER_START_ADDRESS) + i];
response[index++] = (regValue >> 8) & 0xFF;
response[index++] = regValue & 0xFF;
}
uint16_t crc = CalculateCRC(response, index);
response[index++] = crc & 0xFF;
response[index++] = (crc >> 8) & 0xFF;
Modbus_SendResponse(response, index);
}
/* 处理功能码06 */
void Modbus_HandleFunction06(uint16_t registerAddress, uint16_t value) {
/* 检查地址是否合法 */
if (registerAddress < REGISTER_START_ADDRESS
|| registerAddress >= REGISTER_START_ADDRESS + REGISTER_COUNT) {
Modbus_SendExceptionResponse(0x02); // 地址错误
return;
}
/* 写入寄存器值 */
holdingRegisters[registerAddress - REGISTER_START_ADDRESS] = value;
/* 准备响应帧 - 功能码06的响应是原请求帧的原样返回 */
uint8_t index = 0;
response[index++] = MODBUS_SLAVE_ADDRESS;
response[index++] = MODBUS_FUNCTION_CODE_06;
response[index++] = (registerAddress >> 8) & 0xFF; // 寄存器地址高8位
response[index++] = registerAddress & 0xFF; // 寄存器地址低8位
response[index++] = (value >> 8) & 0xFF; // 写入值高8位
response[index++] = value & 0xFF; // 写入值低8位
/* 计算CRC并添加到响应帧 */
uint16_t crc = CalculateCRC(response, index);
response[index++] = crc & 0xFF;
response[index++] = (crc >> 8) & 0xFF;
/* 发送响应 */
Modbus_SendResponse(response, index);
}
// 添加功能码0x10处理函数
void Modbus_HandleFunction10(uint16_t startAddress, uint16_t registerCount,
uint8_t *data) {
// 检查地址和数量是否合法
if (startAddress < REGISTER_START_ADDRESS
|| startAddress + registerCount
> REGISTER_START_ADDRESS + REGISTER_COUNT
|| registerCount == 0 || registerCount > 0x7B) {
Modbus_SendExceptionResponse(0x02); // 地址错误
return;
}
// 处理每个寄存器
for (uint16_t i = 0; i < registerCount; i++) {
uint16_t regIndex = (startAddress - REGISTER_START_ADDRESS) + i;
uint16_t value = (data[i * 2] << 8) | data[i * 2 + 1];
// 只有可写寄存器才更新值
if (registerWritable[regIndex]) {
holdingRegisters[regIndex] = value;
}
// 只读寄存器保持原有值,不做处理
}
// 准备响应帧 - 功能码0x10的响应包含起始地址和写入数量
uint8_t index = 0;
response[index++] = MODBUS_SLAVE_ADDRESS;
response[index++] = MODBUS_FUNCTION_CODE_10;
response[index++] = (startAddress >> 8) & 0xFF; // 起始地址高8位
response[index++] = startAddress & 0xFF; // 起始地址低8位
response[index++] = (registerCount >> 8) & 0xFF; // 写入数量高8位
response[index++] = registerCount & 0xFF; // 写入数量低8位
// 计算CRC并添加到响应帧
uint16_t crc = CalculateCRC(response, index);
response[index++] = crc & 0xFF;
response[index++] = (crc >> 8) & 0xFF;
// 发送响应
Modbus_SendResponse(response, index);
}
/* 发送异常响应 */
void Modbus_SendExceptionResponse(uint8_t exceptionCode) {
response[0] = MODBUS_SLAVE_ADDRESS;
response[1] = modbusBuffer[1] | 0x80; // 异常功能码
response[2] = exceptionCode;
uint16_t crc = CalculateCRC(response, 3);
response[3] = crc & 0xFF;
response[4] = (crc >> 8) & 0xFF;
Modbus_SendResponse(response, 5);
}
/* 发送响应 */
void Modbus_SendResponse(uint8_t *data, uint8_t length) {
/* 使能RS485发送 */
/* 发送数据 */
HAL_UART_Transmit_DMA(&huart1, data, length);
/* 切换到接收模式 */
}
/* 发送响应 */
void Modbus_Master_Send(uint8_t *data, uint8_t length) {
/* 使能RS485发送 */
/* 发送数据 */
HAL_UART_Transmit_DMA(&huart2, data, length);
/* 切换到接收模式 */
}
/* CRC计算 */
uint16_t CalculateCRC(uint8_t *data, uint8_t length) {
uint16_t crc = 0xFFFF;
for (uint8_t i = 0; i < length; i++) {
crc ^= (uint16_t) data[i];
for (uint8_t j = 0; j < 8; j++) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
/* UART接收中断回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart == &huart1) {
if (modbusBufferIndex < MODBUS_BUFFER_SIZE) {
modbusBuffer[modbusBufferIndex++] = huart->Instance->RDR;
} else {
modbusBufferIndex = 0;
}
lastByteTime = HAL_GetTick();
/* 重新启动接收中断 */
HAL_UART_Receive_IT(&huart1,
(uint8_t*) &modbusBuffer[modbusBufferIndex], 1);
} else if (huart == &huart2) {
if (modbus_master_BufferIndex < MODBUS_BUFFER_SIZE) {
modbus_master_Buffer[modbus_master_BufferIndex++] =
huart->Instance->RDR;
} else {
modbus_master_BufferIndex = 0;
}
last_master_ByteTime = HAL_GetTick();
/* 重新启动接收中断 */
HAL_UART_Receive_IT(&huart2,
(uint8_t*) &modbus_master_Buffer[modbus_master_BufferIndex], 1);
}
}
void MB_WriteHoldingReg(uint8_t _addr,
uint16_t _reg, uint16_t _data) {
uint16_t TxCount = 0;
uint16_t crc = 0;
master_tx_buf[TxCount++] = _addr; /* 从站地址 */
master_tx_buf[TxCount++] = 0x06; /* 功能码 */
master_tx_buf[TxCount++] = _reg >> 8; /* 寄存器地址 高字节 */
master_tx_buf[TxCount++] = _reg; /* 寄存器地址 低字节 */
master_tx_buf[TxCount++] = _data >> 8; /* 寄存器(16bits)个数 高字节 */
master_tx_buf[TxCount++] = _data; /* 低字节 */
crc = CalculateCRC(master_tx_buf, TxCount);
master_tx_buf[TxCount++] = crc & 0xFF;
master_tx_buf[TxCount++] = (crc >> 8) & 0xFF;
Modbus_Master_Send(master_tx_buf,TxCount);
dmk_read_state=0;
}
void calculate_dmk()
{
if (modbus_master_BufferIndex
> 0&& (HAL_GetTick() - last_master_ByteTime) > MODBUS_TIMEOUT_MS)
{
/* 接收标记消息完成 */
dmk_read_state=1;//返回成功
}
}