Files
bishe-STM32/docs/01_STM32固件端文档.md
T
2026-05-01 23:03:42 +08:00

10 KiB

STM32 固件端文档

1. STM32 在系统中做什么

STM32 是整套考勤机的主控。它不做人脸识别,人脸识别由 K210 完成。STM32 负责把 K210 的识别结果变成“是否允许签到”的业务判断,并控制硬件反馈。

它主要做这些事:

  1. 初始化 OLED、蜂鸣器、LED、串口、RTC、光敏传感器、补光灯等硬件。
  2. 接收 K210 通过 USART3 发来的识别结果。
  3. 判断识别置信度是否足够。
  4. 判断当前时间是否在服务端配置的签到时间段内。
  5. 判断当前学生在本时间段是否已经签过。
  6. 生成签到记录。
  7. 使用 AES-128-CBC 加密签到 JSON。
  8. 通过 ESP8266 发送 HTTP 请求到服务端。
  9. 网络异常时把记录留在本地,后续自动重试。

2. 相关文件

文件 作用
User/main.c 主程序入口、初始化流程、主循环、联网和同步调度
Hardware/Attendance.c 考勤业务逻辑:时间段、重复判断、本地记录、同步状态
Hardware/Attendance.h 考勤数据结构和函数声明
Hardware/K210_USART.c 解析 K210 串口识别结果
Hardware/esp8266.c ESP8266 AT 指令、HTTP GET/POST、对时、查重
Hardware/Crypto.c AES-128-CBC 加密和 Base64 编码
Hardware/DS1302.c DS1302 RTC 时钟读写
Hardware/LightSensor.c 光敏电阻 ADC 和补光灯控制
Hardware/Buzzer_LED.c 蜂鸣器、成功 LED、状态 LED
Hardware/OLED.c OLED 显示
System/Delay.c 延时和毫秒计时
System/Debug.c 调试串口输出
Project.uvprojx Keil 工程文件

3. 硬件连接

外设 STM32 引脚 说明
ESP8266 TX/RX PA10 / PA9 USART1,波特率 115200
K210 TX/RX PB11 / PB10 USART3,波特率 115200
调试串口 PA3 / PA2 USART2,波特率 115200
OLED SCL/SDA PB8 / PB9 I2C
成功 LED PB4 高电平点亮
蜂鸣器 PB5 低电平触发
光敏传感器 PB0 ADC1 通道 8
补光灯 PB1 高电平点亮
DS1302 CLK/DAT/RST PA4 / PA5 / PA6 软件 GPIO 时序
板载状态 LED PC13 低电平点亮,初始化中亮,就绪后灭

4. 代码中的主要配置

位置:User/main.c

配置 当前值 说明
WIFI_SSID yzfh ESP8266 要连接的 WiFi
WIFI_PASSWORD yzfhroot WiFi 密码
HTTP_SERVER_IP 27.106.113.205 服务端 IP
HTTP_SERVER_PORT 8082 服务端 HTTP 端口
HTTP_API_TOKEN atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV API Token
CLASS_ID 1 当前 STM32 设备所属班级编号
TIME_SYNC_INTERVAL_MS 3600000 每小时对时一次
TIMESLOT_DOWNLOAD_INTERVAL_MS 30000 每 30 秒检查一次时间段配置
WIFI_RECONNECT_INTERVAL_MS 30000 WiFi 断开后每 30 秒重连
RECONNECT_INTERVAL_MS 5000 服务端连接不可用后每 5 秒尝试重连
MIN_CONFIDENCE_THRESHOLD 0.75 最低识别置信度
MAX_ATTENDANCE_RECORDS 100 STM32 本地最多缓存 100 条记录
MAX_TIME_SLOT_COUNT 10 最多支持 10 个签到时间段

5. 启动流程

