217 lines
6.7 KiB
Markdown
217 lines
6.7 KiB
Markdown
# Poweroff Protection
|
||
|
||
基于 STM32 + Linux 的安全断电保护系统。当主电源断开时,STM32 通知 Linux 主机执行关机,等待关机完成后再切断继电器电源,避免数据损坏。
|
||
|
||
## 系统架构
|
||
|
||
```
|
||
主 12V 电源 ──┬──> [Main12V_In] STM32F103C8 [Relay_out] ──> 继电器 ──> Linux 主机电源
|
||
│ │
|
||
│ UART / USB CDC
|
||
│ │
|
||
└──────────────── Linux 主机 (poweroff_linux)
|
||
```
|
||
|
||
## 通信协议
|
||
|
||
| 方向 | 指令 | 说明 |
|
||
|------|------|------|
|
||
| Linux → STM32 | `start` | 启动监控循环 |
|
||
| STM32 → Linux | `Alive` | 心跳请求 |
|
||
| Linux → STM32 | `blive` | 心跳应答 |
|
||
| STM32 → Linux | `SHUTDOWN` | 通知主机立即关机 |
|
||
| Linux → STM32 | `ok` | 关机完成确认 |
|
||
|
||
## 工作流程
|
||
|
||
1. Linux 端连接串口,发送 `start`
|
||
2. STM32 进入监控循环,持续发送 `Alive` 并等待 `blive` 应答(5 秒超时)
|
||
3. 当检测到主 12V 电源断开(连续 10 次读取为高)或心跳超时,STM32 发送 `SHUTDOWN`
|
||
4. 等待 Linux 回复 `ok`(最长 60 秒)
|
||
5. 收到 `ok` 后延迟 10 秒,拉高继电器引脚切断主机电源
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
poweroff/
|
||
├── poweroff_stm32/ # STM32 固件 (Keil MDK 工程)
|
||
│ ├── Core/ # 用户代码 (main.c, gpio.c, usart.c)
|
||
│ ├── Drivers/ # HAL 驱动 + CMSIS
|
||
│ ├── Middlewares/ # USB CDC 中间件
|
||
│ ├── USB_DEVICE/ # USB 设备配置
|
||
│ └── MDK-ARM/ # Keil 工程文件
|
||
│
|
||
└── poweroff_linux/ # Linux 端 Go 程序
|
||
├── shutdown.go # 主程序
|
||
├── shutdown # 预编译二进制
|
||
├── config.json # 配置文件
|
||
├── install.sh # 安装脚本
|
||
├── uninstall.sh # 卸载脚本
|
||
├── change_port.sh # 更换串口脚本
|
||
├── send_signal.sh # 关机信号钩子
|
||
├── ttyshutdown.service
|
||
├── go.mod
|
||
└── go.sum
|
||
```
|
||
|
||
## 硬件引脚 (STM32F103C8)
|
||
|
||
| 引脚 | 端口 | 功能 |
|
||
|------|------|------|
|
||
| SHUT | PB4 | 关机指示(低电平有效) |
|
||
| RUN | PB5 | 运行指示灯 |
|
||
| Relay_out | PB6 | 继电器控制(高电平切断电源) |
|
||
| Main12V_In | PB7 | 主 12V 电源检测 |
|
||
| USART1_TX | PA9 | 串口发送 |
|
||
| USART1_RX | PA10 | 串口接收 |
|
||
| USB | PA11/PA12 | USB CDC 通信 |
|
||
|
||
## 安装
|
||
|
||
### 硬件准备
|
||
|
||
- STM32F103C8 最小系统板(Blue Pill)
|
||
- 继电器模块(低电平触发),用于控制 Linux 主机电源
|
||
- USB 转 TTL 串口模块(如 CH340/CP2102)或 USB 数据线
|
||
- J-Link / ST-Link 下载器
|
||
- 12V 主电源
|
||
|
||
### 接线
|
||
|
||
```
|
||
STM32 外设
|
||
───── ────
|
||
PB6 (Relay_out) ──> 继电器信号端
|
||
PB7 (Main12V_In)──> 主 12V 电源检测(需分压至 3.3V)
|
||
PB5 (RUN) ──> LED 指示灯
|
||
PB4 (SHUT) ──> 关机状态指示灯
|
||
|
||
PA9 (USART1_TX) ──> 串口模块 RX
|
||
PA10 (USART1_RX) ──> 串口模块 TX
|
||
|
||
USB (PA11/PA12) ──> Linux 主机 USB 口(使用 USB CDC 时)
|
||
```
|
||
|
||
> **注意**:12V 电源检测引脚需通过电阻分压将电压降至 3.3V 以下,避免损坏 STM32。推荐使用 10k + 3.3k 电阻分压。
|
||
|
||
### STM32 固件编译与烧录
|
||
|
||
#### 前置要求
|
||
|
||
- [Keil MDK-ARM](https://www.keil.com/download/product/) v5.38+
|
||
- STM32F1xx DFP (Device Family Pack),通过 Pack Installer 安装
|
||
- J-Link 驱动或 ST-Link 驱动
|
||
|
||
#### 编译
|
||
|
||
1. 打开 Keil,选择 `Project → Open Project`
|
||
2. 加载 `poweroff_stm32/MDK-ARM/poweroff_protection.uvprojx`
|
||
3. 点击 `Build (F7)` 编译
|
||
|
||
#### 烧录
|
||
|
||
1. 连接 J-Link / ST-Link 到 STM32 的 SWDIO、SWCLK、GND
|
||
2. 在 Keil 中选择 `Flash → Download (F8)` 烧录
|
||
3. 也可以使用 `poweroff_stm32/MDK-ARM/poweroff_protection/poweroff_protection.hex` 配合 ST-Link Utility 独立烧录
|
||
|
||
### Linux 端安装
|
||
|
||
#### 前置要求
|
||
|
||
- Linux 主机(需要 `shutdown` 命令权限)
|
||
- 串口设备已接入(USB 转串口模块或 USB CDC)
|
||
- `shutdown` 预编译二进制文件已放在 `poweroff_linux/` 目录下
|
||
|
||
#### 编译(可选)
|
||
|
||
如需从源码编译:
|
||
|
||
```bash
|
||
cd poweroff_linux
|
||
go build -o shutdown .
|
||
```
|
||
|
||
#### install.sh — 一键安装
|
||
|
||
安装脚本会交互式引导你完成配置,自动部署为 systemd 服务。
|
||
|
||
```bash
|
||
cd poweroff_linux
|
||
sudo bash install.sh
|
||
```
|
||
|
||
运行后脚本会:
|
||
|
||
1. **扫描串口** — 自动检测已接入的串口设备(ttyUSB / ttyACM / ttyS),以列表形式供你选择,也可手动输入路径
|
||
2. **配置参数** — 按提示设置波特率(默认 115200)和关机指令(默认 `SHUTDOWN`),回车保持默认
|
||
3. **确认安装** — 显示完整配置,确认后执行安装
|
||
4. **自动部署** — 将二进制和配置文件安装到 `/opt/ttyshutdown/`,生成 systemd 服务,安装关机钩子,启用并启动服务
|
||
|
||
安装完成后:
|
||
|
||
```bash
|
||
# 查看服务状态
|
||
systemctl status ttyshutdown
|
||
|
||
# 查看实时日志
|
||
journalctl -u ttyshutdown -f
|
||
```
|
||
|
||
#### uninstall.sh — 卸载
|
||
|
||
```bash
|
||
cd poweroff_linux
|
||
sudo bash uninstall.sh
|
||
```
|
||
|
||
卸载脚本会依次执行:
|
||
|
||
1. 停止并禁用 `ttyshutdown` 服务
|
||
2. 删除 systemd 服务文件 `/etc/systemd/system/ttyshutdown.service`
|
||
3. 删除关机钩子 `/usr/lib/systemd/system-shutdown/send_signal.sh`
|
||
4. 删除安装目录 `/opt/ttyshutdown/`
|
||
|
||
执行前会要求确认(输入 `y`)。
|
||
|
||
#### change_port.sh — 更换串口
|
||
|
||
当串口设备变化(如更换 USB 口、换用不同串口模块)时使用:
|
||
|
||
```bash
|
||
cd poweroff_linux
|
||
sudo bash change_port.sh
|
||
```
|
||
|
||
运行后脚本会:
|
||
|
||
1. **显示当前配置** — 读取 `/opt/ttyshutdown/config.json`,展示当前串口、波特率、关机指令
|
||
2. **扫描新串口** — 列出可用设备,当前使用的串口会标记 `<-- 当前`
|
||
3. **修改参数** — 选择新串口后,可一并修改波特率和关机指令(回车保持原值)
|
||
4. **确认更改** — 显示变更对比(如 `串口设备: /dev/ttyUSB0 -> /dev/ttyACM0`)
|
||
5. **生效** — 自动更新 `config.json` 和关机钩子 `send_signal.sh`,并重启服务
|
||
|
||
#### 常用命令
|
||
|
||
```bash
|
||
# 查看服务状态
|
||
systemctl status ttyshutdown
|
||
|
||
# 查看实时日志
|
||
journalctl -u ttyshutdown -f
|
||
|
||
# 手动重启服务
|
||
sudo systemctl restart ttyshutdown
|
||
|
||
# 手动停止服务
|
||
sudo systemctl stop ttyshutdown
|
||
```
|
||
|
||
## 通信说明
|
||
|
||
STM32 支持 UART 和 USB CDC 双通道,收到 `start` 指令时自动切换到对应通道:
|
||
|
||
- 通过串口模块发送 `start` → 使用 UART 通道
|
||
- 通过 USB CDC 发送 `start` → 使用 USB CDC 通道
|
||
|
||
程序会自动重连串口,每秒发送 `blive` 心跳,收到 `SHUTDOWN` 指令后执行 `shutdown -h now`。
|