shuichan_old/V1.1/STM32F103_App1/README.md

239 lines
11 KiB
Markdown
Raw 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.

# 智能水产投料机 V1.0.3
## 工程概述
本工程基于 **STM32F103RCT6** + **STM32Cube HAL** + **Keil MDK**,实现设备的控制、联网与投喂。
- **BootLoader**`STM32F103_BootLoader/`,负责 OTA 固件烧录、试运行计数与失败回滚
- **应用固件**`STM32F103_App1/`,当前运行版本 V1.0.3
## 产品型号配置
同一套板子适配两种产品,编译前在 `Inc/main.h` 顶部通过一个宏二选一:
```c
#define PRODUCT_WITH_FEED_SCALE 0
```
| 取值 | 产品 | 投喂行为 |
| --- | --- | --- |
| `1` | 智能水产投料机(接 RS485 磅秤) | `feeding``onceWt` 定量自动投喂,带重量反增/超时保护;`sw1` 指令被忽略 |
| `0` | 基础四路继电器(不接磅秤) | `feeding` / `sw1` 直接开关投喂继电器 1由平台侧自行计时 |
## 硬件接口
| 接口 | 用途 | 引脚 | 参数 |
| --- | --- | --- | --- |
| USART1 | 蓝牙串口调试 / 日志输出 | PA9/PA10 | 115200-8N1 |
| USART2 | RS485 喂料秤 | PA2/PA3 | 9600-8N1 |
| USART3 | 4G Air780E MQTT | PB10/PB11 | 921600-8N1见下文波特率自适应 |
| Relay1 | 投喂电机控制 | PB7 | 高电平吸合 |
| Relay2~4 | 备用控制 | PB8/PC0/PC2 | 高电平吸合 |
| I2C软件 | AT24C02 配置存储 | PA11/PA12 | 页写入 |
| SPI软件 | W25Q64 外部 Flash | PB3/PB4/PA15/PB5 | OTA 固件暂存 |
| ADC1 | 电池电压检测 | PA0 | 低电量上报 `pow:0` |
| PA8 | 手动模式检测 | PA8 | 高电平=手动模式 |
| PC13 | LED2 心跳 / TPL5010 喂狗 | PC13 | 每 1s 翻转(见下文看门狗) |
## 看门狗(双狗架构)
| 看门狗 | 超时 | 喂狗点 | 作用 |
| --- | --- | --- | --- |
| IWDG片内独立看门狗 | ~26sLSI 漂移下最短 ~17s | APP 主循环、`app_bg_service()`(所有 AT/OTA 等待每 20ms 让出一次BL 的擦除/拷贝循环 | 固件卡死 → 复位BL 启动OTA 试运行期计一次试错 |
| TPL5010外置硬件狗 | 7 分钟 | PC13(LED2) 电平翻转APP `activeEvents()` 每秒翻转BL 进入时及长循环中翻转 | MCU 完全失控(含 IWDG 失效)时的最后兜底 |
注意LED2 同时承担运行指示和外部狗喂狗,**修改 LED2 闪烁逻辑时必须保持周期性翻转**,否则 7 分钟后整板复位。
## 4G 波特率自适应115200 → 921600
- Air780E 出厂/自适应模式只覆盖 9600~115200921600 必须用 `AT+IPR` 固定。
- APP 联网时**永远先按 115200 探测**(避免向自适应侦测窗口发送其他波特率的乱码):
- 通 → 发 `AT+IPR=921600` + `AT&W` 固化,切换到 921600日志出现 `baud -> 921600`
- 不通(模块已固化 921600→ 直接切 921600 连接。
- 切换由 `USART3_SetBaudRate()` 运行中重写 BRR 完成,不影响 GPIO/DMA/NVIC。
## OTA 升级
### 流程
```text
平台下发 iot.ota.upgrade.post(url, crc16, ver)
→ APP: 模块硬复位 → HTTP HEAD 拿大小 → 擦 W25Q64 槽 B
→ 3072 字节/块分段下载AT+HTTPPARA BREAK/BREAKEND + HTTPACTION + HTTPREAD
→ 每块写 W25Q64 并回读校验,全程累计 CRC16
→ 整包 CRC + 栈顶/复位向量校验 → 可靠上报 result.post等 OK + 重试)
→ 写 OTA 信息区(状态 DOWNLOADED) → 复位进 BootLoader
BootLoader:
→ 擦除备份槽 → 备份当前 APP1 到槽 A失败则中止更新留在旧版本
→ 擦 APP1 → 写入新固件 → CRC + 向量校验 → 状态 INSTALLED → 跳转
新 APP 试运行:
→ MQTT 就绪 + 首次发布成功 + 3s → 上报 confirm.post
→ 确认标志写 W25Q64回读验证 + 3 次重试)→ 版本号存 EEPROM
→ 下次启动 BL 清理 OTA 标志,升级完成
```
### Flash 分区
内部 Flash256KB
| 区域 | 地址 | 大小 |
| --- | --- | --- |
| BootLoader | `0x08000000` | 32KB |
| APP1 运行区 | `0x08008000` | 224KB |
W25Q64 外部 Flash8MB
| 区域 | 地址 | 用途 |
| --- | --- | --- |
| 槽 A | `0x000000` (256KB) | 当前固件备份(回滚镜像) |
| 槽 B | `0x040000` (256KB) | 新固件下载暂存 |
| 信息区 A/B | `0x080000` / `0x081000` (各 4KB) | OTA 状态双副本magic + 序号 + checksum |
### 健康检查与回退
新固件"健康" = 4G 附着 → MQTT 连接 → 首次发布成功。回退判据(**3 次真实故障**才回退):
- **看门狗复位**IWDG/WWDG固件真的卡死→ BL 计一次试错(读 `RCC->CSR` 判别);
- **健康超时**MQTT 就绪 1 分钟仍无首次发布)→ APP 复位前自行计一次;
- **上电/按键/普通软件复位不计次**——现场断电、断网不会误触发回退;
- 试运行期间完全断网 → 不计次、不回退,持续等待网络恢复。
### 掉电/断网安全性
| 故障点 | 结果 |
| --- | --- |
| 下载中断网/掉电 | 信息区未更新,旧固件照常运行,平台可重推 |
| BL 备份阶段掉电 | `backup_valid=0`,重启后重新备份 |
| BL 擦写 APP1 中途掉电 | 状态 `COPYING` 视为 `DOWNLOADED`,重启后完整重做(备份不会被坏镜像覆盖) |
| 备份创建失败 | **中止更新**,留在旧版本,下次重启重试 |
| 回退过程掉电 | 重启后重新执行回退拷贝 |
### 其他要点
- OTA 触发时先强制停止投喂(断开继电器 1
- 下载期间蓝牙命令、秤轮询、LED 心跳、电量检测照常运行(`bg_delay` 切片让出),业务状态上报暂时屏蔽
- 分段接收按 `+HTTPREAD: <len>` 声明长度收齐即处理无静默等待40KB 固件全程约 38 秒(含模块复位重连 ~15s
## 主要功能
1. **MQTT 联网**Air780E 4G 模块,通过 MQTT 连接云平台
2. **远程控制**:平台下发开关 `sw1/sw2/sw3/sw4`、`feeding` 指令(投料机模式下 `sw1` 被忽略,投喂只能走 `feeding`
3. **自动投喂**`PRODUCT_WITH_FEED_SCALE = 1`
- 平台设置单次投喂量 `onceWt`
- 平台下发 `feeding=true` 启动投喂
- 继电器 1 吸合RS485 秤实时读取重量
- 当重量减少 ≥ `onceWt` 时自动停止,带重量反增与 10 分钟超时保护
4. **去皮/标定**:平台设置 `zero` 空载重量,设置后按最新原始重量重新计算剩余料重并立即上报
5. **OTA 升级**:见上文专题
6. **蓝牙调试**USART1 支持 `RESET/INFO/STATUS/R1ON~R4OFF/ALLON/ALLOFF/OTA/RECOVERY/HELP` 等命令
7. **掉电安全**:继电器 2~4 联网后从 EEPROM 恢复上次状态;继电器 1 上电强制断开,防止误投料
## 平台数据字段
| 字段 | 含义 | 说明 |
| --- | --- | --- |
| `ver` | 固件版本号 | 每次状态上报携带,平台可据此识别设备是否发生回退 |
| `weight` | 空载重量 | 平台显示为去皮重量 `zero` |
| `zero` | 剩余料重 | 平台显示为当前剩余料重 |
| `onceWt` | 单次投喂量 | 每次投喂目标重量 |
| `feeding` / `sw1` | 第一路继电器状态 | 1=投喂中0=停止,两个标识符等效 |
| `sw2~sw4` | 备用继电器状态 | 0/1 |
| `pow` | 电量状态 | 1=正常0=低电量 |
下行报文由 `m_app/proto.c` 按键名定位解析(`"sw2"` 不会误中 `"sw21"`,其他字段里的 true/false 不会造成误判)。
## 串口调试命令
通过 USART1蓝牙串口发送
```text
RESET - 系统复位
INFO - 打印 MQTT 配置
STATUS - 打印继电器状态
R1ON - 打开继电器 1
R1OFF - 关闭继电器 1
R2ON/R2OFF ~ R4ON/R4OFF - 控制继电器 2~4
ALLON - 打开所有继电器
ALLOFF - 关闭所有继电器
OTA - 复位进入 BootLoader 检查升级
RECOVERY - 复位进入 BootLoader
HELP - 显示支持命令
```
## 代码分层APP
`main.c` 只保留三行初始化和主循环,逻辑全部下沉到模块:
```c
int main(void)
{
SCB->VTOR = FLASH_BASE | Application_1_Addr;
Board_Init(); // 基础硬件HAL/时钟/GPIO/DMA/UART/看门狗SYSINIT/system.c
app_init(); // 业务模块初始化SYSINIT/app_loop.c
app_loop_init();
while (1) {
IWDG_Feed();
app_loop_process(); // 业务调度SYSINIT/app_loop.c
}
}
```
## 目录结构
```text
STM32F103_App1/
├── Src/
│ └── main.c # 仅 VTOR + Board_Init/app_init/主循环
├── Inc/
│ └── main.h # 产品型号宏 PRODUCT_WITH_FEED_SCALE、MQTT 默认配置
├── m_app/
│ ├── proto.c/h # 平台 JSON 报文取值工具(按键名定位)
│ └── ota_app.h # Flash 分区定义BootLoader 32K + APP1 224K
├── HardWare/
│ ├── USER_CMD/ # 蓝牙串口命令处理
│ ├── FEED_SCALE/ # RS485 喂料秤与定量投喂状态机
│ ├── RELAY/ # 继电器控制、反馈检测、平台指令执行
│ ├── NETWORK/ # 网络抽象层:状态上报/响应/发送互斥
│ ├── CAR/ # Air780E AT 驱动、波特率自适应、OTA 下载
│ ├── UART/ # USART1/2/3 初始化、运行中切波特率、中断/DMA 接收
│ ├── 24C02/ # EEPROM 读写(页写入)
│ ├── IIC/ # 软件 I2C
│ ├── ADC/ # 电池电压检测
│ ├── LED/ # 指示灯LED2 兼任 TPL5010 喂狗)
│ ├── LOG/ # 分级日志USART1 输出)
│ ├── SYSINIT/ # Board_Init/IWDG、app_init、主循环调度、后台任务切片
│ └── W25Q64/ # 外部 Flash 驱动与 OTA 双槽信息区
└── MDK-ARM/ # Keil 工程文件
STM32F103_BootLoader/
├── Src/main.c # 硬件初始化 + IWDG + 入口
├── m_app/ota_boot.c # OTA 状态机:备份/烧录/试运行计数/回退/跳转
├── HardWare/W25Q64/ # 外部 Flash 驱动(与 APP 共用设计)
├── HardWare/LOG/ # 分级日志(与 APP 相同)
└── MDK-ARM/ # Keil 工程文件
```
## 编译烧录
**Keil GUI**
1. 打开 `MDK-ARM/STM32F103rb_App1.uvprojx`BootLoader 工程同理)
2. 按产品形态设置 `Inc/main.h` 中的 `PRODUCT_WITH_FEED_SCALE`
3. 编译下载(先烧 BootLoader 到 `0x08000000`APP1 起始地址 `0x08008000`
4. 首次启动会自动把默认 MQTT 配置写入 AT24C02
**命令行**CI/脚本可用):
```bash
# 编译Keil 安装目录的 UV4-r 全量 -b 增量,-o 输出日志)
/c/Keil_v5/UV4/UV4.exe -r -j0 STM32F103rb_App1.uvprojx -o build.txt
# 烧录J-Link 命令脚本,工程 MDK-ARM 目录下有现成的 jlink_flash.jlink
JLink.exe -CommanderScript jlink_flash.jlink
```
## 版本
- Version: 1.0.3
- Author: Helei