feat: add STM8 mesh relay firmware

This commit is contained in:
十七
2026-11-02 20:30:08 +08:00
commit d275a3523b
27 changed files with 2985 additions and 0 deletions
+556
View File
@@ -0,0 +1,556 @@
# 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 管脚条件。实际硬件上应确认 `PC5_JDY-28M-PWRC` 的上电电平;如果模块未进入指令窗口,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 LED3 蓝牙状态指示
LED3 由 STM8 的 `PD3` 控制,`PC3_JDY-28M-STAT` 用于读取 JDY-28M 的 Mesh 状态。蓝牙初始化完成后,程序需要区分“模块初始化成功”和“已经完成组网”两个状态,不能仅凭 `AT+ROLE2` 成功就认为已经入网。
LED3 显示规则如下:
| 条件 | LED3 状态 | 说明 |
|---|---|---|
| 蓝牙模块初始化故障 | 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
/*
* 更新 LED3 显示状态。
* - 初始化故障时以 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 PD3 控制的 LED3 混淆。
### 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 上报,只通过 LED3 指示。
```
`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 状态;组网状态由 LED3 单独指示;
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 上报,只通过 LED3 指示;
- 后续连续检测恢复正常至少 10 s 时,清除对应故障并主动上报恢复码 `0x04` 或 `0x06`;蓝牙初始化故障无法通过 Mesh 上报,恢复后仅结束 LED3 故障闪烁;
- 故障或恢复上报发送后,等待主机返回 `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 实测或市电安全认证。