# Poweroff Protection 基于 STM32 + Linux 的安全断电保护系统。当主电源断开时,STM32 通知 Linux 主机执行关机,等待关机完成后再切断继电器电源,避免数据损坏。 目前5块板子,仅id:0的板子可以正常使用USB与RS232口进行通信,其余板子由于硬件问题目前仅支持USB进行通信。 ## 系统架构 ``` 主 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`。