STM32 上电后按下面顺序执行:

  1. 初始化调试串口。
  2. 初始化延时模块。
  3. 初始化 OLED。
  4. 初始化蜂鸣器和 LED。
  5. 初始化 USART1,用于连接 ESP8266。
  6. 初始化 USART3,用于接收 K210 数据。
  7. 初始化考勤模块。
  8. 初始化 AES 加密模块。
  9. 初始化 DS1302,并尝试读取时间。
  10. 初始化光敏传感器和补光灯。
  11. 初始化 ESP8266。
  12. 连接 WiFi。
  13. 从服务端获取当前时间。
  14. 连接 HTTP 服务端。
  15. 下载签到时间段配置。
  16. 下载今日当前时段已签到记录。
  17. 进入主循环。

如果 WiFi 或服务端连接失败,程序不会停机,而是进入离线或重连状态。后续主循环会自动重试。

6. 主循环每次做什么

User/main.c 的主循环大致如下:

while (1) {
    ProcessBeep();
    UpdateCurrentTime();
    CheckServerConnection();
    SyncPendingRecords();
    UpdateTimeSlotConfig();
    LightSensor_Update();

    if (K210_GetRxFlag()) {
        Attendance_ProcessFaceResult(&K210_FaceResult);
    }
}

逐项解释:

函数 作用
ProcessBeep 非阻塞处理蜂鸣器和成功 LED
UpdateCurrentTime 从 DS1302 或软件时钟维护当前时间,并定期网络对时
CheckServerConnection 检查当前 HTTP/TCP 连接状态,连接不可用时按需重连
SyncPendingRecords 把本地未同步记录加密上传
UpdateTimeSlotConfig 定期下载服务端签到时间段
LightSensor_Update 根据环境光自动开关补光灯
K210_GetRxFlag 看是否收到 K210 的新识别结果

注意:当前 STM32 HTTP 请求和服务端响应都使用 Connection: close,所以它不是长期保持一个 TCP 长连接,而是在每次请求前检查连接状态,并在需要时重新建立连接。

7. K210 发给 STM32 的数据格式

K210 通过 UART1 发送文本,STM32 通过 USART3 接收。

识别成功:

ID:20240001,NAME:Zhang_San,CONF:0.95

字段说明:

字段 含义
ID 学号或 K210 同步后的身份编号
NAME 显示名,K210 代码中会用下划线代替空格
CONF 置信度,范围一般是 0.0 到 1.0

未识别:

UNKNOWN

STM32 收到 UNKNOWN 后不会签到。

8. 签到判断逻辑

STM32 对一次识别结果的判断顺序如下:

  1. 判断 K210 是否识别成功。
  2. 判断置信度是否低于 0.75。
  3. 判断当前是否在启用的时间段内。
  4. 判断当前时段本地记录中是否已经有该学生。
  5. 判断从服务端下载的今日缓存中是否已经有该学生。
  6. 如果服务端在线,再调用服务端查重接口确认。
  7. 通过所有检查后,生成一条本地考勤记录。
  8. 如果服务端在线,后续同步任务会加密上传。

当前默认没有任何时间段。必须由 Qt 管理端新增并保存时间段,否则第 3 步会失败,OLED 会显示不在签到时间。

9. 时间段同步

STM32 调用:

GET /api/v1/sync/state?client=stm32&last_version=<本地版本>

服务端返回示例:

{
  "version": 5,
  "changed": true,
  "client": "stm32",
  "server_time": "2026-05-01 10:00:00",
  "state": {
    "time_slots": [
      {
        "name": "上午签到",
        "start_time": "08:00",
        "end_time": "09:30",
        "enabled": true
      }
    ]
  }
}

如果 time_slots 是空数组,STM32 会清空本地时间段配置。

10. 今日记录缓存

STM32 为了减少重复签到,会在开机连接服务端后下载今日当前时间段的已签到学号:

GET /api/v1/attendance/today?slot_start=08:00&slot_end=09:30

返回:

