#include "main.h" #include "Modbussimple.h" #include "cmsis_os.h" #include "Callback.h" #include "uType.h" JsonDat_Work JsWork; uint32_t g_modbusbuffer[40] ; // 当用DMA发送的时候 帧头要四字节对齐 /*阀杆相关参数定义*/ extern volatile float Value_open_percent; // 阀杆开行程百分比 extern volatile float Value_open_mm; // 阀杆开行程mm extern volatile float MPXV_P0; // 阀杆压力值 extern volatile float ADS_v0; // ads1256 通道0原始电压值 extern volatile float filtered_ADS_v0; // 滤波后的阀杆电压值 extern volatile float ADS_v0_offset; // ads1256 通道0电压偏移(将结果乘1000倍再赋值) 0.008*1000 = 8.0 // extern volatile float // 阀杆压力值滤波滑动窗口大小 /*油水相关参数定义*/ extern volatile float filtered_oil_cap; // 滤波后的油水电容值 extern volatile float oil_percent; // 油水百分比 extern volatile float oil_cap;// 原始电容值 extern volatile float oil_para_indu; // 并联电感值 extern volatile float oil_para_cap; // 并联电容值 extern volatile float oil_cap_offset;// 油水电容偏移值 // extern volatile float // 油水电容值滤波滑动窗口大小 /*余油相关参数定义*/ extern volatile float ADS_v1; // ads1256 通道1原始电压值 extern volatile float filtered_res_oil_cap; // 滤波后的电容值 extern volatile float MPXV_P1; // 余油压力值(kpa) extern volatile float res_oil_height; // 余油高度值(mm) extern volatile float res_oil_cap; // // 软件IIC 2号(PB10PB11)测得原始电容值 extern volatile float ADS_v1; // ads1256 通道1原始电压值 extern volatile float filtered_ADS_v1; // 滤波之后ads1256 通道1电压值 extern volatile float res_oil_para_indu; // 并联电感值 extern volatile float res_oil_para_cap; // 并联电容值 extern volatile float res_oil_cap_offset;// 余油电容偏移值 extern volatile float ADS_v1_offset; // ads1256 通道1电压偏移值(将结果乘1000倍再赋值) // extern volatile float // 余油电容值滤波滑动窗口大小 // extern volatile float // 余油压力值滤波滑动窗口大小 /*温度相关参数定义*/ extern volatile float ADS_v2; // ads1256 通道2原始电压值 extern volatile float filtered_ADS_v2; // 滤波后的电压值 extern volatile float NTC_temp; // 电压查RT表转换后的温度值(℃) extern volatile float ADS_v2; // ads1256 通道2原始电压值 extern volatile float ADS_v2_offset; // ads1256 通道2电压偏移值(将结果乘1000倍再赋值) // extern volatile float // 温度滤波滑动窗口大小 // 03读指令应答结构体 ModbusRegister_t modbus_map[] = { {0x4000, 2, MODBUS_TYPE_UINT32_BE, &JsRoot.vers_id},// 固件版本号 {0x4002, 1, MODBUS_TYPE_UINT16, &JsRoot.age}, // 运行时长 {0x4010, 1, MODBUS_TYPE_UINT16, &JsRoot.addr}, // 从机设备地址 {0x4011, 1, MODBUS_TYPE_UINT16, &JsRoot.baudrate}, // 波特率 {0x4020, 3, MODBUS_TYPE_UINT16, &JsRoot.mac}, // 设备SN号 {0x0000, 2, MODBUS_TYPE_FLOAT_BE, (void *)&Value_open_percent}, // 阀杆开行程百分比 {0x0002, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_percent}, // 油水百分比 {0x0004, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_height}, // 余油液位高度值(mm) {0x0006, 2, MODBUS_TYPE_FLOAT_BE, (void *)&NTC_temp}, // 温度摄氏度 {0x0100, 1, MODBUS_TYPE_OILTYPE, (void*)&g_oil_type}, // 油品 {0x0102, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[0]}, // 阀杆电压标定值(对应0mm行程) {0x0104, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[1]}, // 阀杆电压标定值(对应1mm行程) {0x0106, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[2]}, // 阀杆电压标定值(对应2mm行程) {0x0108, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[3]}, // 阀杆电压标定值(对应3mm行程) {0x010A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[4]}, // 阀杆电压标定值(对应4mm行程) {0x010C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[5]}, // 阀杆电压标定值(对应5mm行程) {0x010E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[6]}, // 阀杆电压标定值(对应6mm行程) {0x0110, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[0]}, // 油水电容标定值(对应90%配比) {0x0112, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[1]}, // 油水电容标定值(对应91%配比) {0x0114, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[2]}, // 油水电容标定值(对应92%配比) {0x0116, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[3]}, // 油水电容标定值(对应93%配比) {0x0118, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[4]}, // 油水电容标定值(对应94%配比) {0x011A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[5]}, // 油水电容标定值(对应95%配比) {0x011C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[6]}, // 油水电容标定值(对应96%配比) {0x011E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[7]}, // 油水电容标定值(对应97%配比) {0x0120, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[8]}, // 油水电容标定值(对应98%配比) {0x0122, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[9]}, // 油水电容标定值(对应99%配比) {0x0124, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[10]}, // 油水电容标定值(对应100%配比) {0x0126, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[0]}, // 余液电容标定值(1cm液位高度) {0x0128, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[1]}, // 余液电容标定值(2cm液位高度) {0x012A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[2]}, // 余液电容标定值(3cm液位高度) {0x012C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[3]}, // 余液电容标定值(4cm液位高度) {0x012E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[4]}, // 余液电容标定值(5cm液位高度) {0x0130, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[5]}, // 余液电容标定值(6cm液位高度) {0x0132, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[0]}, // 余液压力传感器电压标定值(1cm液位高度) {0x0134, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[1]}, // 余液压力传感器电压标定值(2cm液位高度) {0x0136, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[2]}, // 余液压力传感器电压标定值(3cm液位高度) {0x0138, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[3]}, // 余液压力传感器电压标定值(4cm液位高度) {0x013A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[4]}, // 余液压力传感器电压标定值(5cm液位高度) {0x013C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[5]}, // 余液压力传感器电压标定值(6cm液位高度) {0x0200, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v0}, // 通道0电压原始数据(阀杆) {0x0202, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v0}, // 滤波后通道0电压数据(阀杆) {0x0204, 2, MODBUS_TYPE_FLOAT_BE, (void *)&MPXV_P0}, // 电压转换后的压力值(阀杆) {0x0206, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v0_offset}, // 通道0电压数据偏移值(阀杆) // {0x0208, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 压力值滤波滑动窗口大小(阀杆) {0x020A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_cap}, // 1号电容原始电容值(油水) {0x020C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_oil_cap}, // 滤波后油水电容值 {0x020E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_para_indu}, // 1号并联电感值(油水) {0x0210, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_para_cap}, // 1号并联电容值(油水) {0x0212, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_cap_offset}, // 1号电容偏移值(油水) // {0x0214, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 电容值滤波滑动窗口大小(油水) {0x0216, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_cap}, // 2号电容原始电容值(余油) {0x0218, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_res_oil_cap}, // 滤波之后的电容值(余油) {0x021A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v1}, // 通道1电压原始数据(余油) {0x021C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v1}, // 滤波后电压值(余油) {0x021E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&MPXV_P1}, // 电压转换后的压力值(余油) {0x0220, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_para_indu}, // 2号并联电感值(余油) {0x0222, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_para_cap}, // 2号并联电容值(余油) {0x0224, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_cap_offset}, // 2号电容偏移值(余油) {0x0226, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v1_offset}, // 通道1电压数据偏移值(余油) // {0x0228, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 电容值滤波滑动窗口大小(余油) // {0x022A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 压力值滤波滑动窗口大小(余油) {0x022C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v2}, // 通道2电压原始电压值(温度) {0x022E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v2}, // 滤波后通道2电压值(温度) {0x0230, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v2_offset}, // 通道2电压数据偏移值(温度) // {0x0232, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 温度值滤波滑动窗口大小(温度) }; // Modbus CRC16(低位在前,高位在后) uint16_t modbus_crc16(uint8_t *data, uint16_t length) { uint16_t crc = 0xFFFF; for (uint16_t pos = 0; pos < length; pos++) { crc ^= data[pos]; for (int i = 0; i < 8; i++) { if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001; else crc >>= 1; } } return crc; } // 从映射表中查找寄存器并复制数据 bool read_modbus_registers(uint16_t addr, uint16_t len, uint8_t *dest_buf, uint16_t *out_byte_count) { uint16_t offset = 0; uint16_t remaining = len; uint16_t curr_addr = addr; while (remaining > 0) { bool matched = false; for (int i = 0; i < sizeof(modbus_map) / sizeof(modbus_map[0]); i++) { uint16_t map_start = modbus_map[i].address; uint16_t map_end = map_start + modbus_map[i].length; if (curr_addr >= map_start && curr_addr < map_end) { matched = true; uint16_t index_in_map = curr_addr - map_start; uint16_t can_read = map_end - curr_addr; uint16_t read_count = (remaining < can_read) ? remaining : can_read; void *ptr = modbus_map[i].data_ptr; switch (modbus_map[i].type) { case MODBUS_TYPE_UINT16: { uint16_t *data_ptr = (uint16_t *)ptr; for (uint16_t j = 0; j < read_count; j++) { uint16_t val = data_ptr[index_in_map + j]; dest_buf[offset++] = (val >> 8) & 0xFF; dest_buf[offset++] = val & 0xFF; } break; } case MODBUS_TYPE_UINT32_BE: { uint32_t *data_ptr = (uint32_t *)ptr; for (uint16_t j = 0; j < read_count; j++) { uint16_t reg_idx = index_in_map + j; uint32_t word_idx = reg_idx / 2; bool high = (reg_idx % 2 == 0); uint32_t val = data_ptr[word_idx]; uint16_t word = high ? (val >> 16) : (val & 0xFFFF); dest_buf[offset++] = (word >> 8) & 0xFF; dest_buf[offset++] = word & 0xFF; } break; } case MODBUS_TYPE_FLOAT_BE: { float *f_ptr = (float *)ptr; uint32_t temp; for (uint16_t j = 0; j < read_count; j++) { uint16_t reg_idx = index_in_map + j; uint32_t word_idx = reg_idx / 2; bool high = (reg_idx % 2 == 0); memcpy(&temp, &f_ptr[word_idx], sizeof(float)); // 将 float 拷贝为 uint32_t uint16_t word = high ? (temp >> 16) : (temp & 0xFFFF); // uint32_t 分为 uint16_t dest_buf[offset++] = (word >> 8) & 0xFF; dest_buf[offset++] = word & 0xFF; } break; } case MODBUS_TYPE_OILTYPE: { OilType *oil_ptr = (OilType *)ptr; uint16_t mapped_val = 0; switch (*oil_ptr) { case OIL_DIESEL: mapped_val = 0x0000; break; case OIL_92: mapped_val = 0x0092; break; case OIL_95: mapped_val = 0x0095; break; case OIL_98: mapped_val = 0x0098; break; default: mapped_val = 0xFFFF; break; } dest_buf[offset++] = (mapped_val >> 8) & 0xFF; dest_buf[offset++] = mapped_val & 0xFF; break; } default: return false; } curr_addr += read_count; remaining -= read_count; break; } } if (!matched) return false; } *out_byte_count = offset; return true; } // 将 uint32_t 数组按高字节优先方式拷贝为 Modbus 输出格式(每个 uint32_t 占 4 字节) void copy_uint32_to_modbus_bytes_be(uint32_t *src, uint16_t start_index, uint16_t word_count, uint8_t *dest_buf, uint16_t *offset) { for (uint16_t i = 0; i < word_count / 2; i++) { uint32_t val = src[start_index + i]; uint16_t high = (val >> 16) & 0xFFFF; uint16_t low = val & 0xFFFF; dest_buf[(*offset)++] = (high >> 8) & 0xFF; dest_buf[(*offset)++] = high & 0xFF; dest_buf[(*offset)++] = (low >> 8) & 0xFF; dest_buf[(*offset)++] = low & 0xFF; } } // 功能码 0x03 响应帧(角度浮点数值float) uint16_t modbus_03response_float(uint8_t device_addr, uint8_t num, float value, uint8_t *out_buf) { uint8_t i = 0; out_buf[i++] = device_addr; // 设备地址 out_buf[i++] = 0x03; // 功能码 0x03 out_buf[i++] = num; // 字节数(float = 4字节) // 将 float 转为 4 字节 IEEE 754 格式 uint8_t float_bytes[4]; memcpy(float_bytes, &value, 4); // 注意字节序是否和主机匹配 out_buf[i++] = float_bytes[3]; out_buf[i++] = float_bytes[2]; out_buf[i++] = float_bytes[1]; out_buf[i++] = float_bytes[0]; // 计算 CRC uint16_t crc = modbus_crc16(out_buf, i); out_buf[i++] = crc & 0xFF; // CRC低位 out_buf[i++] = crc >> 8; // CRC高位 return i; // 返回总长度 } // 返回错误响应帧,例如非法功能码、非法地址等错误 uint16_t modbus_error_response(uint8_t addr, uint8_t func_code, uint8_t err_code, uint8_t *buf) { buf[0] = addr; buf[1] = func_code | 0x80; // 错误码 = 功能码 + 0x80 buf[2] = err_code; uint16_t crc = modbus_crc16(buf, 3); buf[3] = crc & 0xFF; buf[4] = crc >> 8; return 5; } // 修改485串口1的波特率 void Set_485_Baudrate(uint16_t baudrate_id) { uint32_t baudrate = 9600; // 默认值 // 根据 ID 映射波特率 switch (baudrate_id) { case 0x0000: baudrate = 9600; break; case 0x0001: baudrate = 4800; break; case 0x0002: baudrate = 9600; break; case 0x0003: baudrate = 14400; break; case 0x0004: baudrate = 19200; break; case 0x0005: baudrate = 38400; break; case 0x0006: baudrate = 56000; break; case 0x0007: baudrate = 57600; break; case 0x0008: baudrate = 115200; break; default: baudrate = 9600; break; // 非法 ID,默认 9600 } // 重新设置 huart1 配置并初始化 huart1.Instance = USART1; huart1.Init.BaudRate = baudrate; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_DeInit(&huart1) != HAL_OK) { Error_Handler(); } if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } } /** * 06写单寄存器相关函数 ***/ // 设置从机地址 bool handle_slave_addr(uint16_t value) { JsRoot.addr = value; DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_ADDR , JsRoot.addr ); // addr 存入到SNAPSHOT数据库 return true; } // 设置波特率并立即生效 bool handle_baudrate(uint16_t value) { if (value <= 0x0008) { JsRoot.baudrate = value; DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_BAUDRATE , JsRoot.baudrate ); // 波特率存入到SNAPSHOT数据库 osDelay(100); Set_485_Baudrate(value); const char* msg = "New baudrate applied\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100); Restart_UART1_DMA(); return true; } return false; } // 重启命令 bool handle_reboot(uint16_t value) { if (value == 0x0001) { // 构造应答 uint16_t len = 0; uint8_t tx_buf[8] = {0}; tx_buf[len++] = JsRoot.addr; tx_buf[len++] = 0x06; tx_buf[len++] = 0x40; tx_buf[len++] = 0x40; tx_buf[len++] = 0x00; tx_buf[len++] = 0x01; uint16_t crc = modbus_crc16(tx_buf, len); tx_buf[len++] = crc & 0xFF; tx_buf[len++] = (crc >> 8) & 0xFF; uart485send(tx_buf, len); osDelay(50); NVIC_SystemReset(); return true; } return false; } // 恢复出厂 bool handle_factory_reset(uint16_t value) { if (value == 0x55AA) { JsRoot.iapLoadStatus = 0; JsRoot.ubootback = 1; DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_UBOOTBACK , JsRoot.ubootback ); // bootloader 状态码存入到SNAPSHOT数据库 DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_IAP_LOAD , JsRoot.iapLoadStatus ); // 装载状态存入到SNAPSHOT数据库 osDelay(100); // 构造应答 uint16_t len = 0; uint8_t tx_buf[8] = {0}; tx_buf[len++] = JsRoot.addr; tx_buf[len++] = 0x06; tx_buf[len++] = 0x40; tx_buf[len++] = 0x42; tx_buf[len++] = 0x55; tx_buf[len++] = 0xAA; uint16_t crc = modbus_crc16(tx_buf, len); tx_buf[len++] = crc & 0xFF; tx_buf[len++] = (crc >> 8) & 0xFF; uart485send(tx_buf, len); osDelay(100); NVIC_SystemReset(); return true; } return false; } bool handle_float_write(uint16_t raw, float* target) { float value; memcpy(&value, &raw, sizeof(uint16_t)); *target = value; // Save_CalibPoints_ToFlash(); return true; } bool handle_uint16_t_write(uint16_t raw, uint16_t* target) { *target = raw; // 直接赋值 // Save_CalibPoints_ToFlash(); // 保存到Flash return true; } static bool handle_uint16_t_oil_type(uint16_t v) { switch (v) { case 0x00: // 写 0x00 -> 柴油 g_oil_type = OIL_DIESEL; break; case 0x92: // 写 0x92 -> 92# g_oil_type = OIL_92; break; case 0x95: g_oil_type = OIL_95; break; case 0x98: g_oil_type = OIL_98; break; default: return false; } // Save_CalibPoints_ToFlash(); // 保存到 Flash return true; } // 06写指令应答结构体 ModbusWriteRegister_t WriteReg_map[] = { {0x4010, handle_slave_addr}, {0x4011, handle_baudrate}, {0x4040, handle_reboot}, {0x4042, handle_factory_reset}, {0x0100, handle_uint16_t_oil_type}, // 油品 }; size_t REGISTER_MAP_SIZE = sizeof(WriteReg_map) / sizeof(WriteReg_map[0]); /** * 10写多寄存器相关函数 ***/ bool handle_float_multi(uint16_t *values, void *arg) { float f; memcpy(&f, values, sizeof(float)); *(float *)arg = f; // 直接写到目标变量 // Save_CalibPoints_ToFlash(); return true; } // 10多寄存器写映射表 ModbusWriteMultiRegister_t WriteMultiReg_map[] = { // --- 阀杆电压标定值 --- {0x0102, 2, handle_float_multi, &JsWork.calib_rod.vol_values[0]}, {0x0104, 2, handle_float_multi, &JsWork.calib_rod.vol_values[1]}, {0x0106, 2, handle_float_multi, &JsWork.calib_rod.vol_values[2]}, {0x0108, 2, handle_float_multi, &JsWork.calib_rod.vol_values[3]}, {0x010A, 2, handle_float_multi, &JsWork.calib_rod.vol_values[4]}, {0x010C, 2, handle_float_multi, &JsWork.calib_rod.vol_values[5]}, {0x010E, 2, handle_float_multi, &JsWork.calib_rod.vol_values[6]}, // --- 油水电容标定值 --- {0x0110, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[0]}, {0x0112, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[1]}, {0x0114, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[2]}, {0x0116, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[3]}, {0x0118, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[4]}, {0x011A, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[5]}, {0x011C, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[6]}, {0x011E, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[7]}, {0x0120, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[8]}, {0x0122, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[9]}, {0x0124, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[10]}, // --- 余油电容标定值 --- {0x0126, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[0]}, {0x0128, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[1]}, {0x012A, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[2]}, {0x012C, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[3]}, {0x012E, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[4]}, {0x0130, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[5]}, // --- 余油电压标定值 --- {0x0132, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[0]}, {0x0134, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[1]}, {0x0136, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[2]}, {0x0138, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[3]}, {0x013A, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[4]}, {0x013C, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[5]}, // --- 阀杆计算相关 --- {0x0206, 2, handle_float_multi, (void *)&ADS_v0_offset}, // 通道0电压数据偏移值(阀杆) // {0x0208, 2, handle_float_multi, (void *)&}, // 电压值滤波滑动窗口大小(阀杆) // --- 油水计算相关 --- {0x020E, 2, handle_float_multi, (void *)&oil_para_indu}, // 1号并联电感值(油水) {0x0210, 2, handle_float_multi, (void *)&oil_para_cap}, // 1号并联电容值(油水) {0x0212, 2, handle_float_multi, (void *)&oil_cap_offset}, // 1号电容偏移值(油水) // {0x0214, 2, handle_float_multi, (void *)&}, // 电容值滤波滑动窗口大小(油水) // --- 余油计算相关 --- {0x0220, 2, handle_float_multi, (void *)&res_oil_para_indu}, // 2号并联电感值(余油) {0x0222, 2, handle_float_multi, (void *)&res_oil_para_cap}, // 2号并联电容值(余油) {0x0224, 2, handle_float_multi, (void *)&res_oil_cap_offset}, // 2号电容偏移值(余油) {0x0226, 2, handle_float_multi, (void *)&ADS_v1_offset}, // 通道1电压数据偏移值(余油) // {0x0228, 2, handle_float_multi, (void *)&}, // 电容值滤波滑动窗口大小(余油) // {0x022A, 2, handle_float_multi, (void *)&}, // 电压值滤波滑动窗口大小(余油) // --- 温度计算相关 --- {0x0230, 2, handle_float_multi, (void *)&ADS_v2_offset}, // 通道2电压数据偏移值(温度) // {0x0232, 2, handle_float_multi, (void *)&}, // 温度值滤波滑动窗口大小(温度) }; size_t MULTI_REGISTER_MAP_SIZE = sizeof(WriteMultiReg_map) / sizeof(WriteMultiReg_map[0]); /******************************************************************************************************************** * 做主机时使用 * *********************************************************************************************************************/ // Modbus 读保持寄存器命令帧(功能码 0x03) uint16_t build_modbus_read_cmd(uint8_t device_addr, uint16_t reg_addr, uint16_t reg_num, uint8_t *out_buf) { uint16_t i = 0; out_buf[i++] = device_addr; // 设备地址 out_buf[i++] = 0x03; // 功能码 0x03 读保持寄存器 out_buf[i++] = (reg_addr >> 8) & 0xFF; // 起始寄存器地址高位 out_buf[i++] = reg_addr & 0xFF; // 起始寄存器地址低位 out_buf[i++] = (reg_num >> 8) & 0xFF; // 读取寄存器数量高位 out_buf[i++] = reg_num & 0xFF; // 读取寄存器数量低位 uint16_t crc = modbus_crc16(out_buf, i); out_buf[i++] = crc & 0xFF; // CRC低位 out_buf[i++] = crc >> 8; // CRC高位 return i; // 命令帧总长度 } // Modbus 功能码0x10的写寄存器命令 // data: uint16_t 数组,每个元素是一个寄存器的数据(2字节) // 返回帧长度 uint16_t build_modbus_write_cmd(uint8_t device_addr, uint8_t func_code, uint16_t reg_addr, uint16_t reg_count, uint16_t *data, uint8_t *out_buf) { uint8_t byte_count = reg_count * 2; uint16_t i = 0; out_buf[i++] = device_addr; // 设备地址 out_buf[i++] = func_code; // 功能码(0x10) out_buf[i++] = (reg_addr >> 8) & 0xFF; // 起始寄存器地址高8位 out_buf[i++] = reg_addr & 0xFF; // 起始寄存器地址低8位 out_buf[i++] = (reg_count >> 8) & 0xFF; // 寄存器数量高8位 out_buf[i++] = reg_count & 0xFF; // 寄存器数量低8位 out_buf[i++] = byte_count; // 数据字节数 // 写入数据(每个寄存器2字节) for (uint16_t j = 0; j < reg_count; j++) { out_buf[i++] = (data[j] >> 8) & 0xFF; out_buf[i++] = data[j] & 0xFF; } // 计算 CRC uint16_t crc = modbus_crc16(out_buf, i); out_buf[i++] = crc & 0xFF; // CRC低位 out_buf[i++] = crc >> 8; // CRC高位 return i; // 返回命令总长度 }