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
324 lines
9.8 KiB
|
3 days ago
|
#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;//返回成功
|
||
|
|
}
|
||
|
|
}
|