{
  "date": "2026-05-01",
  "records": ["20240001", "20240002"]
}

下载后,STM32 会把这些学号放进缓存。之后如果同一个学生在同一个时段再次识别,会被判定为重复签到。

11. 加密上传

STM32 上传签到记录时使用:

POST /api/v1/attendance/checkins
X-Api-Token: <Token>
X-Encrypted: AES128-CBC
Content-Type: application/octet-stream

请求体是 Base64 编码后的 AES 密文。明文 JSON 类似:

{
  "student_id": "20240001",
  "name": "Zhang San",
  "confidence": 0.95,
  "status": "success",
  "class_id": "1"
}

服务端解密成功后写入 attendance.db。

12. 本地记录和同步状态

STM32 的本地记录结构体:

typedef struct {
    char student_id[20];
    char student_name[32];
    float confidence;
    uint32_t timestamp;
    uint8_t time_slot;
    SyncStatus sync_status;
    uint8_t retry_count;
    uint32_t last_retry_time;
} AttendanceRecord;

同步状态:

状态 含义
SYNC_PENDING 新记录,等待上传
SYNC_SYNCING 正在上传
SYNC_SYNCED 上传成功
SYNC_FAILED 上传失败,后续重试

13. OLED 和声光反馈

情况 OLED 蜂鸣器/LED
初始化中 显示 ESP/WiFi/HTTP 状态 PC13 状态灯亮
服务端在线 System Ready / Online Mode 成功提示
WiFi 在线但服务端断开 System Ready / Reconnecting.. 后台重连
WiFi 正在重连 System Ready / WiFi retry... 后台重连
ESP8266 不可用 System Ready / Offline Mode 错误提示
签到成功 Check-in OK! 成功提示
重复签到 Already Signed! 错误提示
置信度低 Low Confidence 错误提示
不在时间段 Not Check Time 错误提示

14. 编译与烧录

使用 Keil 打开:

Project.uvprojx

一般步骤:

  1. 安装 Keil MDK 和 STM32F10x 支持包。
  2. 打开 Project.uvprojx。
  3. 确认芯片型号和启动文件与实际开发板一致。
  4. 修改 User/main.c 中的 WiFi、服务端 IP、班级编号和 Token。
  5. 编译工程。
  6. 使用 ST-Link 或串口 Bootloader 烧录。
  7. 打开调试串口查看日志。

15. 调试建议

15.1 先看调试串口

调试串口会输出:

  1. 硬件初始化状态。
  2. ESP8266 AT 指令结果。
  3. WiFi 连接结果。
  4. HTTP 服务端连接结果。
  5. 时间同步结果。
  6. 时间段下载结果。
  7. K210 原始数据和解析结果。
  8. 加密上传结果。

15.2 常见问题

现象 可能原因 处理
一直显示 WiFi retry SSID/密码错误、ESP8266 没接好、供电不足 检查 WIFI_SSID、WIFI_PASSWORD、供电和串口
HTTP connection failed 服务端 IP/端口错误、防火墙拦截、服务端没启动 用电脑访问健康检查接口
Not Check Time 没有配置时间段,或当前时间不在时间段内 Qt 新增时间段并保存,检查 DS1302/NTP
Already Signed 当前时段已经签过 换时间段或清空记录
Low Confidence K210 比对分数偏低 调整光线、重新录入人脸
Qt 看不到记录 STM32 未同步成功或服务端地址不一致 看服务端日志和 Qt 服务端地址

16. 修改配置时要同步修改哪里

你修改了什么 需要同步修改
服务端 IP User/main.c、k210/main.py、Qt 配置中心
API Token 服务端环境变量或代码、User/main.c、k210/main.py、Qt 环境变量
AES Key/IV Hardware/Crypto.c、server/server_encrypted.cpp、QT/src/CryptoUtils.cpp
班级编号 每块 STM32 对应修改 CLASS_ID
WiFi User/main.c 和 k210/main.py