Modbussimple.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. #include "main.h"
  2. #include "Modbussimple.h"
  3. #include "cmsis_os.h"
  4. #include "Callback.h"
  5. #include "uType.h"
  6. JsonDat_Work JsWork;
  7. uint32_t g_modbusbuffer[40] ; // 当用DMA发送的时候 帧头要四字节对齐
  8. /*阀杆相关参数定义*/
  9. extern volatile float Value_open_percent; // 阀杆开行程百分比
  10. extern volatile float Value_open_mm; // 阀杆开行程mm
  11. extern volatile float MPXV_P0; // 阀杆压力值
  12. extern volatile float ADS_v0; // ads1256 通道0原始电压值
  13. extern volatile float filtered_ADS_v0; // 滤波后的阀杆电压值
  14. extern volatile float ADS_v0_offset; // ads1256 通道0电压偏移(将结果乘1000倍再赋值) 0.008*1000 = 8.0
  15. // extern volatile float // 阀杆压力值滤波滑动窗口大小
  16. /*油水相关参数定义*/
  17. extern volatile float filtered_oil_cap; // 滤波后的油水电容值
  18. extern volatile float oil_percent; // 油水百分比
  19. extern volatile float oil_cap;// 原始电容值
  20. extern volatile float oil_para_indu; // 并联电感值
  21. extern volatile float oil_para_cap; // 并联电容值
  22. extern volatile float oil_cap_offset;// 油水电容偏移值
  23. // extern volatile float // 油水电容值滤波滑动窗口大小
  24. /*余油相关参数定义*/
  25. extern volatile float ADS_v1; // ads1256 通道1原始电压值
  26. extern volatile float filtered_res_oil_cap; // 滤波后的电容值
  27. extern volatile float MPXV_P1; // 余油压力值(kpa)
  28. extern volatile float res_oil_height; // 余油高度值(mm)
  29. extern volatile float res_oil_cap; // // 软件IIC 2号(PB10PB11)测得原始电容值
  30. extern volatile float ADS_v1; // ads1256 通道1原始电压值
  31. extern volatile float filtered_ADS_v1; // 滤波之后ads1256 通道1电压值
  32. extern volatile float res_oil_para_indu; // 并联电感值
  33. extern volatile float res_oil_para_cap; // 并联电容值
  34. extern volatile float res_oil_cap_offset;// 余油电容偏移值
  35. extern volatile float ADS_v1_offset; // ads1256 通道1电压偏移值(将结果乘1000倍再赋值)
  36. // extern volatile float // 余油电容值滤波滑动窗口大小
  37. // extern volatile float // 余油压力值滤波滑动窗口大小
  38. /*温度相关参数定义*/
  39. extern volatile float ADS_v2; // ads1256 通道2原始电压值
  40. extern volatile float filtered_ADS_v2; // 滤波后的电压值
  41. extern volatile float NTC_temp; // 电压查RT表转换后的温度值(℃)
  42. extern volatile float ADS_v2; // ads1256 通道2原始电压值
  43. extern volatile float ADS_v2_offset; // ads1256 通道2电压偏移值(将结果乘1000倍再赋值)
  44. // extern volatile float // 温度滤波滑动窗口大小
  45. // 03读指令应答结构体
  46. ModbusRegister_t modbus_map[] = {
  47. {0x4000, 2, MODBUS_TYPE_UINT32_BE, &JsRoot.vers_id},// 固件版本号
  48. {0x4002, 1, MODBUS_TYPE_UINT16, &JsRoot.age}, // 运行时长
  49. {0x4010, 1, MODBUS_TYPE_UINT16, &JsRoot.addr}, // 从机设备地址
  50. {0x4011, 1, MODBUS_TYPE_UINT16, &JsRoot.baudrate}, // 波特率
  51. {0x4020, 3, MODBUS_TYPE_UINT16, &JsRoot.mac}, // 设备SN号
  52. {0x0000, 2, MODBUS_TYPE_FLOAT_BE, (void *)&Value_open_percent}, // 阀杆开行程百分比
  53. {0x0002, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_percent}, // 油水百分比
  54. {0x0004, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_height}, // 余油液位高度值(mm)
  55. {0x0006, 2, MODBUS_TYPE_FLOAT_BE, (void *)&NTC_temp}, // 温度摄氏度
  56. {0x0100, 1, MODBUS_TYPE_OILTYPE, (void*)&g_oil_type}, // 油品
  57. {0x0102, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[0]}, // 阀杆电压标定值(对应0mm行程)
  58. {0x0104, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[1]}, // 阀杆电压标定值(对应1mm行程)
  59. {0x0106, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[2]}, // 阀杆电压标定值(对应2mm行程)
  60. {0x0108, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[3]}, // 阀杆电压标定值(对应3mm行程)
  61. {0x010A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[4]}, // 阀杆电压标定值(对应4mm行程)
  62. {0x010C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[5]}, // 阀杆电压标定值(对应5mm行程)
  63. {0x010E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_rod.vol_values[6]}, // 阀杆电压标定值(对应6mm行程)
  64. {0x0110, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[0]}, // 油水电容标定值(对应90%配比)
  65. {0x0112, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[1]}, // 油水电容标定值(对应91%配比)
  66. {0x0114, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[2]}, // 油水电容标定值(对应92%配比)
  67. {0x0116, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[3]}, // 油水电容标定值(对应93%配比)
  68. {0x0118, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[4]}, // 油水电容标定值(对应94%配比)
  69. {0x011A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[5]}, // 油水电容标定值(对应95%配比)
  70. {0x011C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[6]}, // 油水电容标定值(对应96%配比)
  71. {0x011E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[7]}, // 油水电容标定值(对应97%配比)
  72. {0x0120, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[8]}, // 油水电容标定值(对应98%配比)
  73. {0x0122, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[9]}, // 油水电容标定值(对应99%配比)
  74. {0x0124, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_oil_water.cap_values[10]}, // 油水电容标定值(对应100%配比)
  75. {0x0126, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[0]}, // 余液电容标定值(1cm液位高度)
  76. {0x0128, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[1]}, // 余液电容标定值(2cm液位高度)
  77. {0x012A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[2]}, // 余液电容标定值(3cm液位高度)
  78. {0x012C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[3]}, // 余液电容标定值(4cm液位高度)
  79. {0x012E, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[4]}, // 余液电容标定值(5cm液位高度)
  80. {0x0130, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.cap_values[5]}, // 余液电容标定值(6cm液位高度)
  81. {0x0132, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[0]}, // 余液压力传感器电压标定值(1cm液位高度)
  82. {0x0134, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[1]}, // 余液压力传感器电压标定值(2cm液位高度)
  83. {0x0136, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[2]}, // 余液压力传感器电压标定值(3cm液位高度)
  84. {0x0138, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[3]}, // 余液压力传感器电压标定值(4cm液位高度)
  85. {0x013A, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[4]}, // 余液压力传感器电压标定值(5cm液位高度)
  86. {0x013C, 2, MODBUS_TYPE_FLOAT_BE, &JsWork.calib_residual_oil.vol_values[5]}, // 余液压力传感器电压标定值(6cm液位高度)
  87. {0x0200, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v0}, // 通道0电压原始数据(阀杆)
  88. {0x0202, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v0}, // 滤波后通道0电压数据(阀杆)
  89. {0x0204, 2, MODBUS_TYPE_FLOAT_BE, (void *)&MPXV_P0}, // 电压转换后的压力值(阀杆)
  90. {0x0206, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v0_offset}, // 通道0电压数据偏移值(阀杆)
  91. // {0x0208, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 压力值滤波滑动窗口大小(阀杆)
  92. {0x020A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_cap}, // 1号电容原始电容值(油水)
  93. {0x020C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_oil_cap}, // 滤波后油水电容值
  94. {0x020E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_para_indu}, // 1号并联电感值(油水)
  95. {0x0210, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_para_cap}, // 1号并联电容值(油水)
  96. {0x0212, 2, MODBUS_TYPE_FLOAT_BE, (void *)&oil_cap_offset}, // 1号电容偏移值(油水)
  97. // {0x0214, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 电容值滤波滑动窗口大小(油水)
  98. {0x0216, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_cap}, // 2号电容原始电容值(余油)
  99. {0x0218, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_res_oil_cap}, // 滤波之后的电容值(余油)
  100. {0x021A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v1}, // 通道1电压原始数据(余油)
  101. {0x021C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v1}, // 滤波后电压值(余油)
  102. {0x021E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&MPXV_P1}, // 电压转换后的压力值(余油)
  103. {0x0220, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_para_indu}, // 2号并联电感值(余油)
  104. {0x0222, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_para_cap}, // 2号并联电容值(余油)
  105. {0x0224, 2, MODBUS_TYPE_FLOAT_BE, (void *)&res_oil_cap_offset}, // 2号电容偏移值(余油)
  106. {0x0226, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v1_offset}, // 通道1电压数据偏移值(余油)
  107. // {0x0228, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 电容值滤波滑动窗口大小(余油)
  108. // {0x022A, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 压力值滤波滑动窗口大小(余油)
  109. {0x022C, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v2}, // 通道2电压原始电压值(温度)
  110. {0x022E, 2, MODBUS_TYPE_FLOAT_BE, (void *)&filtered_ADS_v2}, // 滤波后通道2电压值(温度)
  111. {0x0230, 2, MODBUS_TYPE_FLOAT_BE, (void *)&ADS_v2_offset}, // 通道2电压数据偏移值(温度)
  112. // {0x0232, 2, MODBUS_TYPE_FLOAT_BE, (void *)&}, // 温度值滤波滑动窗口大小(温度)
  113. };
  114. // Modbus CRC16(低位在前,高位在后)
  115. uint16_t modbus_crc16(uint8_t *data, uint16_t length)
  116. {
  117. uint16_t crc = 0xFFFF;
  118. for (uint16_t pos = 0; pos < length; pos++) {
  119. crc ^= data[pos];
  120. for (int i = 0; i < 8; i++) {
  121. if (crc & 0x0001)
  122. crc = (crc >> 1) ^ 0xA001;
  123. else
  124. crc >>= 1;
  125. }
  126. }
  127. return crc;
  128. }
  129. // 从映射表中查找寄存器并复制数据
  130. bool read_modbus_registers(uint16_t addr, uint16_t len, uint8_t *dest_buf, uint16_t *out_byte_count)
  131. {
  132. uint16_t offset = 0;
  133. uint16_t remaining = len;
  134. uint16_t curr_addr = addr;
  135. while (remaining > 0) {
  136. bool matched = false;
  137. for (int i = 0; i < sizeof(modbus_map) / sizeof(modbus_map[0]); i++) {
  138. uint16_t map_start = modbus_map[i].address;
  139. uint16_t map_end = map_start + modbus_map[i].length;
  140. if (curr_addr >= map_start && curr_addr < map_end) {
  141. matched = true;
  142. uint16_t index_in_map = curr_addr - map_start;
  143. uint16_t can_read = map_end - curr_addr;
  144. uint16_t read_count = (remaining < can_read) ? remaining : can_read;
  145. void *ptr = modbus_map[i].data_ptr;
  146. switch (modbus_map[i].type) {
  147. case MODBUS_TYPE_UINT16: {
  148. uint16_t *data_ptr = (uint16_t *)ptr;
  149. for (uint16_t j = 0; j < read_count; j++) {
  150. uint16_t val = data_ptr[index_in_map + j];
  151. dest_buf[offset++] = (val >> 8) & 0xFF;
  152. dest_buf[offset++] = val & 0xFF;
  153. }
  154. break;
  155. }
  156. case MODBUS_TYPE_UINT32_BE: {
  157. uint32_t *data_ptr = (uint32_t *)ptr;
  158. for (uint16_t j = 0; j < read_count; j++) {
  159. uint16_t reg_idx = index_in_map + j;
  160. uint32_t word_idx = reg_idx / 2;
  161. bool high = (reg_idx % 2 == 0);
  162. uint32_t val = data_ptr[word_idx];
  163. uint16_t word = high ? (val >> 16) : (val & 0xFFFF);
  164. dest_buf[offset++] = (word >> 8) & 0xFF;
  165. dest_buf[offset++] = word & 0xFF;
  166. }
  167. break;
  168. }
  169. case MODBUS_TYPE_FLOAT_BE: {
  170. float *f_ptr = (float *)ptr;
  171. uint32_t temp;
  172. for (uint16_t j = 0; j < read_count; j++) {
  173. uint16_t reg_idx = index_in_map + j;
  174. uint32_t word_idx = reg_idx / 2;
  175. bool high = (reg_idx % 2 == 0);
  176. memcpy(&temp, &f_ptr[word_idx], sizeof(float)); // 将 float 拷贝为 uint32_t
  177. uint16_t word = high ? (temp >> 16) : (temp & 0xFFFF); // uint32_t 分为 uint16_t
  178. dest_buf[offset++] = (word >> 8) & 0xFF;
  179. dest_buf[offset++] = word & 0xFF;
  180. }
  181. break;
  182. }
  183. case MODBUS_TYPE_OILTYPE: {
  184. OilType *oil_ptr = (OilType *)ptr;
  185. uint16_t mapped_val = 0;
  186. switch (*oil_ptr) {
  187. case OIL_DIESEL: mapped_val = 0x0000; break;
  188. case OIL_92: mapped_val = 0x0092; break;
  189. case OIL_95: mapped_val = 0x0095; break;
  190. case OIL_98: mapped_val = 0x0098; break;
  191. default: mapped_val = 0xFFFF; break;
  192. }
  193. dest_buf[offset++] = (mapped_val >> 8) & 0xFF;
  194. dest_buf[offset++] = mapped_val & 0xFF;
  195. break;
  196. }
  197. default:
  198. return false;
  199. }
  200. curr_addr += read_count;
  201. remaining -= read_count;
  202. break;
  203. }
  204. }
  205. if (!matched) return false;
  206. }
  207. *out_byte_count = offset;
  208. return true;
  209. }
  210. // 将 uint32_t 数组按高字节优先方式拷贝为 Modbus 输出格式(每个 uint32_t 占 4 字节)
  211. 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)
  212. {
  213. for (uint16_t i = 0; i < word_count / 2; i++) {
  214. uint32_t val = src[start_index + i];
  215. uint16_t high = (val >> 16) & 0xFFFF;
  216. uint16_t low = val & 0xFFFF;
  217. dest_buf[(*offset)++] = (high >> 8) & 0xFF;
  218. dest_buf[(*offset)++] = high & 0xFF;
  219. dest_buf[(*offset)++] = (low >> 8) & 0xFF;
  220. dest_buf[(*offset)++] = low & 0xFF;
  221. }
  222. }
  223. // 功能码 0x03 响应帧(角度浮点数值float)
  224. uint16_t modbus_03response_float(uint8_t device_addr, uint8_t num, float value, uint8_t *out_buf)
  225. {
  226. uint8_t i = 0;
  227. out_buf[i++] = device_addr; // 设备地址
  228. out_buf[i++] = 0x03; // 功能码 0x03
  229. out_buf[i++] = num; // 字节数(float = 4字节)
  230. // 将 float 转为 4 字节 IEEE 754 格式
  231. uint8_t float_bytes[4];
  232. memcpy(float_bytes, &value, 4);
  233. // 注意字节序是否和主机匹配
  234. out_buf[i++] = float_bytes[3];
  235. out_buf[i++] = float_bytes[2];
  236. out_buf[i++] = float_bytes[1];
  237. out_buf[i++] = float_bytes[0];
  238. // 计算 CRC
  239. uint16_t crc = modbus_crc16(out_buf, i);
  240. out_buf[i++] = crc & 0xFF; // CRC低位
  241. out_buf[i++] = crc >> 8; // CRC高位
  242. return i; // 返回总长度
  243. }
  244. // 返回错误响应帧,例如非法功能码、非法地址等错误
  245. uint16_t modbus_error_response(uint8_t addr, uint8_t func_code, uint8_t err_code, uint8_t *buf)
  246. {
  247. buf[0] = addr;
  248. buf[1] = func_code | 0x80; // 错误码 = 功能码 + 0x80
  249. buf[2] = err_code;
  250. uint16_t crc = modbus_crc16(buf, 3);
  251. buf[3] = crc & 0xFF;
  252. buf[4] = crc >> 8;
  253. return 5;
  254. }
  255. // 修改485串口1的波特率
  256. void Set_485_Baudrate(uint16_t baudrate_id)
  257. {
  258. uint32_t baudrate = 9600; // 默认值
  259. // 根据 ID 映射波特率
  260. switch (baudrate_id)
  261. {
  262. case 0x0000: baudrate = 9600; break;
  263. case 0x0001: baudrate = 4800; break;
  264. case 0x0002: baudrate = 9600; break;
  265. case 0x0003: baudrate = 14400; break;
  266. case 0x0004: baudrate = 19200; break;
  267. case 0x0005: baudrate = 38400; break;
  268. case 0x0006: baudrate = 56000; break;
  269. case 0x0007: baudrate = 57600; break;
  270. case 0x0008: baudrate = 115200; break;
  271. default: baudrate = 9600; break; // 非法 ID,默认 9600
  272. }
  273. // 重新设置 huart1 配置并初始化
  274. huart1.Instance = USART1;
  275. huart1.Init.BaudRate = baudrate;
  276. huart1.Init.WordLength = UART_WORDLENGTH_8B;
  277. huart1.Init.StopBits = UART_STOPBITS_1;
  278. huart1.Init.Parity = UART_PARITY_NONE;
  279. huart1.Init.Mode = UART_MODE_TX_RX;
  280. huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  281. huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  282. huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  283. huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  284. if (HAL_UART_DeInit(&huart1) != HAL_OK)
  285. {
  286. Error_Handler();
  287. }
  288. if (HAL_UART_Init(&huart1) != HAL_OK)
  289. {
  290. Error_Handler();
  291. }
  292. }
  293. /**
  294. * 06写单寄存器相关函数
  295. ***/
  296. // 设置从机地址
  297. bool handle_slave_addr(uint16_t value) {
  298. JsRoot.addr = value;
  299. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_ADDR , JsRoot.addr ); // addr 存入到SNAPSHOT数据库
  300. return true;
  301. }
  302. // 设置波特率并立即生效
  303. bool handle_baudrate(uint16_t value) {
  304. if (value <= 0x0008) {
  305. JsRoot.baudrate = value;
  306. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_BAUDRATE , JsRoot.baudrate ); // 波特率存入到SNAPSHOT数据库
  307. osDelay(100);
  308. Set_485_Baudrate(value);
  309. const char* msg = "New baudrate applied\r\n";
  310. HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100);
  311. Restart_UART1_DMA();
  312. return true;
  313. }
  314. return false;
  315. }
  316. // 重启命令
  317. bool handle_reboot(uint16_t value) {
  318. if (value == 0x0001) {
  319. // 构造应答
  320. uint16_t len = 0;
  321. uint8_t tx_buf[8] = {0};
  322. tx_buf[len++] = JsRoot.addr;
  323. tx_buf[len++] = 0x06;
  324. tx_buf[len++] = 0x40;
  325. tx_buf[len++] = 0x40;
  326. tx_buf[len++] = 0x00;
  327. tx_buf[len++] = 0x01;
  328. uint16_t crc = modbus_crc16(tx_buf, len);
  329. tx_buf[len++] = crc & 0xFF;
  330. tx_buf[len++] = (crc >> 8) & 0xFF;
  331. uart485send(tx_buf, len);
  332. osDelay(50);
  333. NVIC_SystemReset();
  334. return true;
  335. }
  336. return false;
  337. }
  338. // 恢复出厂
  339. bool handle_factory_reset(uint16_t value) {
  340. if (value == 0x55AA) {
  341. JsRoot.iapLoadStatus = 0;
  342. JsRoot.ubootback = 1;
  343. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_UBOOTBACK , JsRoot.ubootback ); // bootloader 状态码存入到SNAPSHOT数据库
  344. DB_SaveUInt(DB_ID_SNAPSHOT, KV_KEY_IAP_LOAD , JsRoot.iapLoadStatus ); // 装载状态存入到SNAPSHOT数据库
  345. osDelay(100);
  346. // 构造应答
  347. uint16_t len = 0;
  348. uint8_t tx_buf[8] = {0};
  349. tx_buf[len++] = JsRoot.addr;
  350. tx_buf[len++] = 0x06;
  351. tx_buf[len++] = 0x40;
  352. tx_buf[len++] = 0x42;
  353. tx_buf[len++] = 0x55;
  354. tx_buf[len++] = 0xAA;
  355. uint16_t crc = modbus_crc16(tx_buf, len);
  356. tx_buf[len++] = crc & 0xFF;
  357. tx_buf[len++] = (crc >> 8) & 0xFF;
  358. uart485send(tx_buf, len);
  359. osDelay(100);
  360. NVIC_SystemReset();
  361. return true;
  362. }
  363. return false;
  364. }
  365. bool handle_float_write(uint16_t raw, float* target) {
  366. float value;
  367. memcpy(&value, &raw, sizeof(uint16_t));
  368. *target = value;
  369. // Save_CalibPoints_ToFlash();
  370. return true;
  371. }
  372. bool handle_uint16_t_write(uint16_t raw, uint16_t* target) {
  373. *target = raw; // 直接赋值
  374. // Save_CalibPoints_ToFlash(); // 保存到Flash
  375. return true;
  376. }
  377. static bool handle_uint16_t_oil_type(uint16_t v) {
  378. switch (v) {
  379. case 0x00: // 写 0x00 -> 柴油
  380. g_oil_type = OIL_DIESEL;
  381. break;
  382. case 0x92: // 写 0x92 -> 92#
  383. g_oil_type = OIL_92;
  384. break;
  385. case 0x95:
  386. g_oil_type = OIL_95;
  387. break;
  388. case 0x98:
  389. g_oil_type = OIL_98;
  390. break;
  391. default:
  392. return false;
  393. }
  394. // Save_CalibPoints_ToFlash(); // 保存到 Flash
  395. return true;
  396. }
  397. // 06写指令应答结构体
  398. ModbusWriteRegister_t WriteReg_map[] = {
  399. {0x4010, handle_slave_addr},
  400. {0x4011, handle_baudrate},
  401. {0x4040, handle_reboot},
  402. {0x4042, handle_factory_reset},
  403. {0x0100, handle_uint16_t_oil_type}, // 油品
  404. };
  405. size_t REGISTER_MAP_SIZE = sizeof(WriteReg_map) / sizeof(WriteReg_map[0]);
  406. /**
  407. * 10写多寄存器相关函数
  408. ***/
  409. bool handle_float_multi(uint16_t *values, void *arg) {
  410. float f;
  411. memcpy(&f, values, sizeof(float));
  412. *(float *)arg = f; // 直接写到目标变量
  413. // Save_CalibPoints_ToFlash();
  414. return true;
  415. }
  416. // 10多寄存器写映射表
  417. ModbusWriteMultiRegister_t WriteMultiReg_map[] = {
  418. // --- 阀杆电压标定值 ---
  419. {0x0102, 2, handle_float_multi, &JsWork.calib_rod.vol_values[0]},
  420. {0x0104, 2, handle_float_multi, &JsWork.calib_rod.vol_values[1]},
  421. {0x0106, 2, handle_float_multi, &JsWork.calib_rod.vol_values[2]},
  422. {0x0108, 2, handle_float_multi, &JsWork.calib_rod.vol_values[3]},
  423. {0x010A, 2, handle_float_multi, &JsWork.calib_rod.vol_values[4]},
  424. {0x010C, 2, handle_float_multi, &JsWork.calib_rod.vol_values[5]},
  425. {0x010E, 2, handle_float_multi, &JsWork.calib_rod.vol_values[6]},
  426. // --- 油水电容标定值 ---
  427. {0x0110, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[0]},
  428. {0x0112, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[1]},
  429. {0x0114, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[2]},
  430. {0x0116, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[3]},
  431. {0x0118, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[4]},
  432. {0x011A, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[5]},
  433. {0x011C, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[6]},
  434. {0x011E, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[7]},
  435. {0x0120, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[8]},
  436. {0x0122, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[9]},
  437. {0x0124, 2, handle_float_multi, &JsWork.calib_oil_water.cap_values[10]},
  438. // --- 余油电容标定值 ---
  439. {0x0126, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[0]},
  440. {0x0128, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[1]},
  441. {0x012A, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[2]},
  442. {0x012C, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[3]},
  443. {0x012E, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[4]},
  444. {0x0130, 2, handle_float_multi, &JsWork.calib_residual_oil.cap_values[5]},
  445. // --- 余油电压标定值 ---
  446. {0x0132, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[0]},
  447. {0x0134, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[1]},
  448. {0x0136, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[2]},
  449. {0x0138, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[3]},
  450. {0x013A, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[4]},
  451. {0x013C, 2, handle_float_multi, &JsWork.calib_residual_oil.vol_values[5]},
  452. // --- 阀杆计算相关 ---
  453. {0x0206, 2, handle_float_multi, (void *)&ADS_v0_offset}, // 通道0电压数据偏移值(阀杆)
  454. // {0x0208, 2, handle_float_multi, (void *)&}, // 电压值滤波滑动窗口大小(阀杆)
  455. // --- 油水计算相关 ---
  456. {0x020E, 2, handle_float_multi, (void *)&oil_para_indu}, // 1号并联电感值(油水)
  457. {0x0210, 2, handle_float_multi, (void *)&oil_para_cap}, // 1号并联电容值(油水)
  458. {0x0212, 2, handle_float_multi, (void *)&oil_cap_offset}, // 1号电容偏移值(油水)
  459. // {0x0214, 2, handle_float_multi, (void *)&}, // 电容值滤波滑动窗口大小(油水)
  460. // --- 余油计算相关 ---
  461. {0x0220, 2, handle_float_multi, (void *)&res_oil_para_indu}, // 2号并联电感值(余油)
  462. {0x0222, 2, handle_float_multi, (void *)&res_oil_para_cap}, // 2号并联电容值(余油)
  463. {0x0224, 2, handle_float_multi, (void *)&res_oil_cap_offset}, // 2号电容偏移值(余油)
  464. {0x0226, 2, handle_float_multi, (void *)&ADS_v1_offset}, // 通道1电压数据偏移值(余油)
  465. // {0x0228, 2, handle_float_multi, (void *)&}, // 电容值滤波滑动窗口大小(余油)
  466. // {0x022A, 2, handle_float_multi, (void *)&}, // 电压值滤波滑动窗口大小(余油)
  467. // --- 温度计算相关 ---
  468. {0x0230, 2, handle_float_multi, (void *)&ADS_v2_offset}, // 通道2电压数据偏移值(温度)
  469. // {0x0232, 2, handle_float_multi, (void *)&}, // 温度值滤波滑动窗口大小(温度)
  470. };
  471. size_t MULTI_REGISTER_MAP_SIZE = sizeof(WriteMultiReg_map) / sizeof(WriteMultiReg_map[0]);
  472. /********************************************************************************************************************
  473. * 做主机时使用
  474. *
  475. *********************************************************************************************************************/
  476. // Modbus 读保持寄存器命令帧(功能码 0x03)
  477. uint16_t build_modbus_read_cmd(uint8_t device_addr, uint16_t reg_addr, uint16_t reg_num, uint8_t *out_buf)
  478. {
  479. uint16_t i = 0;
  480. out_buf[i++] = device_addr; // 设备地址
  481. out_buf[i++] = 0x03; // 功能码 0x03 读保持寄存器
  482. out_buf[i++] = (reg_addr >> 8) & 0xFF; // 起始寄存器地址高位
  483. out_buf[i++] = reg_addr & 0xFF; // 起始寄存器地址低位
  484. out_buf[i++] = (reg_num >> 8) & 0xFF; // 读取寄存器数量高位
  485. out_buf[i++] = reg_num & 0xFF; // 读取寄存器数量低位
  486. uint16_t crc = modbus_crc16(out_buf, i);
  487. out_buf[i++] = crc & 0xFF; // CRC低位
  488. out_buf[i++] = crc >> 8; // CRC高位
  489. return i; // 命令帧总长度
  490. }
  491. // Modbus 功能码0x10的写寄存器命令
  492. // data: uint16_t 数组,每个元素是一个寄存器的数据(2字节)
  493. // 返回帧长度
  494. uint16_t build_modbus_write_cmd(uint8_t device_addr, uint8_t func_code,
  495. uint16_t reg_addr, uint16_t reg_count,
  496. uint16_t *data, uint8_t *out_buf)
  497. {
  498. uint8_t byte_count = reg_count * 2;
  499. uint16_t i = 0;
  500. out_buf[i++] = device_addr; // 设备地址
  501. out_buf[i++] = func_code; // 功能码(0x10)
  502. out_buf[i++] = (reg_addr >> 8) & 0xFF; // 起始寄存器地址高8位
  503. out_buf[i++] = reg_addr & 0xFF; // 起始寄存器地址低8位
  504. out_buf[i++] = (reg_count >> 8) & 0xFF; // 寄存器数量高8位
  505. out_buf[i++] = reg_count & 0xFF; // 寄存器数量低8位
  506. out_buf[i++] = byte_count; // 数据字节数
  507. // 写入数据(每个寄存器2字节)
  508. for (uint16_t j = 0; j < reg_count; j++) {
  509. out_buf[i++] = (data[j] >> 8) & 0xFF;
  510. out_buf[i++] = data[j] & 0xFF;
  511. }
  512. // 计算 CRC
  513. uint16_t crc = modbus_crc16(out_buf, i);
  514. out_buf[i++] = crc & 0xFF; // CRC低位
  515. out_buf[i++] = crc >> 8; // CRC高位
  516. return i; // 返回命令总长度
  517. }