From effd19429f8a467995bba66e9e19000a2e0ae46f Mon Sep 17 00:00:00 2001 From: helei Date: Wed, 12 Aug 2026 14:32:03 +0800 Subject: [PATCH] =?UTF-8?q?V1.5:=20=E6=96=B0=E5=A2=9E=20HLW8032=20?= =?UTF-8?q?=E7=94=B5=E8=83=BD=E8=AE=A1=E9=87=8F(UART5=20PD2=204800-8E1?= =?UTF-8?q?=EF=BC=8CPF=E8=84=89=E5=86=B2=E7=B4=AF=E8=AE=A1=E6=8D=A2?= =?UTF-8?q?=E7=AE=97kWh=EF=BC=8Cenergy=E5=AD=97=E6=AE=B5=E6=AF=8F=E5=88=86?= =?UTF-8?q?=E9=92=9F=E4=B8=8A=E6=8A=A5=EF=BC=8CEEPROM=20164=E6=8C=81?= =?UTF-8?q?=E4=B9=85=E5=8C=96+=E6=96=AD=E7=94=B5=E4=BF=9D=E5=AD=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- V1.5/STM32F103_App1/HardWare/ADC/adc.c | 2 + .../STM32F103_App1/HardWare/HLW8032/hlw8032.c | 169 ++++++++++++++++++ .../STM32F103_App1/HardWare/HLW8032/hlw8032.h | 19 ++ .../STM32F103_App1/HardWare/NETWORK/network.c | 17 ++ .../STM32F103_App1/HardWare/NETWORK/network.h | 1 + .../HardWare/SYSINIT/app_loop.c | 9 + V1.5/STM32F103_App1/HardWare/UART/uart.c | 36 ++++ V1.5/STM32F103_App1/HardWare/UART/uart.h | 3 + V1.5/STM32F103_App1/Inc/main.h | 9 + .../MDK-ARM/STM32F103rb_App1.uvprojx | 7 +- V1.5/STM32F103_App1/README.md | 17 +- V1.5/STM32F103_App1/Src/stm32f1xx_hal_msp.c | 18 ++ V1.5/STM32F103_App1/Src/stm32f1xx_it.c | 9 + V1.5/鐗堟湰璇存槑.md | 11 ++ 14 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.c create mode 100644 V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.h diff --git a/V1.5/STM32F103_App1/HardWare/ADC/adc.c b/V1.5/STM32F103_App1/HardWare/ADC/adc.c index 684e47d..7c9c772 100644 --- a/V1.5/STM32F103_App1/HardWare/ADC/adc.c +++ b/V1.5/STM32F103_App1/HardWare/ADC/adc.c @@ -1,4 +1,5 @@ #include "adc.h" +#include "hlw8032.h" #include "main.h" #include "network.h" #include "led.h" @@ -66,6 +67,7 @@ void update_batter(void) /* 电量 <10% 基本等同外部 12V 断开(法拉电容续航约 30s), * 立即写断电记录(含当前运行时长),随后复位: * BootLoader 会检测主电源,12V 未恢复前不跳 APP,防止外设没上电时程序乱跑 */ + hlw8032_save(); /* 法拉电容续航内把累计电量写进 EEPROM */ reset_log_power_loss(); HAL_Delay(200); NVIC_SystemReset(); diff --git a/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.c b/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.c new file mode 100644 index 0000000..82c4e95 --- /dev/null +++ b/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.c @@ -0,0 +1,169 @@ +/* hlw8032.c - HLW8032 电量计量芯片驱动(UART5 只收,4800 8E1) + * + * 帧格式(24 字节,每 50ms 一帧,主动上报): + * [0] 状态寄存器 State REG 0x55=正常 / 0xAA=修调失效 / 0xFx=有寄存器溢出 + * [1] 检测寄存器 Check REG 固定 0x5A + * [2:5] 电压参数寄存器(本模块不用) + * [5:8] 电压寄存器(不用) + * [8:11] 电流参数寄存器(不用) + * [11:14]电流寄存器(不用) + * [14:17]功率参数寄存器 PowerPar 芯片出厂修调常数,算电量要用 + * [17:20]功率寄存器(不用) + * [20] 数据更新寄存器 bit7 = PF 溢出翻转标志 + * [21:23]PF 寄存器 16bit 脉冲计数,溢出清零同时 bit7 翻转 + * [23] 校验和 [2]~[22] 共 21 字节相加取低 8 位 + * + * 手册电量公式: + * 1 度电脉冲数 = (1/PowerPar) × (1/(电压系数×电流系数)) × 10^9 × 3600 + * 电量(kWh) = 总脉冲数 × PowerPar × 电压系数 × 电流系数 / (10^9 × 3600) + * 电压/电流系数在 main.h(HLW_U_COEF / HLW_I_COEF),由采样电阻和互感器变比决定。 + * + * 溢出处理:PF 寄存器只有 16 位,溢出时 bit7 翻转。本驱动记住 bit7 上次值, + * 每帧比对,翻转一次说明溢出一次(+65536)。50ms 一帧 vs 溢出最快也要数小时, + * 不可能在一帧间隔内翻两次,不会漏。 + */ + +#include "hlw8032.h" +#include "uart.h" +#include "24c02.h" +#include "log.h" +#include + +#define HLW_FRAME_LEN 24 +#define HLW_OVERFLOW_PULSES 65536u +#define HLW_EEP_ADDR 164 /* EEPROM 164~171: uint64 累计脉冲数(132~157 蓝牙缓存, 160 日志等级) */ + +static uint8_t s_frame[HLW_FRAME_LEN]; +static uint8_t s_idx = 0; /* 帧同步状态:0=等首字节 1=等 0x5A >=2=收集中 */ + +static uint64_t s_total_pulses = 0; /* 累计脉冲(含 EEPROM 恢复的历史值) */ +static uint64_t s_saved_pulses = 0; /* 上次已写入 EEPROM 的值 */ +static uint32_t s_power_par = 0; /* 功率参数寄存器(芯片常数,收到帧后才有) */ + +static uint32_t s_k = 0; /* 本次上电以来 bit7 翻转(PF 溢出)次数 */ +static uint8_t s_last_bit7 = 0; +static uint32_t s_last_chip = 0; /* 上一帧芯片侧总脉冲 k*65536+n */ +static uint8_t s_synced = 0; /* 收到过有效帧 */ +static uint32_t s_last_frame_tick = 0; + +/*==== 帧校验与电量累计(中断上下文执行,保持轻量)====*/ +static void hlw8032_parse(const uint8_t *f) +{ + uint8_t sum = 0; + for (uint8_t i = 2; i <= 22; i++) sum += f[i]; + if (sum != f[23]) return; /* 校验失败丢帧 */ + + uint32_t power_par = ((uint32_t)f[14] << 16) | ((uint32_t)f[15] << 8) | f[16]; + if (power_par == 0) return; /* 参数寄存器异常,帧不可用 */ + s_power_par = power_par; + + uint8_t bit7 = f[20] & 0x80; + uint16_t pf = ((uint16_t)f[21] << 8) | f[22]; + + if (!s_synced) { + /* 首帧只建立基准,不累计增量: + * 单片机重启而芯片一直在跑时,寄存器里攒的脉冲(几秒,约零点几 Wh)舍弃 */ + s_last_bit7 = bit7; + s_k = 0; + } else if (bit7 != s_last_bit7) { + s_k++; /* PF 溢出一次 */ + s_last_bit7 = bit7; + } + + uint32_t chip_total = s_k * HLW_OVERFLOW_PULSES + pf; + if (s_synced) { + /* 正常单调递增;变小说明芯片断电重启过(寄存器清零),从当前值重新累计 */ + uint32_t delta = (chip_total >= s_last_chip) ? (chip_total - s_last_chip) : chip_total; + s_total_pulses += delta; + } + s_last_chip = chip_total; + s_synced = 1; + s_last_frame_tick = HAL_GetTick(); +} + +/*==== UART5 中断逐字节喂入:首字节同步 + 0x5A 二次确认 + 收满 24 字节解析 ====*/ +void hlw8032_rx_byte(uint8_t b) +{ + if (s_idx == 0) { + /* 首字节候选:0x55 / 0xAA / 0xFx */ + if (b == 0x55 || b == 0xAA || (b & 0xF0) == 0xF0) { + s_frame[0] = b; + s_idx = 1; + } + return; + } + if (s_idx == 1) { + if (b == 0x5A) { + s_frame[1] = b; + s_idx = 2; + } else { + /* 第二字节不是 0x5A:伪同步,但它本身可能是真首字节 */ + s_idx = 0; + if (b == 0x55 || b == 0xAA || (b & 0xF0) == 0xF0) { + s_frame[0] = b; + s_idx = 1; + } + } + return; + } + s_frame[s_idx++] = b; + if (s_idx >= HLW_FRAME_LEN) { + s_idx = 0; + hlw8032_parse(s_frame); + } +} + +/*==== 初始化:EEPROM 恢复累计 + UART5 起收 ====*/ +void hlw8032_init(void) +{ + uint64_t v = 0; + eepromReadData(HLW_EEP_ADDR, &v, sizeof(v)); + if (v == 0xFFFFFFFFFFFFFFFFULL) v = 0; /* 空白 EEPROM(出厂 0xFF) */ + s_total_pulses = v; + s_saved_pulses = v; + + MX_UART5_UART_Init(); + UART5_StartRx(); + if (s_total_pulses) { + log_info("> 电能: HLW8032 就绪 (UART5 PD2), 历史脉冲 %lu%09lu", + (unsigned long)(s_total_pulses / 1000000000ULL), + (unsigned long)(s_total_pulses % 1000000000ULL)); + } else { + log_info("> 电能: HLW8032 就绪 (UART5 PD2)"); + } +} + +/*==== 累计电量 kWh ====*/ +float hlw8032_get_energy_kwh(void) +{ + if (!s_power_par) return 0.0f; + return (float)((double)s_total_pulses * (double)s_power_par * + (double)HLW_U_COEF * (double)HLW_I_COEF / 3.6e12); +} + +/*==== 在线判断:1s 内收到过有效帧 ====*/ +uint8_t hlw8032_online(void) +{ + return s_synced && (HAL_GetTick() - s_last_frame_tick) < 1000; +} + +/*==== 立即写 EEPROM(断电预警/计划复位前调用)====*/ +void hlw8032_save(void) +{ + if (s_total_pulses == s_saved_pulses) return; + uint64_t v = s_total_pulses; + if (eepromWriteData(HLW_EEP_ADDR, &v, sizeof(v)) == 0) { + s_saved_pulses = s_total_pulses; + } +} + +/*==== 1s 周期:每攒够约 0.1 kWh 写一次 EEPROM,限制擦写频率 ====*/ +void hlw8032_tick(void) +{ + if (!s_power_par) return; + double per_01kwh = 3.6e11 / ((double)s_power_par * HLW_U_COEF * HLW_I_COEF); + if (per_01kwh < 1.0) per_01kwh = 1.0; + if (s_total_pulses - s_saved_pulses >= (uint64_t)per_01kwh) { + hlw8032_save(); + } +} diff --git a/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.h b/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.h new file mode 100644 index 0000000..ed52dd8 --- /dev/null +++ b/V1.5/STM32F103_App1/HardWare/HLW8032/hlw8032.h @@ -0,0 +1,19 @@ +#ifndef __HLW8032_H +#define __HLW8032_H + +#include "main.h" + +/* HLW8032 电量计量模块 + * 接线:芯片 TXD -> 单片机 PD2 (UART5_RX),光耦隔离;芯片 RX 预留不用。 + * 通信:4800bps 8E1,芯片每 50ms 主动上报一帧 24 字节,只收不发。 + * 本模块只取 PF 脉冲计数换算累计电量(kWh),电压/电流/功率寄存器忽略。 + * 累计脉冲数持久化在 EEPROM(164~171, uint64),定期 + 断电前保存。 */ + +void hlw8032_init(void); /* UART5 初始化 + EEPROM 恢复累计(app_init 调用) */ +void hlw8032_rx_byte(uint8_t b); /* UART5 中断逐字节喂入(uart.c 接收回调调用) */ +void hlw8032_tick(void); /* 1s 周期:到阈值就把累计脉冲写 EEPROM */ +void hlw8032_save(void); /* 立即写 EEPROM(断电预警/计划复位前调用) */ +float hlw8032_get_energy_kwh(void); /* 累计电量 kWh(未收到帧前为 0) */ +uint8_t hlw8032_online(void); /* 最近 1s 内收到过有效帧 */ + +#endif /* __HLW8032_H */ diff --git a/V1.5/STM32F103_App1/HardWare/NETWORK/network.c b/V1.5/STM32F103_App1/HardWare/NETWORK/network.c index 08b9802..b484883 100644 --- a/V1.5/STM32F103_App1/HardWare/NETWORK/network.c +++ b/V1.5/STM32F103_App1/HardWare/NETWORK/network.c @@ -317,6 +317,23 @@ void NET_publish_power(int on) net_at_unlock(); } +/* 上报累计电量: energy 字段,单位 kWh,两位小数 */ +void NET_publish_energy(float kwh) +{ + if (g_net_tx_busy) { log_info("> NET: energy 上报被丢弃 (发送忙)"); return; } + if (net_at_trylock() != 0) { log_info("> NET: energy 上报被丢弃 (AT 忙)"); return; } + if (s_backend == NET_BACKEND_4G) { + CAT1_printf("AT+MPUB=\"/iot/data/up/%s\",0,0,\"{\22header\22:\22iot.prop.post\22,\22body\22:{\22energy\22:%.2f}}\"", + MqttInfoStr.ClientID, kwh); + } else { + char json[96]; + snprintf(json, sizeof(json), + "{\"header\":\"iot.prop.post\",\"body\":{\"energy\":%.2f}}", kwh); + net_wifi_publish_up(json); + } + net_at_unlock(); +} + void NET_mqtt_report(const char *header, const char *ota_id, int val) { if (g_net_tx_busy) { log_info("> NET: 进度/结果上报被丢弃 (发送忙)"); return; } diff --git a/V1.5/STM32F103_App1/HardWare/NETWORK/network.h b/V1.5/STM32F103_App1/HardWare/NETWORK/network.h index 41f2570..57fb31f 100644 --- a/V1.5/STM32F103_App1/HardWare/NETWORK/network.h +++ b/V1.5/STM32F103_App1/HardWare/NETWORK/network.h @@ -38,6 +38,7 @@ void NET_publish_status(int sw1, int feeding, int sw2, int sw3, int sw4, float weight_kg, float once_wt_kg, float zero_kg); void NET_publish_response(const char *cmd_id, int ok, const char *msg); void NET_publish_power(int on); +void NET_publish_energy(float kwh); /* 上报累计电量,标识符 energy,单位 kWh */ void NET_mqtt_report(const char *header, const char *ota_id, int val); void NET_ota_confirm(void); diff --git a/V1.5/STM32F103_App1/HardWare/SYSINIT/app_loop.c b/V1.5/STM32F103_App1/HardWare/SYSINIT/app_loop.c index e6a55db..6e9b838 100644 --- a/V1.5/STM32F103_App1/HardWare/SYSINIT/app_loop.c +++ b/V1.5/STM32F103_App1/HardWare/SYSINIT/app_loop.c @@ -26,6 +26,7 @@ #include "uart.h" #include "log_cn.h" #include "ble_at.h" +#include "hlw8032.h" #include "reset_log.h" #include "../W25Q64/w25q64.h" @@ -91,6 +92,9 @@ void app_init(void) adcInit(); update_batter(); + /* HLW8032 电能计量(UART5 PD2,只累计电量) */ + hlw8032_init(); + /* 网络模块初始化:按 EEPROM 记忆的上次成功方式优先(4G 或 WiFi) */ NET_init(); @@ -210,6 +214,7 @@ static void sys_task(void *arg) if (HAL_GetTick() - batt_tick >= 1000) { batt_tick = HAL_GetTick(); update_batter(); + hlw8032_tick(); /* 攒够约 0.1kWh 写一次 EEPROM */ reset_log_tick((uint32_t)(up_ms / 1000)); /* 共享 RAM 更新运行秒数,热复位不丢 */ } @@ -223,6 +228,10 @@ static void sys_task(void *arg) if (now - up_print >= 60000) { up_print = now; if (g_net_mqtt_ready) { + /* 每分钟随心跳上报一次累计电量(标识符 energy) */ + if (hlw8032_online()) { + NET_publish_energy(hlw8032_get_energy_kwh()); + } uint32_t mins = (uint32_t)(up_ms / 60000); log_info(FMT_UPTIME, (unsigned)(mins / 1440), diff --git a/V1.5/STM32F103_App1/HardWare/UART/uart.c b/V1.5/STM32F103_App1/HardWare/UART/uart.c index e84492b..714ca31 100644 --- a/V1.5/STM32F103_App1/HardWare/UART/uart.c +++ b/V1.5/STM32F103_App1/HardWare/UART/uart.c @@ -1,5 +1,6 @@ #include "uart.h" #include "network.h" +#include "hlw8032.h" #include #include @@ -7,6 +8,7 @@ UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; UART_HandleTypeDef huart3; UART_HandleTypeDef huart4; +UART_HandleTypeDef huart5; uint16_t Rx_Len = 0; uint8_t Rx_Buf[Rx_Max] = {0}; @@ -27,6 +29,7 @@ static uint8_t uart1_cmd_index = 0; static uint32_t uart1_last_rx_tick = 0; static uint8_t uart2_rx_byte = 0; +static uint8_t uart5_rx_byte = 0; static uint8_t uart2_cmd_buf[UART2_RX_BUF_SIZE] = {0}; static uint8_t uart2_cmd_index = 0; static uint32_t uart2_last_rx_tick = 0; @@ -89,6 +92,26 @@ void MX_UART4_UART_Init(void) if (HAL_UART_Init(&huart4) != HAL_OK) Error_Handler(); } +/* UART5: HLW8032 计量芯片 (PD2=RX <- 芯片 TXD),4800 8E1。 + * 芯片只发不收,TX(PC12) 不配置;8 数据位+偶校验在 F1 上要按 9 位帧长配置 */ +void MX_UART5_UART_Init(void) +{ + huart5.Instance = UART5; + huart5.Init.BaudRate = 4800; + huart5.Init.WordLength = UART_WORDLENGTH_9B; + huart5.Init.StopBits = UART_STOPBITS_1; + huart5.Init.Parity = UART_PARITY_EVEN; + huart5.Init.Mode = UART_MODE_RX; + huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart5.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart5) != HAL_OK) Error_Handler(); +} + +void UART5_StartRx(void) +{ + HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1); +} + void USART3_StartRx(void) { /* 避免重复启动 DMA: 若已在接收则先停止再启动 */ @@ -178,6 +201,15 @@ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) huart->ErrorCode = HAL_UART_ERROR_NONE; HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1); /* RS485 秤口同样自愈 */ } + else if (huart->Instance == UART5) { + __HAL_UART_CLEAR_OREFLAG(huart); + __HAL_UART_CLEAR_PEFLAG(huart); + __HAL_UART_CLEAR_FEFLAG(huart); + __HAL_UART_CLEAR_NEFLAG(huart); + __HAL_UART_CLEAR_IDLEFLAG(huart); + huart->ErrorCode = HAL_UART_ERROR_NONE; + HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1); /* HLW8032 口同样自愈 */ + } else if (huart->Instance == USART3) { __HAL_UART_CLEAR_OREFLAG(huart); __HAL_UART_CLEAR_PEFLAG(huart); @@ -271,6 +303,10 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) } HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1); } + else if (huart->Instance == UART5) { + hlw8032_rx_byte(uart5_rx_byte); + HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1); + } else if (huart->Instance == UART4) { /* DMA(NORMAL) 填满 Rx_Buf:连续数据流没有空闲间隙、IDLE 不触发, * 若不在这里搬运并重启,接收将永久停摆(WiFi OTA 大流量下载必现) */ diff --git a/V1.5/STM32F103_App1/HardWare/UART/uart.h b/V1.5/STM32F103_App1/HardWare/UART/uart.h index 0f4926f..1ac9753 100644 --- a/V1.5/STM32F103_App1/HardWare/UART/uart.h +++ b/V1.5/STM32F103_App1/HardWare/UART/uart.h @@ -10,6 +10,7 @@ extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; /* RS485 喂料秤 */ extern UART_HandleTypeDef huart3; /* 4G Air780E */ extern UART_HandleTypeDef huart4; /* WiFi ESP-01S (PC10=TX, PC11=RX) */ +extern UART_HandleTypeDef huart5; /* HLW8032 计量芯片 (PD2=RX, 只收) */ extern volatile uint8_t uart1_rx_ready; extern uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE]; @@ -23,6 +24,7 @@ void MX_USART1_UART_Init(void); void MX_USART2_UART_Init(void); void MX_USART3_UART_Init(void); void MX_UART4_UART_Init(void); +void MX_UART5_UART_Init(void); void USART3_StartRx(void); /* 启动 USART3 DMA+IDLE 接收 */ void USART3_StopRx(void); /* 停止 USART3 DMA 接收(切 WiFi 通道时调用,释放共享 Rx_Buf) */ void USART3_SetBaudRate(uint32_t baud); /* 运行中切换 USART3 波特率 */ @@ -31,6 +33,7 @@ void UART4_StopRx(void); /* 停止 UART4 DMA void UART4_SetBaudRate(uint32_t baud); /* 运行中切换 UART4 波特率 */ void USART1_StartRx(void); /* 启动 USART1 中断接收 */ void USART2_StartRx(void); /* 启动 USART2 中断接收 */ +void UART5_StartRx(void); /* 启动 UART5 中断接收(HLW8032) */ void USART2_Tick(void); /* 触发 USART2 帧超时自动提交 */ uint16_t USART2_GetFrame(uint8_t *out, uint16_t out_size); /* 从 USART2 取一帧原始字节 */ int USART1_CheckCommand(const char *cmd); /* 检查是否收到指定命令(不区分大小写) */ diff --git a/V1.5/STM32F103_App1/Inc/main.h b/V1.5/STM32F103_App1/Inc/main.h index 43a9ad6..ee29904 100644 --- a/V1.5/STM32F103_App1/Inc/main.h +++ b/V1.5/STM32F103_App1/Inc/main.h @@ -61,6 +61,15 @@ extern UART_HandleTypeDef huart3; * 多台设备现场用名字区分;手机列表大约只显示前 10 位 */ #define BLE_NAME "Bt1" +/*===== HLW8032 电量计量系数(UART5 PD2 接收,只上报累计电量) ===== + * 电压通道: ZMPT107-1(2mA:2mA),初级 220V 串 100K,次级并 50R + * -> 电压系数 = (100K/50)/1000 = 2.0 + * 电流通道: CT 100A/100mA(1000:1),输出并 2R -> 等效采样电阻 0.002R + * -> 电流系数 = 1/(0.002*1000) = 0.5 + * 改电阻/互感器只需改这两个宏(公式见 HLW8032 手册电量计算一节) */ +#define HLW_U_COEF 2.0f +#define HLW_I_COEF 0.5f + /*===== 蓝牙 GATT UUID 配置(透传服务)===== * BLE_UUID_CUSTOM = 1:上电把三个 UUID 设为下面的值(重启模块生效)。 * = 0:保持模块出厂 UUID(fff0/fff1/fff2),仅海凌科自家 APP 可用 diff --git a/V1.5/STM32F103_App1/MDK-ARM/STM32F103rb_App1.uvprojx b/V1.5/STM32F103_App1/MDK-ARM/STM32F103rb_App1.uvprojx index 7b38050..0132ec9 100644 --- a/V1.5/STM32F103_App1/MDK-ARM/STM32F103rb_App1.uvprojx +++ b/V1.5/STM32F103_App1/MDK-ARM/STM32F103rb_App1.uvprojx @@ -369,7 +369,7 @@ --no_multibyte_chars USE_HAL_DRIVER,STM32F103xE - ../Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;..\m_app;..\HardWare\CAR;..\HardWare\RELAY;..\HardWare\LOG;..\HardWare\IIC;..\HardWare\24C02;..\HardWare\ADC;..\HardWare\LED;..\HardWare\SYSINIT;..\HardWare\UART;..\HardWare\W25Q64;..\HardWare\NETWORK;..\HardWare\WIFI;..\HardWare\MQTT;..\HardWare\FEED_SCALE;..\HardWare\USER_CMD;..\Middlewares\FreeRTOS\Source\include;..\Middlewares\FreeRTOS\Source\portable\RVDS\ARM_CM3 + ../Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;..\m_app;..\HardWare\CAR;..\HardWare\RELAY;..\HardWare\LOG;..\HardWare\IIC;..\HardWare\24C02;..\HardWare\ADC;..\HardWare\LED;..\HardWare\SYSINIT;..\HardWare\UART;..\HardWare\W25Q64;..\HardWare\NETWORK;..\HardWare\WIFI;..\HardWare\MQTT;..\HardWare\FEED_SCALE;..\HardWare\USER_CMD;..\HardWare\HLW8032;..\Middlewares\FreeRTOS\Source\include;..\Middlewares\FreeRTOS\Source\portable\RVDS\ARM_CM3 @@ -687,6 +687,11 @@ 1 ..\HardWare\W25Q64\w25q64.c + + hlw8032.c + 1 + ..\HardWare\HLW8032\hlw8032.c + diff --git a/V1.5/STM32F103_App1/README.md b/V1.5/STM32F103_App1/README.md index f536986..1f2a8b6 100644 --- a/V1.5/STM32F103_App1/README.md +++ b/V1.5/STM32F103_App1/README.md @@ -56,6 +56,7 @@ | USART2 | RS485 鍠傛枡绉 | PA2/PA3 | 9600-8N1 | | USART3 | 4G Air780E/EG MQTT+GNSS | PB10/PB11 | 921600-8N1锛堣涓嬫枃娉㈢壒鐜囪嚜閫傚簲锛 | | UART4 | WiFi ESP-01S | PC10/PC11 | 115200鈫921600-8N1锛堣涓嬫枃 WiFi 娉㈢壒鐜囧悓姝ワ級 | +| UART5 | HLW8032 鐢佃兘璁¢噺 | PD2(RX) | 4800-8E1锛屽彧鏀讹紝鑺墖姣 50ms 涓诲姩涓婃姤 | | ESP_RST | WiFi 妯″潡澶嶄綅 | PA5 | 浣庣數骞 500ms 澶嶄綅 | | Relay1 | 鎶曞杺鐢垫満鎺у埗 | PB7 | 楂樼數骞冲惛鍚 | | Relay2~4 | 澶囩敤鎺у埗 | PB8/PC0/PC2 | 楂樼數骞冲惛鍚 | @@ -100,6 +101,17 @@ - 鏂數璁板綍鍙涓嬫鎴愬姛鍚姩娑堣垂涓娆★紙`boot_seen` 浣嶇炕杞爣璁帮級锛屼竴娆℃帀鐢 = 涓鏉¤褰曪紝BL 绛夊緟鏈熼棿涓嶄骇鐢熻褰 - BL 鎵句笉鍒版湁鏁 APP锛堝鍙埛浜 BL锛夛細鎵撳嵃鎻愮ず骞舵瘡 3s 涓诲姩澶嶄綅閲嶈瘯锛屽埛鍏 APP 鍗虫仮澶 +## 鐢佃兘璁¢噺锛圚LW8032锛 + +鍙閲**绱娑堣楃數閲**锛屼笂鎶ュ钩鍙版爣璇嗙 `energy`锛堝崟浣 kWh锛屼袱浣嶅皬鏁帮級銆 + +- **纭欢**锛欻LW8032锛5V 渚涚數锛夌粡 B0505S 闅旂鐢垫簮 + 鍏夎﹂殧绂伙紝鑺墖 TXD 鎺 PD2锛圲ART5_RX锛夛紱鐢靛帇閲囨牱 ZMPT107-1锛2mA:2mA锛屽垵绾 220V 涓 100K锛屾绾у苟 50惟锛夛紝鐢垫祦閲囨牱 CT 100A/100mA锛1000:1锛岃緭鍑哄苟 2惟锛夛紝涓変釜妯℃嫙鑴氬悇瀵瑰湴 33nF +- **閫氫俊**锛4800bps 8E1锛團1 涓婃寜 9 浣嶅抚闀 + 鍋舵牎楠岄厤缃級锛岃姱鐗囨瘡 50ms 涓诲姩涓婃姤 24 瀛楄妭甯э紝鍙敹涓嶅彂锛涘抚鍚屾 = 棣栧瓧鑺 0x55/0xAA/0xFx + 绗簩瀛楄妭 0x5A + 鏍¢獙鍜岋紙[2]~[22] 鐩稿姞浣 8 浣嶏級 +- **鐢甸噺绠楁硶**锛堟墜鍐屽叕寮忥級锛歚kWh = 鎬昏剦鍐 脳 鍔熺巼鍙傛暟瀵勫瓨鍣 脳 鐢靛帇绯绘暟 脳 鐢垫祦绯绘暟 / (10^9脳3600)`锛汸F 瀵勫瓨鍣 16 浣嶆孩鍑虹敱鏁版嵁鏇存柊瀵勫瓨鍣 bit7 缈昏浆璁℃暟锛坄鎬昏剦鍐 = k脳65536 + PF`锛夛紝50ms 涓甯т笉鍙兘婕忕炕杞紱鑺墖鏂數閲嶅惎锛堣鏁板煎掗锛夎嚜鍔ㄩ噸鏂板熀鍑 +- **绯绘暟瀹**锛歚main.h` 鐨 `HLW_U_COEF`锛=100K/50/1000=2.0锛夈乣HLW_I_COEF`锛=1/(0.002脳1000)=0.5锛夆斺旀敼鐢甸樆/浜掓劅鍣ㄥ彧鍔ㄨ繖涓や釜瀹 +- **鎸佷箙鍖**锛氱疮璁¤剦鍐叉暟锛坲int64锛夊瓨 EEPROM 鍋忕Щ 164~171锛涙瘡鏀掔害 0.1kWh 鍐欎竴娆★紙闄愬埗鎿﹀啓锛夛紝鏂數棰勮锛堟硶鎷夌數瀹圭画鑸唴锛夌珛鍗冲啓涓娆★紝鎺夌數鎹熷け <0.1kWh +- **涓婃姤**锛歁QTT 灏辩华涓旇姱鐗囧湪绾匡紙1s 鍐呮湁鏈夋晥甯э級鏃讹紝姣忓垎閽熼殢杩愯蹇冭烦涓婃姤涓娆 `{"energy":%.2f}`锛涙湭鑱旂綉/鑺墖涓嶅湪绾夸笉涓婃姤 + ## 鍙岄氶亾缃戠粶锛4G 浼樺厛锛學iFi 鍏滃簳锛 缃戠粶灞 `HardWare/NETWORK/network.c` 瀵逛笟鍔″眰灞忚斀搴曞眰妯$粍宸紓锛屼笟鍔″彧璋 `NET_*` 鎺ュ彛锛4G 鍚庣锛坄CAR/air780e.c`锛屾ā缁勫唴缃 MQTT锛変笌 WiFi 鍚庣锛坄NETWORK/net_wifi.c`锛孴CP 閫忎紶 + 杞欢 MQTT锛夊悓鏋勶紝杩愯鏃朵簰鏂ュ垏鎹€ @@ -289,6 +301,7 @@ W25Q64 澶栭儴 Flash锛8MB锛夛細 | 130 | 1B | 涓婃鎴愬姛鑱旂綉鏂瑰紡锛0=4G锛1=WiFi鍥哄畾鐑偣锛2=WiFi閰嶇綉鐑偣锛堜粎鍙樺寲鏃跺啓锛 | | 132~157 | 26B | 钃濈墮鍚嶇О閰嶇疆缂撳瓨锛堝懡涓垯寮鏈鸿烦杩囪摑鐗 AT 璁剧疆娴佺▼锛 | | 160 | 1B | 鏃ュ織绛夌骇锛0~5锛歍RACE/DEBUG/INFO/WARN/ERROR/FATAL锛 | +| 164~171 | 8B | HLW8032 绱鑴夊啿鏁帮紙uint64锛屾瘡鏀 0.1kWh + 鏂數鍓嶅啓鍏ワ級 | | 250 | 1B | 鎺㈡祴瀛楄妭锛堜笂鐢靛啓 0xA5 鍥炶锛岄獙璇 I2C 閫氫俊锛 | > 娉ㄦ剰锛氭敼 `MqttInfo_Str` 缁撴瀯浣撲細鏀瑰彉涓婅堪鍋忕Щ锛岀Г鍙傛暟锛120+锛夊拰鑱旂綉鏂瑰紡锛130锛夊湪 @@ -305,6 +318,7 @@ W25Q64 澶栭儴 Flash锛8MB锛夛細 | `sw1` / `feeding` | 绗竴璺户鐢靛櫒鐘舵 | 1=鎶曞杺涓紝0=鍋滄锛涙棤绉ゆā寮忎笅涓ゅ瓧娈**鍚屾椂涓婃姤**锛屽钩鍙颁袱涓紑鍏冲悓姝ュ埛鏂 | | `sw2~sw4` | 澶囩敤缁х數鍣ㄧ姸鎬 | 0/1 | | `pow` | 鐢甸噺鐘舵 | 1=姝e父锛0=浣庣數閲 | +| `energy` | 绱娑堣楃數閲 | HLW8032 璁¢噺锛屽崟浣 kWh锛屼袱浣嶅皬鏁帮紝鑱旂綉鍚庢瘡鍒嗛挓涓婃姤 | | `GPS` | 瀹氫綅鍧愭爣 | 浠 4G 閫氶亾(Air780EG)锛孏CJ-02 楂樺痉鍧愭爣绯伙紝鏍煎紡 `"缁忓害,绾害"`锛屾瘡 5 鍒嗛挓涓婃姤 | > 娉細`zero`锛堝墿浣欐枡閲嶏級涓 `onceWt` 涓虹О閲嶆ā寮忎笓鐢ㄥ瓧娈碘斺擿PRODUCT_WITH_FEED_SCALE=0` 鏃剁姸鎬佷笂鎶ヤ笉鎼哄甫杩欎袱涓瓧娈碉紝骞冲彴涓嬪彂璁剧疆浼氭敹鍒 `no scale on this device` 鎷掔粷搴旂瓟銆 @@ -391,7 +405,8 @@ STM32F103_App1/ 鈹 鈹溾攢鈹 NETWORK/ # 缃戠粶灞傦細network.c 閫氶亾鍒囨崲/缁熶竴鍒嗗彂 + net_wifi.c WiFi 鍚庣 + net_wifi_ota.c WiFi OTA 鈹 鈹溾攢鈹 WIFI/ # esp8266.c ESP-01S AT椹卞姩/閫忎紶/SmartConfig + mqtt_client.c 杞欢MQTT 鈹 鈹溾攢鈹 CAR/ # Air780E/EG AT 椹卞姩銆佹尝鐗圭巼鑷傚簲銆丆SQ 淇″彿妫娴嬨丟NSS 瀹氫綅銆丱TA 涓嬭浇 -鈹 鈹溾攢鈹 UART/ # USART1/2/3+UART4 鍒濆鍖栥佽繍琛屼腑鍒囨尝鐗圭巼銆佷腑鏂/DMA 鎺ユ敹銆丱RE 鑷剤 +鈹 鈹溾攢鈹 UART/ # USART1/2/3+UART4/5 鍒濆鍖栥佽繍琛屼腑鍒囨尝鐗圭巼銆佷腑鏂/DMA 鎺ユ敹銆丱RE 鑷剤 +鈹 鈹溾攢鈹 HLW8032/ # 鐢佃兘璁¢噺锛圲ART5 甯цВ鏋愩丳F 鑴夊啿绱銆乲Wh 鎹㈢畻銆丒EPROM 鎸佷箙鍖栵級 鈹 鈹溾攢鈹 24C02/ # EEPROM 璇诲啓锛堥〉鍐欏叆锛屽甫璺ㄤ换鍔′簰鏂ラ攣锛 鈹 鈹溾攢鈹 IIC/ # 杞欢 I2C锛堝甫鎬荤嚎鎭㈠锛歋DA 琚媺姝绘椂琛 9 鏃堕挓閲婃斁锛 鈹 鈹溾攢鈹 ADC/ # 鐢垫睜鐢靛帇妫娴嬶紙0~100% 闄愬箙銆佹帀鐢靛幓鎶栧垽瀹氾級 diff --git a/V1.5/STM32F103_App1/Src/stm32f1xx_hal_msp.c b/V1.5/STM32F103_App1/Src/stm32f1xx_hal_msp.c index 5bf112f..c8d31da 100644 --- a/V1.5/STM32F103_App1/Src/stm32f1xx_hal_msp.c +++ b/V1.5/STM32F103_App1/Src/stm32f1xx_hal_msp.c @@ -246,6 +246,24 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart) /* USER CODE END UART4_MspInit 1 */ } + else if(huart->Instance==UART5) + { + /* Peripheral clock enable */ + __HAL_RCC_UART5_CLK_ENABLE(); + + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**UART5 GPIO Configuration + PD2 ------> UART5_RX (接 HLW8032 TXD,光耦隔离;PC12=TX 芯片不用不配置) + */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* UART5 interrupt Init */ + HAL_NVIC_SetPriority(UART5_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(UART5_IRQn); + } } diff --git a/V1.5/STM32F103_App1/Src/stm32f1xx_it.c b/V1.5/STM32F103_App1/Src/stm32f1xx_it.c index fec3286..4b678cb 100644 --- a/V1.5/STM32F103_App1/Src/stm32f1xx_it.c +++ b/V1.5/STM32F103_App1/Src/stm32f1xx_it.c @@ -63,6 +63,7 @@ extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef huart4; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart1; +extern UART_HandleTypeDef huart5; /* USER CODE BEGIN EV */ #include "network.h" /* USER CODE END EV */ @@ -325,6 +326,14 @@ void USART3_IRQHandler(void) /* USER CODE END USART3_IRQn 1 */ } +/** + * @brief This function handles UART5 global interrupt (HLW8032). + */ +void UART5_IRQHandler(void) +{ + HAL_UART_IRQHandler(&huart5); +} + /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ diff --git a/V1.5/鐗堟湰璇存槑.md b/V1.5/鐗堟湰璇存槑.md index cb3d384..0a03e84 100644 --- a/V1.5/鐗堟湰璇存槑.md +++ b/V1.5/鐗堟湰璇存槑.md @@ -93,3 +93,14 @@ - 钃濈墮鏀瑰悕琚挒鍐欙細APP 鏁版嵁鎾炶繘 AT 绐楀彛鎶婂悕瀛楀啓鎴 "info" 鈫 鏀"鍏堟煡璇㈠悗璁剧疆"骞傜瓑娴佺▼锛堝悕瀛楀凡瀵瑰氨涓嶅紑 AT 绐楀彛锛 - 璁剧疆鍚庡綋鍦哄洖鏌ュけ璐ワ細妯″潡璁剧疆閲嶅惎鎵嶇敓鏁堬紝鏀逛负涓嬫寮鏈烘煡璇㈡牎楠 - OTA 缁撴灉/纭涓婃姤瓒呮椂锛歯et 浠诲姟涓庝笟鍔′换鍔$珵浜夊叡浜帴鏀剁紦鍐 鈫 NET_process 娑堣垂鍔犻攣銆佸彂甯冩敼 2s 瓒呮椂閿 + +### 杩藉姞锛欻LW8032 鐢佃兘璁¢噺锛2026-08锛 + +- 鏂板 `HardWare/HLW8032/`锛歎ART5(PD2 鍙敹) 4800-8E1 鎺ユ敹鑺墖姣 50ms 涓诲姩涓婃姤鐨 24 瀛楄妭甯э紝 + 甯у悓姝(0x55/0xAA/0xFx + 0x5A)+鏍¢獙鍜岄獙璇侊紱鍙彇 PF 鑴夊啿绱鎹㈢畻绱鐢甸噺 +- 鐢甸噺鎸夋墜鍐屽叕寮忔崲绠楋細kWh = 鎬昏剦鍐裁楀姛鐜囧弬鏁懊楃數鍘嬬郴鏁懊楃數娴佺郴鏁/(10^9脳3600)锛 + PF 16 浣嶆孩鍑洪潬鏁版嵁鏇存柊瀵勫瓨鍣 bit7 缈昏浆璁℃暟锛50ms 涓甯т笉浼氭紡锛夛紱鑺墖鏂數閲嶅惎鑷姩閲嶆柊鍩哄噯 +- 绯绘暟瀹 `HLW_U_COEF`(2.0)/`HLW_I_COEF`(0.5) 鍦 main.h锛屽搴 ZMPT107-1(100K/50R)+CT 1000:1(2R) +- 绱鑴夊啿(uint64)鎸佷箙鍖 EEPROM 鍋忕Щ 164锛氭瘡鏀掔害 0.1kWh 鍐欎竴娆 + 鏂數棰勮鏃剁珛鍗冲啓锛堟硶鎷夌數瀹圭画鑸唴锛 +- 骞冲彴涓婃姤鏍囪瘑绗 `energy`锛坘Wh 涓や綅灏忔暟锛夛紝MQTT 灏辩华涓旇姱鐗囧湪绾挎椂姣忓垎閽熶竴娆★紝4G/WiFi 鍙岄氶亾 +- UART5 甯 ORE 鑷剤锛涚‖浠讹細B0505S 闅旂鐢垫簮 + 鍏夎︼紝鑺墖 TXD 鎺 PD2