V1.5: 新增 HLW8032 电能计量(UART5 PD2 4800-8E1,PF脉冲累计换算kWh,energy字段每分钟上报,EEPROM 164持久化+断电保存)
This commit is contained in:
parent
2ecf32fde9
commit
effd19429f
|
|
@ -1,4 +1,5 @@
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
|
#include "hlw8032.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
|
@ -66,6 +67,7 @@ void update_batter(void)
|
||||||
/* 电量 <10% 基本等同外部 12V 断开(法拉电容续航约 30s),
|
/* 电量 <10% 基本等同外部 12V 断开(法拉电容续航约 30s),
|
||||||
* 立即写断电记录(含当前运行时长),随后复位:
|
* 立即写断电记录(含当前运行时长),随后复位:
|
||||||
* BootLoader 会检测主电源,12V 未恢复前不跳 APP,防止外设没上电时程序乱跑 */
|
* BootLoader 会检测主电源,12V 未恢复前不跳 APP,防止外设没上电时程序乱跑 */
|
||||||
|
hlw8032_save(); /* 法拉电容续航内把累计电量写进 EEPROM */
|
||||||
reset_log_power_loss();
|
reset_log_power_loss();
|
||||||
HAL_Delay(200);
|
HAL_Delay(200);
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
|
|
|
||||||
|
|
@ -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 <string.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -317,6 +317,23 @@ void NET_publish_power(int on)
|
||||||
net_at_unlock();
|
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)
|
void NET_mqtt_report(const char *header, const char *ota_id, int val)
|
||||||
{
|
{
|
||||||
if (g_net_tx_busy) { log_info("> NET: 进度/结果上报被丢弃 (发送忙)"); return; }
|
if (g_net_tx_busy) { log_info("> NET: 进度/结果上报被丢弃 (发送忙)"); return; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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_response(const char *cmd_id, int ok, const char *msg);
|
||||||
void NET_publish_power(int on);
|
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_mqtt_report(const char *header, const char *ota_id, int val);
|
||||||
void NET_ota_confirm(void);
|
void NET_ota_confirm(void);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "log_cn.h"
|
#include "log_cn.h"
|
||||||
#include "ble_at.h"
|
#include "ble_at.h"
|
||||||
|
#include "hlw8032.h"
|
||||||
#include "reset_log.h"
|
#include "reset_log.h"
|
||||||
#include "../W25Q64/w25q64.h"
|
#include "../W25Q64/w25q64.h"
|
||||||
|
|
||||||
|
|
@ -91,6 +92,9 @@ void app_init(void)
|
||||||
adcInit();
|
adcInit();
|
||||||
update_batter();
|
update_batter();
|
||||||
|
|
||||||
|
/* HLW8032 电能计量(UART5 PD2,只累计电量) */
|
||||||
|
hlw8032_init();
|
||||||
|
|
||||||
/* 网络模块初始化:按 EEPROM 记忆的上次成功方式优先(4G 或 WiFi) */
|
/* 网络模块初始化:按 EEPROM 记忆的上次成功方式优先(4G 或 WiFi) */
|
||||||
NET_init();
|
NET_init();
|
||||||
|
|
||||||
|
|
@ -210,6 +214,7 @@ static void sys_task(void *arg)
|
||||||
if (HAL_GetTick() - batt_tick >= 1000) {
|
if (HAL_GetTick() - batt_tick >= 1000) {
|
||||||
batt_tick = HAL_GetTick();
|
batt_tick = HAL_GetTick();
|
||||||
update_batter();
|
update_batter();
|
||||||
|
hlw8032_tick(); /* 攒够约 0.1kWh 写一次 EEPROM */
|
||||||
reset_log_tick((uint32_t)(up_ms / 1000)); /* 共享 RAM 更新运行秒数,热复位不丢 */
|
reset_log_tick((uint32_t)(up_ms / 1000)); /* 共享 RAM 更新运行秒数,热复位不丢 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,6 +228,10 @@ static void sys_task(void *arg)
|
||||||
if (now - up_print >= 60000) {
|
if (now - up_print >= 60000) {
|
||||||
up_print = now;
|
up_print = now;
|
||||||
if (g_net_mqtt_ready) {
|
if (g_net_mqtt_ready) {
|
||||||
|
/* 每分钟随心跳上报一次累计电量(标识符 energy) */
|
||||||
|
if (hlw8032_online()) {
|
||||||
|
NET_publish_energy(hlw8032_get_energy_kwh());
|
||||||
|
}
|
||||||
uint32_t mins = (uint32_t)(up_ms / 60000);
|
uint32_t mins = (uint32_t)(up_ms / 60000);
|
||||||
log_info(FMT_UPTIME,
|
log_info(FMT_UPTIME,
|
||||||
(unsigned)(mins / 1440),
|
(unsigned)(mins / 1440),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "hlw8032.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
@ -7,6 +8,7 @@ UART_HandleTypeDef huart1;
|
||||||
UART_HandleTypeDef huart2;
|
UART_HandleTypeDef huart2;
|
||||||
UART_HandleTypeDef huart3;
|
UART_HandleTypeDef huart3;
|
||||||
UART_HandleTypeDef huart4;
|
UART_HandleTypeDef huart4;
|
||||||
|
UART_HandleTypeDef huart5;
|
||||||
|
|
||||||
uint16_t Rx_Len = 0;
|
uint16_t Rx_Len = 0;
|
||||||
uint8_t Rx_Buf[Rx_Max] = {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 uint32_t uart1_last_rx_tick = 0;
|
||||||
|
|
||||||
static uint8_t uart2_rx_byte = 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_buf[UART2_RX_BUF_SIZE] = {0};
|
||||||
static uint8_t uart2_cmd_index = 0;
|
static uint8_t uart2_cmd_index = 0;
|
||||||
static uint32_t uart2_last_rx_tick = 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();
|
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)
|
void USART3_StartRx(void)
|
||||||
{
|
{
|
||||||
/* 避免重复启动 DMA: 若已在接收则先停止再启动 */
|
/* 避免重复启动 DMA: 若已在接收则先停止再启动 */
|
||||||
|
|
@ -178,6 +201,15 @@ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||||||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||||||
HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1); /* RS485 秤口同样自愈 */
|
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) {
|
else if (huart->Instance == USART3) {
|
||||||
__HAL_UART_CLEAR_OREFLAG(huart);
|
__HAL_UART_CLEAR_OREFLAG(huart);
|
||||||
__HAL_UART_CLEAR_PEFLAG(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);
|
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) {
|
else if (huart->Instance == UART4) {
|
||||||
/* DMA(NORMAL) 填满 Rx_Buf:连续数据流没有空闲间隙、IDLE 不触发,
|
/* DMA(NORMAL) 填满 Rx_Buf:连续数据流没有空闲间隙、IDLE 不触发,
|
||||||
* 若不在这里搬运并重启,接收将永久停摆(WiFi OTA 大流量下载必现) */
|
* 若不在这里搬运并重启,接收将永久停摆(WiFi OTA 大流量下载必现) */
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ extern UART_HandleTypeDef huart1;
|
||||||
extern UART_HandleTypeDef huart2; /* RS485 喂料秤 */
|
extern UART_HandleTypeDef huart2; /* RS485 喂料秤 */
|
||||||
extern UART_HandleTypeDef huart3; /* 4G Air780E */
|
extern UART_HandleTypeDef huart3; /* 4G Air780E */
|
||||||
extern UART_HandleTypeDef huart4; /* WiFi ESP-01S (PC10=TX, PC11=RX) */
|
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 volatile uint8_t uart1_rx_ready;
|
||||||
extern uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];
|
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_USART2_UART_Init(void);
|
||||||
void MX_USART3_UART_Init(void);
|
void MX_USART3_UART_Init(void);
|
||||||
void MX_UART4_UART_Init(void);
|
void MX_UART4_UART_Init(void);
|
||||||
|
void MX_UART5_UART_Init(void);
|
||||||
void USART3_StartRx(void); /* 启动 USART3 DMA+IDLE 接收 */
|
void USART3_StartRx(void); /* 启动 USART3 DMA+IDLE 接收 */
|
||||||
void USART3_StopRx(void); /* 停止 USART3 DMA 接收(切 WiFi 通道时调用,释放共享 Rx_Buf) */
|
void USART3_StopRx(void); /* 停止 USART3 DMA 接收(切 WiFi 通道时调用,释放共享 Rx_Buf) */
|
||||||
void USART3_SetBaudRate(uint32_t baud); /* 运行中切换 USART3 波特率 */
|
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 UART4_SetBaudRate(uint32_t baud); /* 运行中切换 UART4 波特率 */
|
||||||
void USART1_StartRx(void); /* 启动 USART1 中断接收 */
|
void USART1_StartRx(void); /* 启动 USART1 中断接收 */
|
||||||
void USART2_StartRx(void); /* 启动 USART2 中断接收 */
|
void USART2_StartRx(void); /* 启动 USART2 中断接收 */
|
||||||
|
void UART5_StartRx(void); /* 启动 UART5 中断接收(HLW8032) */
|
||||||
void USART2_Tick(void); /* 触发 USART2 帧超时自动提交 */
|
void USART2_Tick(void); /* 触发 USART2 帧超时自动提交 */
|
||||||
uint16_t USART2_GetFrame(uint8_t *out, uint16_t out_size); /* 从 USART2 取一帧原始字节 */
|
uint16_t USART2_GetFrame(uint8_t *out, uint16_t out_size); /* 从 USART2 取一帧原始字节 */
|
||||||
int USART1_CheckCommand(const char *cmd); /* 检查是否收到指定命令(不区分大小写) */
|
int USART1_CheckCommand(const char *cmd); /* 检查是否收到指定命令(不区分大小写) */
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,15 @@ extern UART_HandleTypeDef huart3;
|
||||||
* 多台设备现场用名字区分;手机列表大约只显示前 10 位 */
|
* 多台设备现场用名字区分;手机列表大约只显示前 10 位 */
|
||||||
#define BLE_NAME "Bt1"
|
#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 配置(透传服务)=====
|
/*===== 蓝牙 GATT UUID 配置(透传服务)=====
|
||||||
* BLE_UUID_CUSTOM = 1:上电把三个 UUID 设为下面的值(重启模块生效)。
|
* BLE_UUID_CUSTOM = 1:上电把三个 UUID 设为下面的值(重启模块生效)。
|
||||||
* = 0:保持模块出厂 UUID(fff0/fff1/fff2),仅海凌科自家 APP 可用
|
* = 0:保持模块出厂 UUID(fff0/fff1/fff2),仅海凌科自家 APP 可用
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,7 @@
|
||||||
<MiscControls>--no_multibyte_chars</MiscControls>
|
<MiscControls>--no_multibyte_chars</MiscControls>
|
||||||
<Define>USE_HAL_DRIVER,STM32F103xE</Define>
|
<Define>USE_HAL_DRIVER,STM32F103xE</Define>
|
||||||
<Undefine></Undefine>
|
<Undefine></Undefine>
|
||||||
<IncludePath>../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</IncludePath>
|
<IncludePath>../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</IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
<Aads>
|
||||||
|
|
@ -687,6 +687,11 @@
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\HardWare\W25Q64\w25q64.c</FilePath>
|
<FilePath>..\HardWare\W25Q64\w25q64.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>hlw8032.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\HardWare\HLW8032\hlw8032.c</FilePath>
|
||||||
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@
|
||||||
| USART2 | RS485 喂料秤 | PA2/PA3 | 9600-8N1 |
|
| USART2 | RS485 喂料秤 | PA2/PA3 | 9600-8N1 |
|
||||||
| USART3 | 4G Air780E/EG MQTT+GNSS | PB10/PB11 | 921600-8N1(见下文波特率自适应) |
|
| USART3 | 4G Air780E/EG MQTT+GNSS | PB10/PB11 | 921600-8N1(见下文波特率自适应) |
|
||||||
| UART4 | WiFi ESP-01S | PC10/PC11 | 115200→921600-8N1(见下文 WiFi 波特率同步) |
|
| UART4 | WiFi ESP-01S | PC10/PC11 | 115200→921600-8N1(见下文 WiFi 波特率同步) |
|
||||||
|
| UART5 | HLW8032 电能计量 | PD2(RX) | 4800-8E1,只收,芯片每 50ms 主动上报 |
|
||||||
| ESP_RST | WiFi 模块复位 | PA5 | 低电平 500ms 复位 |
|
| ESP_RST | WiFi 模块复位 | PA5 | 低电平 500ms 复位 |
|
||||||
| Relay1 | 投喂电机控制 | PB7 | 高电平吸合 |
|
| Relay1 | 投喂电机控制 | PB7 | 高电平吸合 |
|
||||||
| Relay2~4 | 备用控制 | PB8/PC0/PC2 | 高电平吸合 |
|
| Relay2~4 | 备用控制 | PB8/PC0/PC2 | 高电平吸合 |
|
||||||
|
|
@ -100,6 +101,17 @@
|
||||||
- 断电记录只被下次成功启动消费一次(`boot_seen` 位翻转标记),一次掉电 = 一条记录,BL 等待期间不产生记录
|
- 断电记录只被下次成功启动消费一次(`boot_seen` 位翻转标记),一次掉电 = 一条记录,BL 等待期间不产生记录
|
||||||
- BL 找不到有效 APP(如只刷了 BL):打印提示并每 3s 主动复位重试,刷入 APP 即恢复
|
- BL 找不到有效 APP(如只刷了 BL):打印提示并每 3s 主动复位重试,刷入 APP 即恢复
|
||||||
|
|
||||||
|
## 电能计量(HLW8032)
|
||||||
|
|
||||||
|
只计量**累计消耗电量**,上报平台标识符 `energy`(单位 kWh,两位小数)。
|
||||||
|
|
||||||
|
- **硬件**:HLW8032(5V 供电)经 B0505S 隔离电源 + 光耦隔离,芯片 TXD 接 PD2(UART5_RX);电压采样 ZMPT107-1(2mA:2mA,初级 220V 串 100K,次级并 50Ω),电流采样 CT 100A/100mA(1000:1,输出并 2Ω),三个模拟脚各对地 33nF
|
||||||
|
- **通信**:4800bps 8E1(F1 上按 9 位帧长 + 偶校验配置),芯片每 50ms 主动上报 24 字节帧,只收不发;帧同步 = 首字节 0x55/0xAA/0xFx + 第二字节 0x5A + 校验和([2]~[22] 相加低 8 位)
|
||||||
|
- **电量算法**(手册公式):`kWh = 总脉冲 × 功率参数寄存器 × 电压系数 × 电流系数 / (10^9×3600)`;PF 寄存器 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)——改电阻/互感器只动这两个宏
|
||||||
|
- **持久化**:累计脉冲数(uint64)存 EEPROM 偏移 164~171;每攒约 0.1kWh 写一次(限制擦写),断电预警(法拉电容续航内)立即写一次,掉电损失 <0.1kWh
|
||||||
|
- **上报**:MQTT 就绪且芯片在线(1s 内有有效帧)时,每分钟随运行心跳上报一次 `{"energy":%.2f}`;未联网/芯片不在线不上报
|
||||||
|
|
||||||
## 双通道网络(4G 优先,WiFi 兜底)
|
## 双通道网络(4G 优先,WiFi 兜底)
|
||||||
|
|
||||||
网络层 `HardWare/NETWORK/network.c` 对业务层屏蔽底层模组差异,业务只调 `NET_*` 接口;4G 后端(`CAR/air780e.c`,模组内置 MQTT)与 WiFi 后端(`NETWORK/net_wifi.c`,TCP 透传 + 软件 MQTT)同构,运行时互斥切换。
|
网络层 `HardWare/NETWORK/network.c` 对业务层屏蔽底层模组差异,业务只调 `NET_*` 接口;4G 后端(`CAR/air780e.c`,模组内置 MQTT)与 WiFi 后端(`NETWORK/net_wifi.c`,TCP 透传 + 软件 MQTT)同构,运行时互斥切换。
|
||||||
|
|
@ -289,6 +301,7 @@ W25Q64 外部 Flash(8MB):
|
||||||
| 130 | 1B | 上次成功联网方式:0=4G,1=WiFi固定热点,2=WiFi配网热点(仅变化时写) |
|
| 130 | 1B | 上次成功联网方式:0=4G,1=WiFi固定热点,2=WiFi配网热点(仅变化时写) |
|
||||||
| 132~157 | 26B | 蓝牙名称配置缓存(命中则开机跳过蓝牙 AT 设置流程) |
|
| 132~157 | 26B | 蓝牙名称配置缓存(命中则开机跳过蓝牙 AT 设置流程) |
|
||||||
| 160 | 1B | 日志等级(0~5:TRACE/DEBUG/INFO/WARN/ERROR/FATAL) |
|
| 160 | 1B | 日志等级(0~5:TRACE/DEBUG/INFO/WARN/ERROR/FATAL) |
|
||||||
|
| 164~171 | 8B | HLW8032 累计脉冲数(uint64,每攒 0.1kWh + 断电前写入) |
|
||||||
| 250 | 1B | 探测字节(上电写 0xA5 回读,验证 I2C 通信) |
|
| 250 | 1B | 探测字节(上电写 0xA5 回读,验证 I2C 通信) |
|
||||||
|
|
||||||
> 注意:改 `MqttInfo_Str` 结构体会改变上述偏移,秤参数(120+)和联网方式(130)在
|
> 注意:改 `MqttInfo_Str` 结构体会改变上述偏移,秤参数(120+)和联网方式(130)在
|
||||||
|
|
@ -305,6 +318,7 @@ W25Q64 外部 Flash(8MB):
|
||||||
| `sw1` / `feeding` | 第一路继电器状态 | 1=投喂中,0=停止;无秤模式下两字段**同时上报**,平台两个开关同步刷新 |
|
| `sw1` / `feeding` | 第一路继电器状态 | 1=投喂中,0=停止;无秤模式下两字段**同时上报**,平台两个开关同步刷新 |
|
||||||
| `sw2~sw4` | 备用继电器状态 | 0/1 |
|
| `sw2~sw4` | 备用继电器状态 | 0/1 |
|
||||||
| `pow` | 电量状态 | 1=正常,0=低电量 |
|
| `pow` | 电量状态 | 1=正常,0=低电量 |
|
||||||
|
| `energy` | 累计消耗电量 | HLW8032 计量,单位 kWh,两位小数,联网后每分钟上报 |
|
||||||
| `GPS` | 定位坐标 | 仅 4G 通道(Air780EG),GCJ-02 高德坐标系,格式 `"经度,纬度"`,每 5 分钟上报 |
|
| `GPS` | 定位坐标 | 仅 4G 通道(Air780EG),GCJ-02 高德坐标系,格式 `"经度,纬度"`,每 5 分钟上报 |
|
||||||
|
|
||||||
> 注:`zero`(剩余料重)与 `onceWt` 为称重模式专用字段——`PRODUCT_WITH_FEED_SCALE=0` 时状态上报不携带这两个字段,平台下发设置会收到 `no scale on this device` 拒绝应答。
|
> 注:`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
|
│ ├── NETWORK/ # 网络层:network.c 通道切换/统一分发 + net_wifi.c WiFi 后端 + net_wifi_ota.c WiFi OTA
|
||||||
│ ├── WIFI/ # esp8266.c ESP-01S AT驱动/透传/SmartConfig + mqtt_client.c 软件MQTT
|
│ ├── WIFI/ # esp8266.c ESP-01S AT驱动/透传/SmartConfig + mqtt_client.c 软件MQTT
|
||||||
│ ├── CAR/ # Air780E/EG AT 驱动、波特率自适应、CSQ 信号检测、GNSS 定位、OTA 下载
|
│ ├── CAR/ # Air780E/EG AT 驱动、波特率自适应、CSQ 信号检测、GNSS 定位、OTA 下载
|
||||||
│ ├── UART/ # USART1/2/3+UART4 初始化、运行中切波特率、中断/DMA 接收、ORE 自愈
|
│ ├── UART/ # USART1/2/3+UART4/5 初始化、运行中切波特率、中断/DMA 接收、ORE 自愈
|
||||||
|
│ ├── HLW8032/ # 电能计量(UART5 帧解析、PF 脉冲累计、kWh 换算、EEPROM 持久化)
|
||||||
│ ├── 24C02/ # EEPROM 读写(页写入,带跨任务互斥锁)
|
│ ├── 24C02/ # EEPROM 读写(页写入,带跨任务互斥锁)
|
||||||
│ ├── IIC/ # 软件 I2C(带总线恢复:SDA 被拉死时补 9 时钟释放)
|
│ ├── IIC/ # 软件 I2C(带总线恢复:SDA 被拉死时补 9 时钟释放)
|
||||||
│ ├── ADC/ # 电池电压检测(0~100% 限幅、掉电去抖判定)
|
│ ├── ADC/ # 电池电压检测(0~100% 限幅、掉电去抖判定)
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,24 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
|
||||||
|
|
||||||
/* USER CODE END UART4_MspInit 1 */
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ extern UART_HandleTypeDef huart3;
|
||||||
extern UART_HandleTypeDef huart4;
|
extern UART_HandleTypeDef huart4;
|
||||||
extern UART_HandleTypeDef huart2;
|
extern UART_HandleTypeDef huart2;
|
||||||
extern UART_HandleTypeDef huart1;
|
extern UART_HandleTypeDef huart1;
|
||||||
|
extern UART_HandleTypeDef huart5;
|
||||||
/* USER CODE BEGIN EV */
|
/* USER CODE BEGIN EV */
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
/* USER CODE END EV */
|
/* USER CODE END EV */
|
||||||
|
|
@ -325,6 +326,14 @@ void USART3_IRQHandler(void)
|
||||||
/* USER CODE END USART3_IRQn 1 */
|
/* 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 BEGIN 1 */
|
||||||
|
|
||||||
/* USER CODE END 1 */
|
/* USER CODE END 1 */
|
||||||
|
|
|
||||||
11
V1.5/版本说明.md
11
V1.5/版本说明.md
|
|
@ -93,3 +93,14 @@
|
||||||
- 蓝牙改名被撞写:APP 数据撞进 AT 窗口把名字写成 "info" → 改"先查询后设置"幂等流程(名字已对就不开 AT 窗口)
|
- 蓝牙改名被撞写:APP 数据撞进 AT 窗口把名字写成 "info" → 改"先查询后设置"幂等流程(名字已对就不开 AT 窗口)
|
||||||
- 设置后当场回查失败:模块设置重启才生效,改为下次开机查询校验
|
- 设置后当场回查失败:模块设置重启才生效,改为下次开机查询校验
|
||||||
- OTA 结果/确认上报超时:net 任务与业务任务竞争共享接收缓冲 → NET_process 消费加锁、发布改 2s 超时锁
|
- OTA 结果/确认上报超时:net 任务与业务任务竞争共享接收缓冲 → NET_process 消费加锁、发布改 2s 超时锁
|
||||||
|
|
||||||
|
### 追加:HLW8032 电能计量(2026-08)
|
||||||
|
|
||||||
|
- 新增 `HardWare/HLW8032/`:UART5(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`(kWh 两位小数),MQTT 就绪且芯片在线时每分钟一次,4G/WiFi 双通道
|
||||||
|
- UART5 带 ORE 自愈;硬件:B0505S 隔离电源 + 光耦,芯片 TXD 接 PD2
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue