扩展板改按需检测:取消2s轮询,平时零流量;命令三段式(FC03预读+FC05+FC03校验),上电一次性探测保留断电恢复
This commit is contained in:
parent
fa8942aca1
commit
4fb21a4b43
|
|
@ -82,15 +82,16 @@
|
|||
4. 反馈采样建议 10~50ms 周期,加简单消抖(如连续 3 次一致才更新 REG1);**消抖总时长必须 <150ms**——主控在 FC05 回显后 150ms 就读 FC03 校验反馈位,反馈跟不上会误判"负载未通电"
|
||||
5. 只响应地址 0x10 的帧;**不要响应广播/其它地址**(总线上还有秤,地址 0x01)
|
||||
6. 收帧间隔不足 50ms 也要能正常解析(主控保证发送间隔,从机只做鲁棒接收)
|
||||
7. 主控**平时不发帧**(无周期轮询,只在控制命令和上电探测时通信),从机不要把"长时间收不到帧"当异常处理
|
||||
|
||||
## 5. 主机行为(联调参考)
|
||||
|
||||
主控侧已实现(`HardWare/RELAY/ext_relay.c`):
|
||||
主控侧已实现(`HardWare/RELAY/ext_relay.c`),**平时总线零流量(无周期轮询),只在控制时检测**:
|
||||
|
||||
- **命令流程**:平台/蓝牙下发 → FC05 → 等回显(300ms 超时,补发 1 次)→ 延时 150ms 等触点稳定 → FC03 读状态 → 校验"输出位=目标 且 反馈位=目标 且 **反馈位有跳变**(命令前≠目标,与板载继电器反馈同语义;重复命令原本已在目标态的豁免)" → 应答平台(失败:`Load unpowered / relay failure !`)→ 上报全状态
|
||||
- **周期轮询**:空闲每 2s 发一次 FC03,兼在线检测;连续 3 次无应答判离线(日志提示)
|
||||
- **上电探测**:主控上电 3s 后发一次 FC03——有应答则标记在线并触发断电恢复比对;无应答(补发 1 次仍无)记日志"未接扩展板?",不影响其它功能
|
||||
- **命令流程**:平台/蓝牙下发 → **FC03 预读**(判定在线 + 快照命令前反馈值;无应答补发 1 次,仍无应答回平台 `ext relay board offline`)→ FC05 → 等回显(300ms 超时,补发 1 次)→ 延时 150ms 等触点稳定 → FC03 读状态 → 校验"输出位=目标 且 反馈位=目标 且 **反馈位有跳变**(命令前≠目标,与板载继电器反馈同语义;重复命令原本已在目标态的豁免)" → 应答平台(失败:`Load unpowered / relay failure !`)→ 上报全状态
|
||||
- **离线判定**:命令链路最终无应答即判离线(日志提示),不单独周期监测;下次命令第一步自动重新探测,恢复应答即上线
|
||||
- **断电记忆恢复**:扩展板状态存在主控 EEPROM(偏移 102 的 Relay_State[5],bit0~3);每次离线→上线时比对实际状态与记忆,不一致的回路逐路补发 FC05 纠正,恢复完成统一上报一次
|
||||
- **离线行为**:离线期间下发命令直接回复平台 "ext relay board offline";板子恢复应答后自动上线并补一次状态上报
|
||||
- 上电 3s 内不发帧(避开上电窗口)
|
||||
|
||||
## 6. 平台/蓝牙映射
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@
|
|||
* 协议: Modbus RTU, 从机地址 0x10, 详见 Docs/RS485扩展继电器协议.md
|
||||
* FC05 写单线圈(线圈0~3=继电器1~4, 0xFF00吸合/0x0000断开), 从机回显
|
||||
* FC03 读保持寄存器 0x0000 起 4 个: 输出状态/反馈状态/故障标志/固件版本
|
||||
* 时序: 总线静默 >=50ms 才发帧(与秤查询共用 rs485_bus 时间戳);
|
||||
* 应答超时 300ms 补发 1 次; 空闲每 2s 轮询一次状态兼在线检测
|
||||
* 时序: 总线静默 >=50ms 才发帧(与秤查询共用 rs485_bus 时间戳); 应答超时 300ms 补发 1 次
|
||||
* 检测策略: 平时零流量(无周期轮询), 只在以下时机收发:
|
||||
* 1) 上电 3s 后一次性探测(确认在线 + 触发断电状态恢复)
|
||||
* 2) 平台/蓝牙控制命令: FC03 读当前态(快照命令前反馈) -> FC05 -> 150ms -> FC03 校验跳变
|
||||
* 3) 断电恢复: 离线->上线时比对 EEPROM 记忆, 不一致的回路逐路补发 FC05
|
||||
*/
|
||||
|
||||
#include "ext_relay.h"
|
||||
|
|
@ -21,8 +24,11 @@
|
|||
|
||||
#define EXT_RESP_TIMEOUT_MS 300u /* 应答超时 */
|
||||
#define EXT_FB_SETTLE_MS 150u /* 命令回显后等触点/负载稳定再读反馈 */
|
||||
#define EXT_POLL_INTERVAL_MS 2000u /* 空闲轮询周期 */
|
||||
#define EXT_OFFLINE_MISS 3u /* 连续失败次数判离线 */
|
||||
|
||||
/* 帧事件(on_frame 置位, process 消费; 同在 app_task 单线程) */
|
||||
static uint8_t rx_echo_ok = 0;
|
||||
static uint8_t rx_state_ok = 0;
|
||||
static uint8_t rx_exc = 0;
|
||||
|
||||
/* Modbus CRC16(与秤同款多项式) */
|
||||
static uint16_t ext_crc16(const uint8_t *data, uint16_t len)
|
||||
|
|
@ -37,15 +43,10 @@ static uint16_t ext_crc16(const uint8_t *data, uint16_t len)
|
|||
return crc;
|
||||
}
|
||||
|
||||
/* 帧事件(on_frame 置位, process 消费; 同在 app_task 单线程) */
|
||||
static uint8_t rx_echo_ok = 0;
|
||||
static uint8_t rx_state_ok = 0;
|
||||
static uint8_t rx_exc = 0;
|
||||
|
||||
/* 总线发送: 等 50ms 静默 + 清接收缓冲(防陈旧帧) + 发送 + 刷新时间戳 */
|
||||
/* 总线发送: 清残留应答标志 + 等 50ms 静默 + 清接收缓冲 + 发送 + 刷新时间戳 */
|
||||
static void ext_tx(const uint8_t *frame, uint16_t len)
|
||||
{
|
||||
rx_echo_ok = 0; /* 清上一事务残留的应答标志, 防止迟到帧被当前事务误消费 */
|
||||
rx_echo_ok = 0;
|
||||
rx_state_ok = 0;
|
||||
rx_exc = 0;
|
||||
uint32_t dt = HAL_GetTick() - rs485_bus_last_tick();
|
||||
|
|
@ -89,21 +90,29 @@ static uint8_t s_state = 0; /* REG0
|
|||
static uint8_t s_fb = 0; /* REG1 反馈状态 */
|
||||
static uint8_t s_fault = 0; /* REG2 故障标志 */
|
||||
static uint16_t s_ver = 0; /* REG3 从机版本 */
|
||||
static uint8_t s_miss = 0; /* 连续无应答计数 */
|
||||
static uint8_t s_fault_logged = 0; /* 已打印的故障位(变化才重打) */
|
||||
static uint32_t s_last_poll = 0;
|
||||
|
||||
/* 命令状态机 */
|
||||
static uint8_t cmd_pending = 0; /* 有命令待发送 */
|
||||
static uint8_t cmd_stage = 0; /* 0闲 1等FC05回显 2触点稳定延时 3等FC03应答 */
|
||||
/* 事务阶段 */
|
||||
#define ST_IDLE 0 /* 空闲 */
|
||||
#define ST_READ 1 /* 独立读: 上电探测 / 命令前读取 */
|
||||
#define ST_ECHO 2 /* 等 FC05 回显 */
|
||||
#define ST_SETTLE 3 /* 触点稳定延时 */
|
||||
#define ST_CONFIRM 4 /* 命令后读校验 */
|
||||
|
||||
/* 事务类型 */
|
||||
#define TXN_NONE 0 /* 上电探测 */
|
||||
#define TXN_CMD 1 /* 平台/蓝牙命令 */
|
||||
#define TXN_RESTORE 2 /* 断电恢复补发 */
|
||||
|
||||
static uint8_t cmd_stage = ST_IDLE;
|
||||
static uint8_t cmd_txn = TXN_NONE;
|
||||
static uint8_t cmd_pending = 0; /* 有用户命令待发送 */
|
||||
static uint8_t cmd_ch = 0, cmd_on = 0, cmd_retry = 0;
|
||||
static uint8_t cmd_is_poll = 0; /* 当前事务是轮询(不应答平台) */
|
||||
static uint8_t cmd_is_restore = 0;/* 当前事务是断电恢复(不应答平台) */
|
||||
static uint32_t cmd_tick = 0;
|
||||
static char cmd_id[20] = {0};
|
||||
static uint8_t cmd_state_before = 0; /* 命令前输出位(最近轮询值) */
|
||||
static uint8_t cmd_fb_before = 0; /* 命令前反馈位(最近轮询值) */
|
||||
|
||||
static uint8_t cmd_state_before = 0; /* 命令前输出位(FC03 预读值) */
|
||||
static uint8_t cmd_fb_before = 0; /* 命令前反馈位(FC03 预读值) */
|
||||
static uint8_t boot_probe_done = 0; /* 上电一次性探测已发 */
|
||||
|
||||
#define EXT_STATE_EEPROM_IDX 5 /* MqttInfoStr.Relay_State[5] 原保留字节: 扩展板状态位掩码 */
|
||||
|
||||
|
|
@ -134,9 +143,9 @@ uint8_t ext_relay_online(void) { return s_online; }
|
|||
uint8_t ext_relay_state_mask(void) { return s_state; }
|
||||
uint8_t ext_relay_fault_mask(void) { return s_fault; }
|
||||
|
||||
/* 一次事务成功: fresh_state=1 表示刚收到 FC03(状态是最新的) */
|
||||
static void ext_note_success(int fresh_state)
|
||||
{
|
||||
s_miss = 0;
|
||||
if (!s_online) {
|
||||
s_online = 1;
|
||||
log_info("> EXT: 扩展继电器板上线 (从机版本 V%u.%02X)", s_ver >> 8, s_ver & 0xFF);
|
||||
|
|
@ -156,10 +165,9 @@ static void ext_note_success(int fresh_state)
|
|||
|
||||
static void ext_note_fail(void)
|
||||
{
|
||||
if (s_miss < 255) s_miss++;
|
||||
if (s_online && s_miss >= EXT_OFFLINE_MISS) {
|
||||
if (s_online) {
|
||||
s_online = 0;
|
||||
log_warn("> EXT: 扩展继电器板离线(连续 %u 次无应答)", EXT_OFFLINE_MISS);
|
||||
log_warn("> EXT: 扩展继电器板离线(命令无应答)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,12 +182,8 @@ static void ext_respond(int ok, const char *msg)
|
|||
void ext_relay_cmd(uint8_t ch, uint8_t on, const char *id)
|
||||
{
|
||||
if (ch < 1 || ch > EXT_RELAY_CH) return;
|
||||
if (!s_online) {
|
||||
log_warn("> EXT: 扩展板离线, 拒绝 SW%d 命令", ch + 4);
|
||||
if (id) NET_publish_response(id, 0, "ext relay board offline");
|
||||
return;
|
||||
}
|
||||
if (cmd_pending || cmd_stage != 0) {
|
||||
/* 不在线也照常受理: 命令链路第一步就是 FC03 探测, 不通才应答离线(平时无轮询) */
|
||||
if (cmd_pending || cmd_stage != ST_IDLE) {
|
||||
log_warn("> EXT: 上一命令未完成, 拒绝 SW%d 命令", ch + 4);
|
||||
if (id) NET_publish_response(id, 0, "ext relay busy");
|
||||
return;
|
||||
|
|
@ -233,79 +237,130 @@ void ext_relay_on_frame(const uint8_t *b, uint16_t len)
|
|||
log_warn("> EXT: 未识别帧 FC=%02X len=%u", b[1], (unsigned)len);
|
||||
}
|
||||
|
||||
/* 当前事务的最终失败收尾 */
|
||||
static void ext_txn_failed(const char *respond_msg)
|
||||
{
|
||||
if (cmd_txn == TXN_CMD) {
|
||||
log_warn("> EXT: SW%d 命令失败(%s)", cmd_ch + 4, respond_msg);
|
||||
ext_respond(0, respond_msg);
|
||||
} else if (cmd_txn == TXN_RESTORE) {
|
||||
restore_next_tick = HAL_GetTick() + 2000; /* 退避后重试, 位保留 */
|
||||
} else {
|
||||
log_warn("> EXT: 上电探测无应答(未接扩展板?)");
|
||||
}
|
||||
ext_note_fail();
|
||||
cmd_txn = TXN_NONE;
|
||||
cmd_stage = ST_IDLE;
|
||||
}
|
||||
|
||||
/* 事务超时/异常统一处理: 补发 1 次, 仍失败则收尾 */
|
||||
static void ext_txn_retry_or_fail(uint8_t resend_fc05, const char *respond_msg)
|
||||
{
|
||||
if (cmd_retry < 1) {
|
||||
cmd_retry++;
|
||||
if (resend_fc05) ext_send_fc05(cmd_ch, cmd_on);
|
||||
else ext_send_fc03();
|
||||
cmd_tick = HAL_GetTick();
|
||||
return;
|
||||
}
|
||||
ext_txn_failed(respond_msg);
|
||||
}
|
||||
|
||||
void ext_relay_process(void)
|
||||
{
|
||||
uint32_t now = HAL_GetTick();
|
||||
if (now < 3000u) return; /* 上电稳定期, 与秤首次查询对齐 */
|
||||
|
||||
/* 取新命令(仅空闲时) */
|
||||
if (cmd_pending && cmd_stage == 0) {
|
||||
cmd_pending = 0;
|
||||
cmd_is_poll = 0;
|
||||
/* 上电一次性探测: 确认在线 + 触发断电恢复比对 */
|
||||
if (!boot_probe_done && cmd_stage == ST_IDLE && !cmd_pending) {
|
||||
boot_probe_done = 1;
|
||||
cmd_txn = TXN_NONE;
|
||||
cmd_retry = 0;
|
||||
/* 快照命令前状态(与板载一致: 校验反馈跳变, 防从机反馈卡死误判成功) */
|
||||
cmd_state_before = (uint8_t)((s_state >> (cmd_ch - 1)) & 1u);
|
||||
cmd_fb_before = (uint8_t)((s_fb >> (cmd_ch - 1)) & 1u);
|
||||
cmd_stage = 1;
|
||||
ext_send_fc05(cmd_ch, cmd_on);
|
||||
cmd_stage = ST_READ;
|
||||
ext_send_fc03();
|
||||
cmd_tick = now;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_stage == 1) { /* 等 FC05 回显 */
|
||||
if (rx_echo_ok) {
|
||||
rx_echo_ok = 0;
|
||||
ext_note_success(0);
|
||||
cmd_stage = 2;
|
||||
cmd_tick = now;
|
||||
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
||||
rx_exc = 0;
|
||||
if (cmd_retry < 1) {
|
||||
cmd_retry++;
|
||||
/* 用户命令: 先 FC03 预读(判定在线+快照命令前状态) */
|
||||
if (cmd_pending && cmd_stage == ST_IDLE) {
|
||||
cmd_pending = 0;
|
||||
cmd_txn = TXN_CMD;
|
||||
cmd_retry = 0;
|
||||
cmd_stage = ST_READ;
|
||||
ext_send_fc03();
|
||||
cmd_tick = now;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_stage == ST_READ) {
|
||||
if (rx_state_ok) {
|
||||
rx_state_ok = 0;
|
||||
ext_note_success(1);
|
||||
if (s_fault != s_fault_logged) { /* 故障位变化才打印 */
|
||||
s_fault_logged = s_fault;
|
||||
if (s_fault) {
|
||||
log_warn("> EXT: 反馈异常标志=%02X (输出=%02X 反馈=%02X)", s_fault, s_state, s_fb);
|
||||
}
|
||||
}
|
||||
if (cmd_txn == TXN_CMD) {
|
||||
/* 快照命令前状态(与板载一致: 校验反馈跳变, 防从机反馈卡死误判成功) */
|
||||
cmd_state_before = (uint8_t)((s_state >> (cmd_ch - 1)) & 1u);
|
||||
cmd_fb_before = (uint8_t)((s_fb >> (cmd_ch - 1)) & 1u);
|
||||
cmd_retry = 0;
|
||||
cmd_stage = ST_ECHO;
|
||||
ext_send_fc05(cmd_ch, cmd_on);
|
||||
cmd_tick = now;
|
||||
} else {
|
||||
log_warn("> EXT: SW%d 命令无应答", cmd_ch + 4);
|
||||
if (!cmd_is_restore) ext_respond(0, "ext relay no response");
|
||||
else { cmd_is_restore = 0; restore_next_tick = now + 2000; }
|
||||
ext_note_fail();
|
||||
cmd_stage = 0;
|
||||
cmd_txn = TXN_NONE;
|
||||
cmd_stage = ST_IDLE; /* 上电探测完成 */
|
||||
}
|
||||
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
||||
rx_exc = 0;
|
||||
if (cmd_txn == TXN_CMD) {
|
||||
ext_txn_retry_or_fail(0, "ext relay board offline");
|
||||
} else {
|
||||
ext_txn_retry_or_fail(0, "");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_stage == 2) { /* 触点/负载稳定延时 */
|
||||
if (cmd_stage == ST_ECHO) { /* 等 FC05 回显 */
|
||||
if (rx_echo_ok) {
|
||||
rx_echo_ok = 0;
|
||||
ext_note_success(0);
|
||||
cmd_stage = ST_SETTLE;
|
||||
cmd_tick = now;
|
||||
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
||||
rx_exc = 0;
|
||||
ext_txn_retry_or_fail(1, "ext relay no response");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_stage == ST_SETTLE) { /* 触点/负载稳定延时 */
|
||||
if ((now - cmd_tick) >= EXT_FB_SETTLE_MS) {
|
||||
cmd_retry = 0;
|
||||
cmd_stage = 3;
|
||||
cmd_stage = ST_CONFIRM;
|
||||
ext_send_fc03();
|
||||
cmd_tick = now;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_stage == 3) { /* 等 FC03 状态应答(命令收尾或周期轮询共用) */
|
||||
if (cmd_stage == ST_CONFIRM) { /* 命令后读校验 */
|
||||
if (rx_state_ok) {
|
||||
rx_state_ok = 0;
|
||||
ext_note_success(1);
|
||||
if (cmd_is_restore) {
|
||||
/* 断电恢复的一路已完成: 清位, 全部完成才统一保存+上报 */
|
||||
cmd_is_restore = 0;
|
||||
if (cmd_txn == TXN_RESTORE) {
|
||||
cmd_txn = TXN_NONE;
|
||||
restore_diff &= (uint8_t)~(1u << (cmd_ch - 1));
|
||||
if (!restore_diff) {
|
||||
log_info("> EXT: 断电状态恢复完成 (输出=%02X)", s_state);
|
||||
ext_save_state();
|
||||
relayStatueUpdata();
|
||||
}
|
||||
} else if (cmd_is_poll) {
|
||||
cmd_is_poll = 0;
|
||||
if (s_fault != s_fault_logged) { /* 故障位变化才打印, 防止每 2s 刷屏 */
|
||||
s_fault_logged = s_fault;
|
||||
if (s_fault) {
|
||||
log_warn("> EXT: 反馈异常标志=%02X (输出=%02X 反馈=%02X)", s_fault, s_state, s_fb);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 与板载继电器反馈同语义: 输出位=目标 且 反馈位=目标 且 反馈有跳变
|
||||
* (命令前!=目标, 命令后=目标); 重复命令原本就在目标态的豁免跳变要求。
|
||||
|
|
@ -325,54 +380,31 @@ void ext_relay_process(void)
|
|||
cmd_state_before, cmd_fb_before);
|
||||
ext_respond(0, "Load unpowered / relay failure !"); /* 与板载失败文案一致 */
|
||||
}
|
||||
cmd_txn = TXN_NONE;
|
||||
ext_save_state(); /* 断电记忆: 以实际输出状态落盘 */
|
||||
relayStatueUpdata(); /* 命令完成后上报全状态 */
|
||||
}
|
||||
cmd_stage = 0;
|
||||
cmd_stage = ST_IDLE;
|
||||
} else if (rx_exc || (now - cmd_tick) > EXT_RESP_TIMEOUT_MS) {
|
||||
rx_exc = 0;
|
||||
if (cmd_retry < 1) {
|
||||
cmd_retry++;
|
||||
ext_send_fc03();
|
||||
cmd_tick = now;
|
||||
} else {
|
||||
if (!cmd_is_poll && !cmd_is_restore) {
|
||||
log_warn("> EXT: SW%d 状态确认无应答", cmd_ch + 4);
|
||||
ext_respond(0, "ext relay no response");
|
||||
}
|
||||
cmd_is_poll = 0;
|
||||
if (cmd_is_restore) { cmd_is_restore = 0; restore_next_tick = now + 2000; }
|
||||
ext_note_fail();
|
||||
cmd_stage = 0;
|
||||
}
|
||||
ext_txn_retry_or_fail(0, "ext relay no response");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 断电恢复: 逐路补发 FC05 使扩展板回到 EEPROM 记忆状态 */
|
||||
if (restore_diff && now >= restore_next_tick) {
|
||||
/* 断电恢复: 逐路补发 FC05 使扩展板回到 EEPROM 记忆状态(空闲且无争用时) */
|
||||
if (restore_diff && now >= restore_next_tick && cmd_stage == ST_IDLE && !cmd_pending) {
|
||||
uint8_t bit = (uint8_t)(restore_diff & (uint8_t)(-(int)restore_diff)); /* 最低待恢复位 */
|
||||
uint8_t ch = 1;
|
||||
while (!(bit & 1)) { bit >>= 1; ch++; }
|
||||
cmd_is_poll = 0;
|
||||
cmd_is_restore = 1;
|
||||
cmd_txn = TXN_RESTORE;
|
||||
cmd_ch = ch;
|
||||
cmd_on = (uint8_t)((restore_target >> (ch - 1)) & 1u);
|
||||
cmd_retry = 0;
|
||||
cmd_stage = 1;
|
||||
cmd_stage = ST_ECHO;
|
||||
ext_send_fc05(cmd_ch, cmd_on);
|
||||
cmd_tick = now;
|
||||
log_info("> EXT: 恢复 SW%d -> %s", ch + 4, cmd_on ? "开" : "关");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 空闲: 周期轮询(兼在线检测) */
|
||||
if ((now - s_last_poll) >= EXT_POLL_INTERVAL_MS) {
|
||||
s_last_poll = now;
|
||||
cmd_is_poll = 1;
|
||||
cmd_retry = 0;
|
||||
cmd_stage = 3;
|
||||
ext_send_fc03();
|
||||
cmd_tick = now;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
版本说明.md
5
版本说明.md
|
|
@ -16,6 +16,11 @@
|
|||
- 协议文档:`Docs/RS485扩展继电器协议.md`(从机板按此实现)
|
||||
|
||||
### 追加(2026-09-04)
|
||||
- **扩展板检测改为按需触发,取消 2s 周期轮询**(平时总线零流量):
|
||||
上电 3s 一次性 FC03 探测(确认在线 + 触发断电恢复比对);
|
||||
控制命令改三段式:FC03 预读(判定在线 + 快照命令前反馈)→ FC05 → 150ms → FC03 校验跳变;
|
||||
命令链路最终无应答即判离线并应答平台 `ext relay board offline`,下次命令自动重新探测恢复;
|
||||
断电恢复触发点不变(离线→上线比对 EEPROM 逐路补发)
|
||||
- **扩展板状态断电记忆+上电恢复**(与板载继电器一致):状态位掩码存 `MqttInfoStr.Relay_State[5]`(原保留字节,
|
||||
bit0~3=扩展 1~4 路,0xFF 空白视为全断),复用 EEPROM 偏移 102 现有落盘路径;
|
||||
扩展板每次离线→上线时比对 FC03 实际状态与 EEPROM 记忆,不一致的回路逐路补发 FC05 纠正
|
||||
|
|
|
|||
Loading…
Reference in New Issue