7 changed files with 617 additions and 0 deletions
@ -0,0 +1,15 @@ |
|||||
|
cmake_minimum_required(VERSION 3.10) |
||||
|
|
||||
|
set(COMMON_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../library/CMakeLists.txt") |
||||
|
|
||||
|
if(EXISTS ${COMMON_CMAKE_PATH}) |
||||
|
include(${COMMON_CMAKE_PATH}) |
||||
|
else() |
||||
|
message(FATAL_ERROR "Cannot find common build logic at ${COMMON_CMAKE_PATH}") |
||||
|
endif() |
||||
|
|
||||
|
if(TARGET bspMCU) |
||||
|
target_link_libraries(Spoolend PUBLIC bspMCU) |
||||
|
else() |
||||
|
message(WARNING "[Spoolend] Dependency 'bspMCU' not found.") |
||||
|
endif() |
||||
@ -0,0 +1,96 @@ |
|||||
|
/******************************************************************************
|
||||
|
|
||||
|
版权所有 (C), 2018-2099, Radkil |
||||
|
|
||||
|
****************************************************************************** |
||||
|
文 件 名 : Spoolend.c |
||||
|
版 本 号 : 初稿 |
||||
|
作 者 : radkil |
||||
|
生成日期 : 2026年6月10日 |
||||
|
最近修改 : |
||||
|
功能描述 : 线轴端控制板 |
||||
|
|
||||
|
修改历史 : |
||||
|
1.日 期 : 2026年6月10日 |
||||
|
作 者 : radkil |
||||
|
修改内容 : 创建文件 |
||||
|
|
||||
|
******************************************************************************/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 外部变量说明 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 外部函数原型说明 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 内部函数原型说明 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 全局变量 * |
||||
|
*----------------------------------------------*/ |
||||
|
TComCtrl *g_ptRS485_1; |
||||
|
TComCtrl *g_ptRS485_2; |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 模块级变量 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 常量定义 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
/*----------------------------------------------*
|
||||
|
* 宏定义 * |
||||
|
*----------------------------------------------*/ |
||||
|
|
||||
|
int RS485_1_Send(char *_pBuffer, uint32_t _iSize) |
||||
|
{ |
||||
|
HAL_GPIO_WritePin(RS485_1_DIR_GPIO_Port, RS485_1_DIR_Pin, GPIO_PIN_SET); |
||||
|
TUartUserData *ptUartUserData = (TUartUserData *)g_ptRS485_1->m_pUserData; |
||||
|
int iRet = HAL_UART_Transmit(ptUartUserData->m_uart, (uint8_t *)_pBuffer, _iSize, 100); |
||||
|
HAL_GPIO_WritePin(RS485_1_DIR_GPIO_Port, RS485_1_DIR_Pin, GPIO_PIN_RESET); |
||||
|
return iRet; |
||||
|
} |
||||
|
|
||||
|
int RS485_2_Send(char *_pBuffer, uint32_t _iSize) |
||||
|
{ |
||||
|
HAL_GPIO_WritePin(RS485_2_DIR_GPIO_Port, RS485_2_DIR_Pin, GPIO_PIN_SET); |
||||
|
TUartUserData *ptUartUserData = (TUartUserData *)g_ptRS485_2->m_pUserData; |
||||
|
int iRet = HAL_UART_Transmit(ptUartUserData->m_uart, (uint8_t *)_pBuffer, _iSize, 100); |
||||
|
HAL_GPIO_WritePin(RS485_2_DIR_GPIO_Port, RS485_2_DIR_Pin, GPIO_PIN_RESET); |
||||
|
return iRet; |
||||
|
} |
||||
|
|
||||
|
#ifndef CONFIG_UART_IT_IDLEDMA |
||||
|
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) |
||||
|
{ |
||||
|
if (huart->Instance == LPUART1) |
||||
|
{ |
||||
|
UART_RX_IRQHandler(g_ptRS485_1); |
||||
|
} |
||||
|
else if (huart->Instance == USART1) |
||||
|
{ |
||||
|
UART_RX_IRQHandler(g_ptRS485_2); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
void SpoolendInit(void) |
||||
|
{ |
||||
|
TUartUserData *ptUartUserData = UART_userdata_init(0, -1, 512); |
||||
|
g_ptRS485_1 = rd_ComCreate(check_MK32Data, decode_MK32Data, E28_SBUS_Send, ptUartUserData->m_buf_size, ptUartUserData); |
||||
|
UART_IT_init(g_ptRS485_1); |
||||
|
TUartUserData *ptUartUserData1 = UART_userdata_init(0, -1, 512); |
||||
|
g_ptRS485_1 = rd_ComCreate(check_MK32Data, decode_MK32Data, E28_SBUS_Send, ptUartUserData1->m_buf_size, ptUartUserData1); |
||||
|
UART_IT_init(g_ptRS485_1); |
||||
|
} |
||||
|
|
||||
|
void SpoolendTask(void) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
@ -0,0 +1,105 @@ |
|||||
|
#include "flash_operation.h" |
||||
|
|
||||
|
void Flash_InitInternal(void) |
||||
|
{ |
||||
|
// 解锁Flash
|
||||
|
HAL_FLASH_Unlock(); |
||||
|
|
||||
|
// 设置Flash延迟
|
||||
|
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_4); |
||||
|
|
||||
|
// 清除所有错误标志
|
||||
|
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); |
||||
|
} |
||||
|
|
||||
|
uint32_t GetFlashPage(uint32_t address) |
||||
|
{ |
||||
|
return (address - FLASH_BASE_ADDRESS) / FLASH_PAGE_SIZE; |
||||
|
} |
||||
|
|
||||
|
HAL_StatusTypeDef WriteParametersToFlash(int16_t* parameters) |
||||
|
{ |
||||
|
HAL_StatusTypeDef status = HAL_OK; |
||||
|
uint32_t flash_address = DATA_FLASH_ADDRESS; |
||||
|
uint32_t primask_bit; |
||||
|
|
||||
|
// 关闭全局中断
|
||||
|
primask_bit = __get_PRIMASK(); |
||||
|
__disable_irq(); |
||||
|
|
||||
|
// 内部初始化Flash
|
||||
|
Flash_InitInternal(); |
||||
|
|
||||
|
// 擦除Flash页
|
||||
|
FLASH_EraseInitTypeDef erase_init; |
||||
|
uint32_t page_error = 0; |
||||
|
|
||||
|
erase_init.TypeErase = FLASH_TYPEERASE_PAGES; |
||||
|
erase_init.Banks = FLASH_BANK_1; |
||||
|
erase_init.Page = GetFlashPage(DATA_FLASH_ADDRESS); |
||||
|
erase_init.NbPages = 1; |
||||
|
|
||||
|
// 执行擦除
|
||||
|
if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK) |
||||
|
{ |
||||
|
HAL_FLASH_Lock(); |
||||
|
// 恢复中断状态
|
||||
|
if (!primask_bit) { |
||||
|
__enable_irq(); |
||||
|
} |
||||
|
return HAL_ERROR; |
||||
|
} |
||||
|
|
||||
|
// 写入4个int16_t数据
|
||||
|
for (int i = 0; i < PARAM_COUNT; i++) |
||||
|
{ |
||||
|
// 每次写入64位数据(4个int16_t)
|
||||
|
if (i % 4 == 0) |
||||
|
{ |
||||
|
uint64_t combined_data = 0; |
||||
|
|
||||
|
// 组合4个int16_t到一个uint64_t
|
||||
|
for (int j = 0; j < 4 && (i + j) < PARAM_COUNT; j++) |
||||
|
{ |
||||
|
combined_data |= ((uint64_t)((uint16_t)parameters[i + j]) << (j * 16)); |
||||
|
} |
||||
|
|
||||
|
// 写入组合后的数据
|
||||
|
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, |
||||
|
flash_address + (i * sizeof(int16_t)), |
||||
|
combined_data) != HAL_OK) |
||||
|
{ |
||||
|
status = HAL_ERROR; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 锁定Flash
|
||||
|
HAL_FLASH_Lock(); |
||||
|
|
||||
|
// 恢复中断状态
|
||||
|
if (!primask_bit) { |
||||
|
__enable_irq(); |
||||
|
} |
||||
|
|
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
void ReadParametersFromFlash(int16_t* parameters) |
||||
|
{ |
||||
|
uint32_t flash_address = DATA_FLASH_ADDRESS; |
||||
|
|
||||
|
// 内部初始化Flash(主要是解锁和配置)
|
||||
|
Flash_InitInternal(); |
||||
|
|
||||
|
// 从Flash读取数据
|
||||
|
for (int i = 0; i < PARAM_COUNT; i++) |
||||
|
{ |
||||
|
// 读取int16_t数据
|
||||
|
parameters[i] = *(int16_t*)(flash_address + (i * sizeof(int16_t))); |
||||
|
} |
||||
|
|
||||
|
// 锁定Flash(虽然读取不需要锁定,但为了对称性)
|
||||
|
HAL_FLASH_Lock(); |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
#ifndef FLASH_OPERATION_H |
||||
|
#define FLASH_OPERATION_H |
||||
|
|
||||
|
#include "stm32g4xx_hal.h" |
||||
|
|
||||
|
/* 定义Flash存储地址 - 使用最后一页 */ |
||||
|
#define FLASH_BASE_ADDRESS 0x08000000 |
||||
|
//#define FLASH_SIZE (128 * 1024) // 128KB
|
||||
|
//#define FLASH_PAGE_SIZE 0x800 // 2KB per page
|
||||
|
#define DATA_FLASH_ADDRESS (FLASH_BASE_ADDRESS + FLASH_SIZE - FLASH_PAGE_SIZE) // 最后一页
|
||||
|
#define PARAM_COUNT 12 |
||||
|
|
||||
|
/* 函数声明 */ |
||||
|
HAL_StatusTypeDef WriteParametersToFlash(int16_t* parameters); |
||||
|
void ReadParametersFromFlash(int16_t* parameters); |
||||
|
|
||||
|
#endif |
||||
@ -0,0 +1,60 @@ |
|||||
|
/*
|
||||
|
* modbus.h |
||||
|
* |
||||
|
* Created on: Jul 3, 2025 |
||||
|
* Author: shiyanlei |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __MODBUS_SLAVE_H |
||||
|
#define __MODBUS_SLAVE_H |
||||
|
|
||||
|
#include "stm32g4xx_hal.h" |
||||
|
/* 定义Modbus相关参数 */ |
||||
|
#define MODBUS_SLAVE_ADDRESS 0x34 |
||||
|
#define MODBUS_FUNCTION_CODE_03 0x03 |
||||
|
#define MODBUS_FUNCTION_CODE_06 0x06 |
||||
|
#define MODBUS_FUNCTION_CODE_10 0x10 // 写多个寄存器功能码
|
||||
|
#define MODBUS_BUFFER_SIZE 256 |
||||
|
#define MODBUS_TIMEOUT_MS 2 |
||||
|
#define MODBUS_CRC_OFF 0 //==1关闭CRC校验
|
||||
|
/* 定义寄存器相关参数 */ |
||||
|
#define REGISTER_START_ADDRESS 0x0000 |
||||
|
//#define REGISTER_COUNT 10
|
||||
|
#define REGISTER_COUNT 12 |
||||
|
|
||||
|
extern uint16_t holdingRegisters[REGISTER_COUNT]; |
||||
|
extern uint8_t RS485_1_RX; |
||||
|
extern uint8_t RS485_1_Host_Existed; |
||||
|
|
||||
|
#define registerWritable_0 1 |
||||
|
#define registerWritable_1 1 |
||||
|
#define registerWritable_2 1 |
||||
|
#define registerWritable_3 1 |
||||
|
#define registerWritable_4 1 |
||||
|
#define registerWritable_5 1 |
||||
|
#define registerWritable_6 1 |
||||
|
#define registerWritable_7 1 |
||||
|
#define registerWritable_8 1 |
||||
|
#define registerWritable_9 1 |
||||
|
#define registerWritable_10 1 |
||||
|
#define registerWritable_11 1 |
||||
|
|
||||
|
|
||||
|
//holdingRegisters[0]= motor_cmd //0:stop 1:forward 2:reverse
|
||||
|
//holdingRegisters[1]= HX711_A_F //int16_t 10g
|
||||
|
//holdingRegisters[2]= HX711_K //uint16_t
|
||||
|
//holdingRegisters[3]= HX711_D //int16_t 1g
|
||||
|
//holdingRegisters[4]= HX711_B_F //int16_t 10g
|
||||
|
|
||||
|
|
||||
|
|
||||
|
extern void MB_WriteHoldingReg(uint8_t _addr, |
||||
|
uint16_t _reg, uint16_t _data); |
||||
|
|
||||
|
/* 初始化Modbus从机 */ |
||||
|
void Modbus_Init(void); |
||||
|
|
||||
|
/* 处理Modbus消息 */ |
||||
|
void Modbus_Process(void); |
||||
|
|
||||
|
#endif /* __MODBUS_SLAVE_H */ |
||||
@ -0,0 +1,323 @@ |
|||||
|
#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;//返回成功
|
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue