Files
十七 42a4650a78 feat: 完善Mesh继电器OTA与地址协议
- 增加STM8 Bootloader工程及出厂固件恢复流程\n- 增加W25Q64外部Flash驱动和OTA分包接收、CRC16校验、断点续传状态管理\n- 增加固件版本查询、升级结果上报与主机确认机制\n- 将业务帧从55 AA帧头调整为发送方Mesh短地址+CMD+LEN+DATA+CRC16\n- 修正JDY-28M外层地址与业务发送方地址的职责划分,支持广播请求定向应答\n- 同步更新硬件引脚、存储分区、OTA流程和主机通信协议文档\n- 已使用SDCC重新编译,应用代码大小为5512字节,链接地址为0x8800
2026-11-03 11:29:55 +08:00

557 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# STM8S003F3P6TR 蓝牙 Mesh 继电器固件设计
## 1. 适用范围
本设计对应当前电路图中的单路交流通断器,功能包括:
- 通过 JDY-28M 蓝牙模块接收 Mesh 控制指令;
- 控制 PA1 输出,驱动 SS8050 和继电器线圈;
- 通过 ACS712ELCTR-30A 连续采集负载电流;
- 继电器吸合后在规定时间内无电流,生成“吸合无电流”故障;
- 继电器断开后仍有电流,生成“断开有电流”故障;
- 通过蓝牙返回状态、实时电流和故障码。
## 2. 引脚连接确认
根据原理图重新核对后,ACS712 的 VIOUT 经 R3/R4/C2 滤波后连接到 STM8 的 `PC4`,用于电流 ADC 采样;`PC3_JDY-28M-STAT` 是 JDY-28M 的 STAT 状态信号,两者不是同一网络。因此,之前关于“ACS712 模拟输出与 JDY-28M 状态输出共用 PC3”的判断已撤销。
程序中应按以下方式配置:
- `PC4`:模拟输入,连接 ACS712 电流检测滤波输出;禁止配置为推挽数字输出;
- `PC3`:数字输入,用于读取 JDY-28M 状态;不要把它当作 ACS712 ADC 通道;
- PC3 的有效电平已经由 JDY-28M 手册明确:MESH 模式下高电平表示入网成功,低电平表示尚未入网。
## 3. 推荐软件接口
| 功能 | 原理图网络 | 固件用途 |
|---|---|---|
| 继电器驱动 | `PA1_relay` | 高电平吸合,低电平断开 |
| 电流模拟量 | `PC4` | ADC 输入,连接 ACS712 滤波输出 |
| 蓝牙状态 | `PC3_JDY-28M-STAT` | 数字输入,读取 JDY-28M 状态 |
| 蓝牙接收 | `PD5_JDY-28M-RXD` | MCU UART TX,发送给 JDY-28M RXD |
| 蓝牙发送 | `PD6_JDY-28M-TXD` | MCU UART RX,接收 JDY-28M TXD |
| 调试下载 | `SWIM/NRST` | 仅用于 SWIM 调试和下载 |
| 本地按键 | `SW1` | 短按切换,长按恢复出厂设置 |
STM8S003F3 的 ADC 是 10 位,输入范围为 0 至 VDDA;UART1 可用于蓝牙串口通信。根据 ST 官方 STM8S003F3 数据手册 DS7147 Rev 10 的表 6,TSSOP20/UFQFPN20 封装的 PC4 标注为 `AIN2`,因此程序选择 ADC1 通道 2;PC4 仍必须配置为模拟输入,不能作为数字推挽输出。
## 4. JDY-28M Mesh 使用方式
根据 JDY-28M V1.4 手册,本项目采用 `AT+ROLE2` 的 MESH 指令通信模式。该模式支持目标地址和 CMD 指令,通信数据带有模块定义的数据头,适合本项目的设备寻址、命令确认和故障上报。
JDY-28M 仍然只负责 Mesh 组网和无线转发,STM8 负责继电器、电流采样、故障判定和最终执行。不能让 JDY-28M 直接通过 OUT 引脚控制继电器,否则会绕过 STM8 的 ACS712 电流确认逻辑。
### 4.1 上电自动确认 Mesh 指令模式
STM8 上电后必须先保持继电器断开,再初始化 JDY-28M。启动流程如下:
```text
上电
↓
继电器强制断开,启动 UART 接收环形缓冲区
↓
进入模块串口指令窗口,发送 AT+ROLE
↓
收到 +ROLE=2? ── 是 ──→ 发送 AT+MADDR 查询短地址
│
否
↓
发送 AT+ROLE2
↓
等待 +OK,发送 AT+RESET
↓
等待模块重新启动,再次发送 AT+ROLE 验证
↓
收到 +MADDR=<短地址>
↓
校验短地址并保存到运行期 RAM
↓
Mesh 初始化完成,允许继电器业务运行
```
程序要求:
- `AT+ROLE` 返回值必须严格等于 `2`,不能只根据 `+OK` 判断成功;
- 发送 `AT+ROLE2` 后应等待模块返回 `+OK`,再发送 `AT+RESET`,不要连续发送多条命令;
- 模块复位期间继电器必须保持断开,UART 接收缓存应清空,避免把启动回显当作业务帧;
- 复位后要重新查询并验证 `AT+ROLE`,不能假定设置命令已经持久化成功;
- 只有成功收到并解析 `AT+MADDR` 返回的有效 2 字节短地址后,才允许把 Mesh 初始化标记为完成;短地址只保存在运行期 RAM 中,每次上电重新查询,不写入 EEPROM;
- 如果连续重试仍无法确认模式或短地址,进入 `BT_INIT_FAULT`,继电器保持断开,并通过 LED/故障状态报告蓝牙初始化故障;Mesh 尚未组网本身不属于初始化故障,不强制断开继电器;
- 短地址不写入 EEPROM,设备每次上电都从 JDY-28M 重新查询。
JDY-28M 手册说明,MESH 指令模式相关配置需要注意模块的指令/透传状态和 PWRC 管脚条件。当前硬件使用 `PA2_JDY-28M-PWRC`,RESET 使用 `PD2_JDY-28M-RESET`;如果模块未进入指令窗口,STM8 应先按手册要求控制 PWRC,再发送 `AT+ROLE`。
建议的初始化状态枚举如下:
```c
typedef enum
{
BT_INIT_START = 0, /* 初始化开始,继电器仍保持断开 */
BT_INIT_QUERY_ROLE, /* 查询 JDY-28M 当前工作模式 */
BT_INIT_SET_ROLE, /* 当前模式不是 ROLE2,发送 AT+ROLE2 */
BT_INIT_RESET_WAIT, /* 等待模块复位并重新启动 */
BT_INIT_QUERY_ADDRESS, /* 发送 AT+MADDR 查询 Mesh 短地址 */
BT_INIT_SAVE_ADDRESS, /* 校验地址并保存到运行期 RAM */
BT_INIT_READY, /* 蓝牙初始化成功,允许进入业务状态 */
BT_INIT_FAULT /* 初始化失败,继电器保持断开 */
} BluetoothInitState;
/*
* 蓝牙模块初始化任务。
* 该任务必须采用超时和重试机制,不能使用长时间阻塞延时,
* 否则会影响 ACS712 采样、看门狗服务和本地按键检测。
*/
void Bluetooth_InitTask(void)
{
/* 只有收到明确的 +ROLE=2 和有效 +MADDR 响应后才进入 READY。 */
}
```
短地址只保存在运行期 RAM 中。上电时必须重新执行 `AT+MADDR` 查询并校验,查询失败不能使用旧地址替代。
### 4.2 PB5 蓝牙状态指示
蓝牙状态/故障指示灯由 STM8 的 `PB5` 控制,低电平点亮;`PD3` 改作继电器状态指示灯,高电平点亮。`PC3_JDY-28M-STAT` 用于读取 JDY-28M 的 Mesh 状态。蓝牙初始化完成后,程序需要区分“模块初始化成功”和“已经完成组网”两个状态,不能仅凭 `AT+ROLE2` 成功就认为已经入网。
PB5蓝牙状态/故障灯显示规则如下:
| 条件 | PB5 状态 | 说明 |
|---|---|---|
| 蓝牙模块初始化故障 | 300 ms 亮、300 ms 灭 | 最高优先级,表示 ROLE/RESET/MADDR 初始化失败 |
| 初始化成功但尚未完成 Mesh 组网 | 1 s 亮、1 s 灭 | 表示模块正常,但当前没有完成组网 |
| 已完成 Mesh 组网 | 常亮 | 表示 PC3 已确认模块处于组网状态 |
建议使用 1 ms 系统节拍实现 LED 状态机,不在主循环中使用阻塞延时。LED 状态优先级固定为:
```text
BT_INIT_FAULT > BT_NOT_JOINED > BT_JOINED
```
JDY-28M 手册第 7 页对 STAT(第 6 脚)给出了明确规定:在 MESH 模式下,入网成功输出高电平,未入网输出低电平。因此原理图中的 `PC3_JDY-28M-STAT` 应按高有效处理:
```c
/* JDY-28M 手册明确规定:MESH 入网成功时 STAT 输出高电平。 */
#define JDY_MESH_JOINED_LEVEL 1
/*
* 更新 PB5 蓝牙状态/故障灯显示状态。
* - 初始化故障时以 300 ms 周期闪烁;
* - 初始化成功但 PC3 未确认组网时以 1 s 周期闪烁;
* - PC3 连续稳定确认已组网时保持常亮。
*/
void BluetoothLed_Update(uint8_t init_fault, uint8_t init_ready,
uint8_t mesh_status_level)
{
/* 具体 GPIO 翻转由 1 ms 定时任务执行,避免阻塞业务处理。 */
}
```
PC3 状态必须连续稳定确认至少 3 秒:连续 3 秒读取到高电平才切换为常亮;连续 3 秒读取到低电平才切换为 1 秒闪烁。模块的 ALED(第 17 脚)是 JDY-28M 自带的广播 LED 指示脚,不应与本项目由 STM8 PB5 控制的蓝牙状态灯混淆;PD3只用于继电器状态指示。
### 4.3 量产配置
每个设备在产测或配网阶段配置一次,之后发送 `AT+RESET`:
```text
AT+ROLE2
AT+BAUD4
AT+MADDR<设备两字节短地址>
AT+NETID<四字节组网ID>,<十六进制参数>
AT+MCLSSA0
AT+ZJEN1
AT+RESET
```
- `AT+BAUD4` 为 9600 baud,应与 STM8 UART 保持一致;
- `AT+MADDR` 设置 Mesh 短地址,设备之间不能重复;
- `AT+NETID` 设置网络 ID,同一网络必须一致,手册说明该参数设置后不能查询,因此必须保存生产记录;
- `AT+MCLSSA0` 选择 A0 类型,适合 MESH 透传/指令通信与低功耗 IO 类设备;
- `AT+ZJEN1` 开启 Mesh 中继能力,是否关闭应根据现场网络拓扑测试决定。
### 4.4 MESH 指令与 STM8 应用层
在 `AT+ROLE2` 下,JDY-28M 使用目标短地址和 Mesh CMD 进行通信。手册第 29 页给出了 UART 发送和接收的完整示例。本项目使用其中的 Mesh 数据通信方式,把 STM8 业务帧作为 Mesh 数据区发送;不把业务帧中的 `0x55 0xAA` 误认为 JDY-28M 的无线帧头。
STM8 仍然需要对 UART 业务数据进行二次校验,不能把收到的任何 UART 字节直接当作继电器命令。由于当前使用的是 `AT+ROLE2` MESH 指令通信模式,目标短地址属于 JDY-28M 的发送帧字段,接收帧中还会携带来源短地址,因此不应在 STM8 业务载荷中重复添加。
### 4.4.1 JDY-28M Mesh 外层帧
手册第 29 页的示例表明,JDY-28M 串口发送给模块的外层帧为:
```text
41 54 2B AA A1 | 目标短地址 2B | A0 | 业务数据 | 0D 0A
```
其中:
- `41 54 2B AA A1`:固定的 JDY-28M MESH 指令前缀,对应 ASCII/十六进制字符串 `41542BAAA1`;
- 目标短地址:2 字节,例如 `FFFF` 表示广播,`000C` 表示发送到短地址 `000C`;
- `A0`:手册示例中的 MESH 数据通信命令字节;
- 业务数据:本项目的 STM8 业务帧,例如 `55 AA CMD LEN DATA CRC16`;
- `0D 0A`:JDY-28M 指令结束符。
因此,主机或上位机发送给某个继电器节点的完整数据应类似:
```text
41 54 2B AA A1 00 0C A0 55 AA CMD LEN DATA CRC16 0D 0A
```
手册给出的设备接收帧格式为:
```text
F1 DD 09 00 0A | 源短地址 2B | 业务数据 | 0D 0A
```
例如源地址为 `000C`、业务数据为 `1122334455` 时,接收格式为:
```text
F1 DD 09 00 0A 00 0C 11 22 33 44 55 0D 0A
```
STM8 收到外层帧后,应先识别并剥离 `F1 DD 09 00 0A`、来源短地址和 `0D 0A`,再把中间的业务数据交给 `55 AA | CMD | LEN | DATA | CRC16` 解析器。手册第 29 页说明 MESH 数据长度支持最长 20 字节,因此本项目的业务帧总长度必须控制在该限制内。
因此,STM8 业务数据只保留以下应用层字段:
```text
帧头 0x55 0xAA | CMD | LEN | DATA | CRC16
```
字段定义:
- `0x55 0xAA`:STM8 业务帧同步头;
- `CMD`:需要执行或返回的命令;
- `LEN`:DATA 字段的字节数;
- `DATA`:命令参数或返回数据;
- `CRC16`:从 `CMD` 开始计算到 DATA 结束的 CRC16,不包含帧头。
CRC16 固定采用 CRC-16/MODBUS,参数必须由主机和 STM8 完全一致地实现:
- 多项式:标准表示为 `0x8005`,采用右移实现时使用 `0xA001`;
- 初始值:`0xFFFF`;
- 输入反转:是;
- 输出反转:是;
- CRC 字节顺序:低字节在前、高字节在后;
- 计算范围:从 `CMD` 开始,到 DATA 结束,不包含 `0x55 0xAA` 帧头;
- 不计算 JDY-28M 外层帧头、目标地址、`A0` 和 `0D 0A`。
固定测试向量:
```text
输入数据:01 01 01
CRC结果:0x4498
发送顺序:98 44
完整示例:55 AA 01 01 01 98 44
```
### 5.5 业务命令定义
| CMD | 名称 | 方向 | DATA 定义 |
|---|---|---|---|
| `0x01` | 继电器控制 | 主机→设备 | `0x00` 断开;`0x01` 吸合 |
| `0x02` | 查询继电器状态 | 主机→设备/设备→主机 | 返回 `0x00` 断开;`0x01` 吸合 |
| `0x03` | 读取电流数据 | 主机→设备/设备→主机 | 返回 2 字节实际电流值,单位 mA,低字节在前 |
| `0x04` | 故障上报 | 设备→主机 | `0x00` 吸合但无电流;`0x01` 断开但有异常电流;`0x02` 采样异常;`0x04/0x06` 对应恢复 |
| `0x05` | 设备短地址上报 | 设备→主机 | 返回 2 字节 Mesh 短地址 |
| `0x06` | 配置电流阈值 | 主机→设备 | 2 字节无符号阈值,单位 mA,低字节在前 |
### 5.5.1 应答命令分配建议
采用“请求命令 + `0x80` = 应答命令”的规则:
| 请求 CMD | 应答 CMD | 应答含义 | DATA |
|---|---|---|---|
| `0x01` | `0x81` | 继电器控制成功 | `0x00` 断开,`0x01` 吸合 |
| `0x02` | `0x82` | 继电器状态返回 | `0x00` 断开,`0x01` 吸合 |
| `0x03` | `0x83` | 电流数据返回 | 2 字节实际电流值,单位 mA,低字节在前 |
| `0x04` | - | 故障/恢复主动上报 | 故障码,设备主动发送 |
| `0x05` | `0x85` | 设备短地址返回 | 2 字节短地址,低字节在前 |
| `0x06` | `0x86` | 电流阈值配置成功 | 2 字节当前阈值,单位 mA,低字节在前 |
| `0x04` | `0x84` | 故障/恢复上报确认 | 1 字节,被确认的故障码 |
如果设备不能执行请求,使用统一错误应答 `CMD=0xE0`:
```text
DATA[0]:错误码
0x01 = 设备未初始化完成
0x02 = 参数长度错误
0x03 = 参数值非法
0x04 = 当前状态不允许执行
0x05 = ROM 写入失败
0x06 = 业务命令不支持
```
CRC 错误不发送 `0xE0`,直接丢弃,因为 CRC 错误时不能确认收到的命令内容。
广播请求同样需要应答。特别是广播 `CMD=0x05` 地址查询时,主机通过收集所有设备返回的 `0x85` 应答获得网络内的短地址列表。
为避免所有设备同时回复造成 Mesh 碰撞,广播地址查询应采用错峰应答:
```text
response_delay_ms = 20 + (mesh_short_address % 16) * 20
```
设备收到广播地址查询后,不立即发送,而是在计算出的时间槽发送 `CMD=0x85`,DATA 为本机 2 字节短地址。主机应在足够的收集窗口内接收多个应答,并按短地址去重。
广播控制指令也返回 `0x81` 控制应答;为避免多个设备同时回复,广播控制应答同样采用基于短地址的错峰发送。单播指令不需要错峰,可以在执行后立即应答。
建议固定返回格式:
```text
CMD=0x02, LEN=1, DATA=[RELAY_STATE]
CMD=0x03, LEN=2, DATA=[CURRENT_L, CURRENT_H]
CMD=0x05, LEN=2, DATA=[ADDR_L, ADDR_H]
```
`0x04` 故障上报建议定义为:
```text
DATA[0]:故障码,0x00=继电器已吸合但没有电流输出,0x01=继电器已断开但仍存在异常电流,0x02=ACS712采样异常,0x04=电流故障恢复,0x06=采样异常恢复。蓝牙初始化异常不通过 Mesh 上报,只通过 PB5 指示。
```
`CMD=0x03` 的电流数据是 STM8 根据 ACS712 采样值、零点偏置和校准系数计算出的实际电流,不是 ADC 原始值。数据类型为 16 位无符号整数,单位为 mA,低字节在前,并采用四舍五入:
```text
实际电流 1250 mA = 0x04E2
DATA = 0xE2 0x04
实际电流 500 mA = 0x01F4
DATA = 0xF4 0x01
```
该格式的最大表示值为 65535 mA,即 65.535 A,能够覆盖 ACS712ELCTR-30A 的量程。
例如,继电器吸合后检测不到电流时主动发送:
```text
55 AA 04 01 00 CRC16
```
其中 `CMD=0x04`,`LEN=0x01`,故障码为 `0x00`,表示继电器已吸合但没有电流输出。实际发送时应将末尾 `CRC16` 替换为计算结果。
JDY-28M 先按 MESH 外层帧完成目标地址处理和来源地址携带,STM8 再校验业务帧头、命令、长度和 CRC,然后执行命令。当前协议不设置业务层 SEQ;因此主机不应在未确认应答时盲目重发继电器控制帧,后续如需要可靠重发,应另行增加事务机制。
只有在未来存在“模块地址”和“业务逻辑地址”不一致的需求时,才在业务载荷中额外增加逻辑设备号;此时字段名称必须使用 `logical_device_id`,不能再命名为目标短地址或源短地址,以免与 JDY-28M 地址混淆。
## 5. 设备进入可执行状态后的指令划分
只有完成以下条件后,设备才将 `device_ready` 置为 1,开始处理业务指令:
1. JDY-28M 已确认 `AT+ROLE=2`;
2. 已成功查询并校验 Mesh 短地址;
3. 已读取并保存 Mesh 状态;组网状态由 PB5 蓝牙状态灯单独指示;PD3指示继电器状态;
4. STM8 已完成 ACS712 零点初始化;
5. 继电器输出已经处于安全的断开状态。
未进入 `device_ready` 前,只允许处理初始化相关命令,不能执行远程继电器控制。初始化完成后,即使 Mesh 尚未组网,也不强制断开继电器;如果收到本地或后续有效业务控制,仍可按正常逻辑执行。
### 5.1 指令一:询问设备短地址
主机发送“询问地址”业务指令后,STM8 不重新修改地址,只返回启动阶段通过 `AT+MADDR` 查询并保存的当前短地址。
```text
请求方式:主机发送地址查询请求
应答命令:0x05 ADDRESS_REPORT
应答数据:设备短地址 2 bytes
```
如果地址没有通过校验或蓝牙初始化尚未完成,应返回地址无效/设备未就绪错误,不能返回未校验的旧地址。
### 5.1.1 指令六:配置电流阈值
主机发送 `CMD=0x06`、`LEN=2`,DATA 为低字节在前的 16 位无符号阈值,单位为 mA。STM8 校验通过后将阈值写入 ROM;后续上电时读取该值,读取失败或数据无效时使用默认值 100 mA。
```text
CMD=0x06, LEN=2, DATA=[THRESHOLD_L, THRESHOLD_H]
```
阈值配置成功后,设备重新封装应答帧,使用专用的配置应答 CMD 并重新计算 CRC16,不能直接原样返回主机的 Mesh 外层帧。
### 5.2 指令二:控制继电器吸合或断开
```text
请求命令:0x01 RELAY_CONTROL
应答方式:返回当前继电器状态帧(CMD=0x02)
```
处理流程:
1. 校验 JDY-28M 外层地址、业务命令长度和 CRC;
2. 判断设备是否 `device_ready`;
3. 设置继电器软件目标状态;
4. 立即控制 `PA1_relay` 输出,使继电器吸合或断开;
5. 重新封装一帧应答数据,使用专用的控制应答 CMD,重新计算业务 CRC16,并通过新的 JDY-28M 外层地址和帧头发送;
7. 继续由 ACS712 采样和故障状态机进行后续确认。
控制应答不需要等待电流确认。返回成功表示继电器控制动作已经发出,不表示负载电流已经符合预期。由于目前没有触点反馈,不单独判断继电器机械控制失败;后续异常统一由 ACS712 电流检测故障上报。
收到新的控制指令时,应立即更新目标状态,并重新启动对应的电流确认窗口。
### 5.3 指令三:故障主动上报
故障不是主机查询后才返回,而是由 STM8 在电流确认窗口结束后主动通过 JDY-28M 上报:
```text
上报命令:0x04 FAULT_REPORT
故障码 DATA[0]=0x00:继电器吸合,但持续无有效电流
故障码 DATA[0]=0x01:继电器断开,但仍持续存在有效电流
故障码 DATA[0]=0x02:ACS712 采样异常
故障码 DATA[0]=0x04:电流故障恢复
故障码 DATA[0]=0x06:采样异常恢复
```
故障上报数据建议包含:
```text
设备短地址 | 故障码 | 继电器目标状态 | 当前电流值
```
上报规则:
- 吸合后持续检测至少 10 s,电流始终低于 `I_ON_THRESHOLD`,主动上报 `0x00`;
- 断开后持续检测至少 10 s,电流仍持续高于 `I_OFF_THRESHOLD`,主动上报 `0x01`;
- ACS712 采样异常上报 `0x02`;蓝牙初始化异常无法通过 Mesh 上报,只通过 PB5 指示;
- 后续连续检测恢复正常至少 10 s 时,清除对应故障并主动上报恢复码 `0x04` 或 `0x06`;蓝牙初始化故障无法通过 Mesh 上报,恢复后仅结束 PB5 故障闪烁;
- 故障或恢复上报发送后,等待主机返回 `CMD=0x84` 确认;
- 未收到确认时,每隔 10 s 重发一次相同的 `CMD=0x04` 上报帧;
- 收到 `CMD=0x84` 且 DATA 与当前待确认故障码一致后,停止该事件的周期重发;
- 重复收到的故障上报不得重复改变继电器状态,只需返回 `CMD=0x84`;
- 故障上报不能改变当前继电器输出,除非产品需求明确要求保护性断开;
- `0x04` 专用于设备主动故障/恢复上报,`0x84` 专用于主机确认。
### 5.4 指令处理优先级
```text
初始化故障保护
> 继电器控制指令
> 故障状态机
> 周期状态上报
```
如果设备处于蓝牙初始化故障,继电器必须保持断开;如果设备已经进入业务运行状态,继电器控制应答和故障主动上报分别走同步、异步两条路径。
## 6. 状态模型
继电器控制状态不应直接等同于“负载已经工作”。建议保存以下状态:
```c
typedef enum
{
RELAY_OFF = 0, /* 软件要求继电器断开 */
RELAY_ON = 1 /* 软件要求继电器吸合 */
} RelayCommandState;
typedef enum
{
FAULT_NONE = 0x00, /* 无故障 */
FAULT_ON_NO_CURRENT = 0x01, /* 要求吸合,但确认窗口内无电流 */
FAULT_OFF_HAS_CURRENT = 0x02,/* 要求断开,但确认窗口内仍有电流 */
FAULT_CURRENT_SENSOR = 0x03 /* 采样异常或零点未校准 */
} FaultCode;
```
建议故障状态采用“锁存 + 明确清除”:故障发生后继续上报,只有收到清除故障指令、重新执行一次有效控制,或设备重启并完成自检后才清除。是否允许自动清除,应由产品需求决定。
## 7. ACS712 采样算法
ACS712 输出是以约 VCC/2 为零电流中心的模拟电压,30 A 型号的典型灵敏度约为 66 mV/A。不要用单次 ADC 值判断有无电流,应采用连续采样计算 RMS。
推荐参数:
- ADC 采样频率:1 kHz 至 2 kHz;
- RMS 窗口:至少 20 ms,推荐 100 ms;
- 每个窗口先计算平均值作为零点/偏置;
- 对每个采样值计算相对零点的平方和;
- 使用整数或定点运算,避免 STM8 上使用浮点造成代码过大和执行时间不可控;
- 上电后继电器保持断开,采集 200 ms 至 500 ms 的零点偏置;
- 零点偏置只能在确认负载无电流时更新,不能在继电器吸合状态下随意跟踪。
计算关系为:
```text
I_rms = sqrt(sum((ADC_i - ADC_zero)^2) / N) * Vref / (1023 * 0.066)
```
实际项目中应使用已知标准电流进行两点或多点校准,得到 `CURRENT_SCALE` 和 `CURRENT_OFFSET`,不要直接把典型灵敏度当成最终精度。
## 8. 故障判定时序
### 6.1 吸合无电流
1. 收到 ON 指令;
2. 设置软件目标状态为 ON;
3. PA1 输出吸合电平;
4. 等待继电器机械动作时间,例如 100 ms;
5. 持续检测电流,确认窗口至少 10 s;
6. 若窗口内连续满足 `I_rms >= I_ON_THRESHOLD`,判定吸合成功;
7. 窗口结束仍无有效电流,生成 `FAULT_ON_NO_CURRENT`。
`I_ON_THRESHOLD` 支持动态配置,默认值为 100 mA;实际产品可根据最小负载电流、ACS712 噪声和现场校准结果调整。
### 6.2 断开仍有电流
1. 收到 OFF 指令;
2. 设置软件目标状态为 OFF;
3. PA1 输出断开电平;
4. 等待触点释放时间,例如 100 ms;
5. 持续检测电流,确认窗口至少 10 s;
6. 若窗口内电流持续低于阈值,判定断开正常;
7. 若连续多个采样窗口仍满足 `I_rms >= I_OFF_THRESHOLD`,生成 `FAULT_OFF_HAS_CURRENT`。
`I_OFF_THRESHOLD` 应高于零点噪声。吸合和断开的电流阈值支持动态配置,默认值均为 100 mA。电流必须持续满足故障条件至少 10 s 才上报,不能根据单次采样或瞬时浪涌报错。
## 9. 推荐主循环结构
```c
void App_MainLoop(void)
{
/* 读取 UART 环形缓冲区,将完整帧交给协议解析器。 */
Bluetooth_ProcessRxFrames();
/* 由 1 ms 定时节拍触发电流采样,不在主循环中使用阻塞延时。 */
CurrentSampler_ProcessPendingSamples();
/* 每完成一个 RMS 窗口,就更新当前电流和采样质量。 */
CurrentMonitor_ProcessCompletedWindow();
/* 根据继电器目标状态、延时和电流结果推进故障状态机。 */
RelayFaultMonitor_Run();
/* 周期性发送状态,不应阻塞继电器控制和 ADC 采样。 */
Bluetooth_ReportPeriodicStatusIfDue();
/* 防止程序跑飞;喂狗动作应放在确认主循环各任务正常执行之后。 */
IWDG_ServiceIfSystemHealthy();
}
```
## 10. 建议蓝牙协议
正式量产使用前文定义的二进制帧:
```text
0x55 0xAA | CMD | LEN | DATA | CRC16
```
Mesh 目标地址和源地址由 JDY-28M 的 MESH 指令帧承担,不放入 STM8 业务载荷。
## 11. 关键异常处理
- 蓝牙帧 CRC 错误:丢弃并返回通信错误,不改变继电器状态;
- LEN 超出协议允许范围:丢弃整帧,不执行继电器动作;
- 上电:继电器默认断开,先完成 ADC 零点采集和自检;初始化完成后,Mesh 未组网不再强制改变继电器状态;
- ACS712 输出超出 0 至 VDDA:记录传感器故障,禁止根据异常值自动闭合;
- 采样窗口不足:不更新电流值,不进行故障判定;
- MCU 看门狗复位:重启后保持继电器断开,并上报复位原因;
- 故障状态下:可以继续发送实时电流,但不应静默覆盖原故障码。
## 12. 推荐实现顺序
1. 复核 PC4 的 ADC 通道编号、PC3 的蓝牙状态有效电平以及 PCB 走线;
2. 单独验证 PA1-继电器吸合/断开极性;
3. 在继电器断开状态下验证 ACS712 零点和噪声;
4. 用已知负载校准电流换算;
5. 验证蓝牙 UART 收发和 Mesh 重发/去重;
6. 最后启用两类故障判定,并分别测试“空载吸合”和“触点粘连/外部旁路带电”场景。
该文档是固件设计和测试基线,不代表已经完成编译、下载、PCB 实测或市电安全认证。