当前位置:首页 > 消费电子 > 消费电子
[导读]智能插座不是“ESP接继电器+网页点一下”就完事。量产固件要把三件事拆开:远程指令只改状态、计量芯片独立采数、定时任务非阻塞跑。主循环里一堆delay、继电器直接跟WiFi回调耦合,基本就是掉线卡死、定时漂移、电量跳变的起点。


智能插座不是“ESP接继电器+网页点一下”就完事。量产固件要把三件事拆开:远程指令只改状态、计量芯片独立采数、定时任务非阻塞跑。主循环里一堆delay、继电器直接跟WiFi回调耦合,基本就是掉线卡死、定时漂移、电量跳变的起点。

一、系统分层

典型架构:

云端/MQTT ──> WiFi模块(ESP8266/ESP32)

               │ UART/AT或直跑固件

               ▼

           主控逻辑(状态机)

  ┌────────┴────────┬──────────┐

继电器驱动        计量芯片       按键/LED

(GPIO)      (HLW8032/CSE)   (本地覆盖)

WiFi侧只负责收指令、回状态;继电器归本地状态机管;计量芯片走独立串口或脉冲采集;定时任务挂在系统节拍上。

二、远程开关:指令改状态,别直接动继电器

MQTT下发{"switch":1},固件别在回调里直接set_gpio,先更状态再统一执行:

typedef struct {

   uint8_t relay_req;     // 请求状态

   uint8_t relay_act;     // 实际状态

   uint8_t lock;          // 童锁

} socket_ctl_t;


void mqtt_on_msg(const char*json){

   if(json_get_bool(json,"switch"))

       ctl.relay_req = 1;

   else

       ctl.relay_req = 0;

   // 不在这里操作GPIO

}


void relay_task_10ms(void){

   if(ctl.lock) return;

   if(ctl.relay_req != ctl.relay_act){

       gpio_write(RELAY_PIN, ctl.relay_req);

       ctl.relay_act = ctl.relay_req;

       mqtt_publish_state(ctl.relay_act);   // 状态回传

       nv_save_relay(ctl.relay_act);        // 断电记忆

   }

}

好处:本地按键、APP、定时任务都走relay_req,不会互相打架;状态变化才上报,不刷屏。

按键本地覆盖同理:

if(key_edge()){

   ctl.relay_req = !ctl.relay_act;

}

三、电量统计:走计量芯片,不靠ADC瞎算

电阻采样+MCU ADC算功率误差大、校准烦。正经用HLW8032/CSE7759B,UART直接读电压电流有功功率;HLW8012类则是测CF脉冲周期。

HLW8032串口4800bps,帧格式固定,解析核心:

uint8_t hlw_rx[24];

void meter_parse(void){

   if(uart_recv(hlw_rx,24)!=24) return;

   if(hlw_rx[0]!=0x55) return;            // 帧头

   uint16_t v = (hlw_rx[2]<<8)|hlw_rx[3];

   uint16_t i = (hlw_rx[4]<<8)|hlw_rx[5];

   uint16_t p = (hlw_rx[8]<<8)|hlw_rx[9];

   volt = v * V_COEF;

   curr = i * I_COEF;

   power = p * P_COEF;                    // 系数产测标定

}

电能累计用功率对时间积分,别每帧清零:

static float energy_kwh;

void energy_accum(uint32_t ms){

   static uint32_t last;

   uint32_t dt = ms-last; last=ms;

   energy_kwh += power * (dt/1000.0f) / 3600.0f / 1000.0f;

}

要点:

系数放NV,出厂标定点存进去

功率<5W当待机,可不上报

电流过流/功率过载→强制断继电器

串口电平转换:计量芯片5V、WiFi模块3.3V要分压

四、定时控制:非阻塞状态机

别写delay(3600000)等定时到——WiFi回调、MQTT心跳全卡死。用系统节拍比较:

typedef struct {

   uint32_t on_sec;

   uint32_t off_sec;

   uint8_t  enable;

   uint8_t  repeat;

} timer_t;


timer_t timers[4];


void timer_task(uint32_t now_sec){

   for(int k=0;k<4;k++){

       if(!timers[k].enable) continue;

       if(timers[k].on_sec && now_sec>=timers[k].on_sec){

           ctl.relay_req = 1;

           timers[k].on_sec = timers[k].repeat? timers[k].on_sec+86400:0;

       }

       if(timers[k].off_sec && now_sec>=timers[k].off_sec){

           ctl.relay_req = 0;

           timers[k].off_sec = timers[k].repeat? timers[k].off_sec+86400:0;

       }

   }

}

时间源用SNTP对时后的RTC秒;没联网先用MCU节拍近似,联网后校正。

倒计时的写法:

if(timer.countdown){

   if(now_sec >= timer.off_at)

       ctl.relay_req = 0;

}

时间比较一律用now-last>=interval,别用now>target,49天回卷会炸。

五、掉电记忆与过载保护

断电再来电,继电器状态从NV读,别默认常开:

ctl.relay_act = nv_load_relay();   // 上电关闭/恢复上次

gpio_write(RELAY_PIN, ctl.relay_act);

过载保护独立判断,不等APP:

if(power > MAX_POWER_W || curr > MAX_I_A){

   ctl.relay_req = 0;

   mqtt_publish_fault(OVERLOAD);

}

六、落坑清单

MQTT回调里直接写继电器→本地按键冲突

主循环delay等定时→WiFi断线不重连

ADC电阻分压算功率→误差20%

HLW串口波特率错→全是0x00

5V计量芯片直连3.3V RX→烧IO

断电不存继电器状态→来电自启危险负载

定时用系统秒但不对时→凌晨跳变

功率每帧上报→云端刷屏限流

过载只上报不断继电器→跳闸/起火

按键和APP同时操作无仲裁→状态撕裂

七、落地顺序

继电器单独状态机,relay_req/relay_act分离

MQTT/按键/定时都只改relay_req

串口接HLW8032,标定电压电流功率系数

功率积分算电能,存NV

定时任务挂RTC秒,非阻塞比较

SNTP对时校正

断电记忆+过载强制断

状态变化上报,功率按阈值上报

智能插座固件稳不稳,不在能连WiFi,在执行出口唯一、采样走专用计量芯片、定时不阻塞主循环。远程开关只改状态,电量交给HLW/CSE,定时挂在节拍上——三者解耦后,APP、按键、定时、过载互不踩踏。剩下的都是细节:串口电平、系数标定、断电记忆、上报节流,哪条漏了现场就出怪问题。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