ch32v307_camera/doc/模式配置与功能说明.md
2026-03-15 16:47:32 +08:00

670 lines
24 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.

# CH32V307 TCPClient 模式配置与功能说明
> **版本**: v2.0 — 自主触发架构
> **更新日期**: 2026-03
> **适用代码**: main.c 自主触发架构(已移除所有 `TEST_ENABLE_*` 编译开关)
## 目录
1. [系统架构概述](#1-系统架构概述)
2. [运行模式说明](#2-运行模式说明)
3. [编译期常量总表](#3-编译期常量总表)
4. [自主触发架构详解](#4-自主触发架构详解)
5. [2D 触发状态机](#5-2d-触发状态机)
6. [1D 采集状态机](#6-1d-采集状态机)
7. [TEMP_REQ 辅助通道](#7-temp_req-辅助通道)
8. [测试模式详解](#8-测试模式详解)
9. [正常模式详解](#9-正常模式详解)
10. [网络与服务器配置](#10-网络与服务器配置)
11. [配置下发流程](#11-配置下发流程)
12. [RTOS 任务架构](#12-rtos-任务架构)
13. [GPIO 引脚分配](#13-gpio-引脚分配)
14. [功能完整性对照表](#14-功能完整性对照表)
15. [已知注意事项](#15-已知注意事项)
---
## 1. 系统架构概述
本系统基于 CH32V307WCU6 (RISC-V) 微控制器,运行 FreeRTOS 实时操作系统,通过 WCHNET TCP/IP 协议栈与上位机通信。系统行为完全由运行时服务器配置驱动——服务器下发 Config2D/Config1D 并设置 `Enabled=1`MCU 自主执行触发检测和数据采集上报。
### 硬件资源
| 资源 | 配置 |
|------|------|
| MCU | CH32V307WCU6 (RISC-V, 144MHz) |
| FLASH | 128KB |
| SRAM | 192KB (Option Bytes [7:5]=110) |
| 传感器 | Mini212G2 (256×192, Y16 原始温度) |
| 网络 | 1000M 以太网 RGMII (WCHNET) |
| 串口波特率 | 921600 |
### 软件组件
| 组件 | 说明 |
|------|------|
| FreeRTOS v202112.00 | 实时操作系统Heap=16KB |
| WCHNET | 万瑞 TCP/IP 协议栈 |
| QDX 协议栈 | 自定义 TLV 二进制通信协议 (0x55AA, v2.0) |
| 预处理模块 | 滑窗 ROI 搜索 + 温度统计 + 自动降尺寸 |
---
## 2. 运行模式说明
系统仅保留一个编译期宏开关 `TEST_PATTERN_MODE`控制数据来源。所有业务功能触发、采集、NG 输出、心跳)在两种模式下均始终启用,行为由服务器运行时配置驱动。
### 两种模式对比
| 对比项 | 测试模式 (`TEST_PATTERN_MODE=1`) | 正常模式 (`TEST_PATTERN_MODE=0`) |
|--------|------|------|
| **数据来源** | 软件生成模拟热图 (~10 FPS) | Mini212G2 传感器 DVP/DMA 采集 |
| **硬件依赖** | 仅需网口,无需传感器 | 需连接 Mini212G2 + DVP 线缆 |
| **初始化** | 跳过 `DVP_Init()` | 执行 DVP 初始化 |
| **帧生成** | `task_test_pattern_entry` 任务周期填充 | DVP 行中断逐行 DMA 搬运 |
| **默认配置** | 自动注入测试配置2D Enabled=1, 内部触发, 80°C | 等待服务器下发,默认不使能 |
| **自主触发** | ✅ 立即工作(无需服务器) | ✅ 需服务器下发 Enabled=1 后激活 |
| **TEMP_REQ** | ✅ 可用(需对应模式 Enabled=1 | ✅ 可用 |
| **NG GPIO** | ✅ PA8 始终初始化 | ✅ PA8 始终初始化 |
| **外部触发 GPIO** | ✅ PA15/EXTI15 始终初始化 | ✅ PA15/EXTI15 始终初始化 |
---
## 3. 编译期常量总表
所有宏定义位于 `prj/TCPClient/User/main.c` 文件头部。
### 3.1 主模式开关
| 宏名 | 当前值 | 说明 |
|------|--------|------|
| `TEST_PATTERN_MODE` | **0** | **唯一编译开关**1=测试模式0=正常模式 |
### 3.2 业务常量
| 宏名 | 值 | 说明 |
|------|-----|------|
| `DEFAULT_BURST_COUNT` | 3 | 服务器未配置时的默认连拍帧数 |
| `DEFAULT_BURST_INTERVAL_MS` | 200 | 服务器未配置时的默认连拍间隔 (ms) |
| `MAX_TCP_PAYLOAD_SIZE` | 9216 | TCP 发送缓冲区大小 (字节) |
| `KEEPALIVE_ENABLE` | 1 | TCP KeepAlive20s 空闲 / 15s 探测 / 9 次) |
| `TEST_FPS_DELAY_MS` | 100 | 测试模式帧生成间隔 (~10 FPS) |
| `SNAPSHOT_1D_POINTS` | 30 | TEMP_REQ 1D 空间采样点数 |
| `MAX_1D_POINTS` | 512 | 1D 采集缓冲最大样本数 |
| `NG_PULSE_MS` | 200 | NG 脉冲默认宽度(服务器可通过 NGioDelay 覆盖) |
### 3.3 GPIO 引脚宏
| 宏名 | 值 | 说明 |
|------|-----|------|
| `EXT_TRIG_GPIO_PORT` | GPIOA | 外部触发输入端口 |
| `EXT_TRIG_GPIO_PIN` | GPIO_Pin_15 | PA15 |
| `EXT_TRIG_EXTI_LINE` | EXTI_Line15 | 外部中断线 |
| `NG_GPIO_PORT` | GPIOA | NG 输出端口 |
| `NG_GPIO_PIN` | GPIO_Pin_8 | PA8 |
### 3.4 传感器相关宏 (dvp.h)
| 宏名 | 值 | 说明 |
|------|-----|------|
| `SENSOR_WIDTH` | 256 | 传感器像素宽度 |
| `SENSOR_HEIGHT` | 192 | 传感器像素高度 |
| `BYTES_PER_LINE` | 512 | 每行字节数 (256×2) |
### 3.5 传感器通信宏 (mini212g2.h)
> 当前模组已通过 USB 预配置MCU UART 配置功能已用 `#if 0` 关闭。
> **USART2 (PA2/PA3) 引脚已被占用,不可用于传感器通信。**
| 宏名 | 当前值 | 说明 |
|------|--------|------|
| `SENSOR_UART_ENABLE` | **0 (已禁用)** | 传感器通过 USB 预配置 |
---
## 4. 自主触发架构详解
### 4.1 核心设计原则
系统的所有业务行为由运行时服务器配置驱动,不再使用编译期功能开关:
```
服务器下发 Config2D (Enabled=1) → MCU 自主执行 2D 触发/连拍/上报
服务器下发 Config1D (Enabled=1) → MCU 自主执行 1D 采集/上报
两者互斥Config2D.Enabled 优先级高于 Config1D.Enabled
```
### 4.2 主循环逻辑流程
```
task_business_entry (优先级 5, 2ms 轮询)
├── [1] NG 脉冲超时检查 → 到期则拉低 PA8
├── [2] DVP_Task() (仅正常模式)
│ ├── 行 DMA 完成 → 复制到 FrameBuffer
│ └── 最后一行 → Frame_Ready_Flag=1
├── [3] TEMP_REQ 辅助通道(服务器按需截图)
│ ├── 前提:对应模式 Enabled=1
│ ├── is2D=1 → Preprocess_Execute() → TCP 发送 (frameType=0x02)
│ └── is2D=0 → send_1d_snapshot() → 30 点空间采样
└── [4] 自主触发主管线
│ 前提Frame_Ready_Flag=1 && TcpLogic_GetLatestConfig OK
├── Config2D.Enabled=1 → handle_2d_trigger()
2D 触发状态机:消抖 → 延迟 → 连拍)
└── Config1D.Enabled=1 → handle_1d_trigger()
1D 采集状态机IDLE → DEBOUNCE → COLLECTING
```
### 4.3 回调注册
| 回调 | 注册函数 | 触发时机 | 处理 |
|------|---------|---------|------|
| `OnConfigUpdate` | `TcpLogic_RegisterConfigCallback` | 服务器下发配置 | → `Preprocess_Settings_Change()` |
| `OnDetectionResult` | `TcpLogic_RegisterDetectionCallback` | 服务器返回检测结果 (resultStatus=0 为 NG) | → PA8 NG 脉冲 |
| `OnTempFrameRequest` | `TcpLogic_RegisterTempFrameRequestCallback` | 服务器请求截图 | → 设置 `g_temp_req_pending` |
---
## 5. 2D 触发状态机
### 5.1 状态机流程
```
┌─────────────┐
│ IDLE │
│ 等待触发 │
└──────┬──────┘
┌────────────┼────────────┐
│ TriggerMode=0 │ TriggerMode=1
│ (内部触发) │ (外部触发)
▼ ▼
Preprocess_CheckInternalTrigger2D() PA15/EXTI15 上升沿
│ (TriggerRoi 区域 Max/Avg > Threshold)
│ │
│ ┌──────────────┐
│ │ DEBOUNCE │
│ │ DebounceMs │
│ └──────┬───────┘
│ │
└─────────┬───────────────┘
┌──────────────┐
│ DELAY │
│ DelayMs │
└──────┬───────┘
┌──────────────┐
│ BURST │──┐
│ 发送第1帧 │ │ 剩余 BurstCount-1 帧
└──────────────┘ │ 间隔 InternalIntervalMs
▲ │
└──────────┘
Burst 完成 → 回到 IDLE
```
### 5.2 关键 Config2D 字段
| 字段 | 类型 | 2D 触发中的作用 |
|------|------|----------------|
| `Enabled` | u8 | 1=启用 2D 管线 |
| `TriggerMode` | u8 | 0=内部(温度), 1=外部(GPIO) |
| `TriggerDebounceIntervalMs` | u16 | 外部触发消抖等待 (ms) |
| `TriggerDelayMs` | u16 | 触发确认后延迟采集 (ms) |
| `TriggerBurstCount` | u8 | 连拍帧数 |
| `TriggerInternalIntervalMs` | u16 | 连拍帧间隔 (ms) |
| `TriggerCondition` | u8 | 内部触发判定0=平均温度, 1=最大温度 |
| `TriggerTemperatureThreshold` | i16 | 内部触发温度阈值 (0.1°C/LSB) |
| `TriggerRoiX/Y/W/H` | u16×4 | 内部触发检测区域 |
| `TargetWidth` / `TargetHeight` | u16 | 预处理输出尺寸 |
| `NGioDelay` | u16 | NG 脉冲宽度 (ms) |
### 5.3 2D 帧发送路径
```
handle_2d_trigger() → start_2d_burst()
→ do_2d_capture_send()
→ Preprocess_Execute(raw, tx_buf, &meta) // 滑窗 ROI 搜索
→ TcpLogic_BuildAndSendTemperatureFrame(tx_buf, &meta, 0x01, 1)
// frameType=TRIGGER, is2D=1
```
---
## 6. 1D 采集状态机
### 6.1 状态机流程
```
┌─────────────┐
│ S1D_IDLE │ (RunMode 必须=1)
│ 等待触发 │
└──────┬──────┘
┌────────────┼────────────┐
│ TriggerType=1 │ TriggerType=2
│ (内部触发) │ (外部触发)
▼ ▼
前置环形缓冲(3样本) PA15/EXTI15 上升沿
连续3个 ≥ TriggerTempLimit │
│ ▼
│ ┌───────────────┐
│ │ S1D_DEBOUNCE │
│ │ HighTimerLimit │
│ └──────┬────────┘
│ │
└─────────┬───────────────┘
┌────────────────┐
│ S1D_COLLECTING │
│ 逐帧采集温度点 │
│ (中心行最大值) │
└───────┬────────┘
┌────────┼────────┐
│ 停止条件1 │ 停止条件2
│ BufferSize 满 │ 已触发 + NgCountLimit 连续冷点
│ │
└────────┬────────┘
切片 [LSizeStart, -RSizeStart]
send_1d_collection() → TCP 发送
回到 S1D_IDLE
```
### 6.2 1D 温度采样方式
每个 DVP 帧产生一个温度样本:取中心行所有像素的最大温度值(`get_1d_sample()`)。
### 6.3 内部触发预环形缓冲
内部触发模式维护长度为 3 的环形缓冲:
- 每帧写入一个样本到环形缓冲
- 当 3 个样本全部 ≥ `TriggerTempLimit` → 进入 COLLECTING 状态
- 环形缓冲内容(最旧在前)写入采集数组前 3 位
- 从第 4 位起继续采集
### 6.4 关键 Config1D 字段
| 字段 | 类型 | 1D 采集中的作用 |
|------|------|----------------|
| `Enabled` | u8 | 1=启用 1D 管线 |
| `RunMode` | u8 | 0=STOP, 1=RUN, 2=NOP, 3=DEBUG |
| `TriggerType` | u8 | 1=内部(温度), 2=外部(GPIO) |
| `BufferSize` | u16 | 单次采集最大样本数(停止条件) |
| `TriggerTempLimit` | i16 | 触发/采集温度阈值 (0.1°C/LSB) |
| `HighTimerLimit` | u16 | 外部触发消抖时间 (ms) |
| `NgCountLimit` | u8 | 连续冷点数→停止采集 |
| `LSizeStart` | u16 | 切片左起始偏移 |
| `RSizeStart` | u16 | 切片右侧移除点数 |
### 6.5 1D 数据打包格式
每个样本点 4 字节 (Little-Endian)
| 偏移 | 类型 | 说明 |
|------|------|------|
| 0-1 | u16 LE | TimeOffset (距采集开始的毫秒偏移) |
| 2-3 | u16 LE | Temperature (0.1°C/LSB) |
---
## 7. TEMP_REQ 辅助通道
TEMP_REQ 是服务器主动请求的按需截图通道,与自主触发管线独立工作:
- **2D 截图**`Preprocess_Execute()` → 滑窗搜索 → 发送 `frameType=0x02`MASKED
- **1D 截图**`send_1d_snapshot()` → 从中心行等间距采样 30 点 → 发送
前提:对应模式 `Enabled=1`,否则请求被忽略并打印 `TEMP_REQ ignored`
---
## 8. 测试模式详解
### 8.1 启用方式
```c
#define TEST_PATTERN_MODE 1
```
编译烧录即可,**无需连接任何传感器硬件**,仅需以太网连接。
### 8.2 测试图案
系统自动循环生成 4 种测试图案256×192 Y16 格式):
| 图案 | 持续帧数 | 温度范围 | 是否触发 | 用途 |
|------|---------|---------|---------|------|
| **对角渐变** | 20 帧 | 25.0°C → 45.0°C | 否 | 基线测试 |
| **中心热点** | 5 帧 | 背景 28~32°C, 中心 90.0°C | 是 (>80°C) | 触发测试 |
| **均匀温场** | 10 帧 | 35.0°C | 否 | 无触发验证 |
| **棋盘格** | 5 帧 | 28.0°C / 85.0°C 交替 | 是 (>80°C) | ROI 搜索测试 |
总周期40 帧 ≈ 4 秒循环一次。
### 8.3 自动注入测试配置
测试模式启动时通过 `TcpLogic_InjectTestConfig()` 注入以下配置(走标准缓存+回调路径):
```
Config2D:
Enabled = 1 # 自动启用 2D 管线
TriggerMode = 0 # 内部触发(温度检测)
TargetWidth = 64 # 预处理输出 64×64
TargetHeight = 64
TriggerRoiX/Y = 0, 0 # 全幅扫描
TriggerRoiW/H = 256, 192
TriggerCondition = 1 # 最大温度
TriggerTemperatureThreshold = 800 # 80.0°C
TriggerBurstCount = 3 # 3 帧连拍
TriggerInternalIntervalMs = 200
NGioDelay = 200
```
> **注入路径**`TcpLogic_InjectTestConfig()` → 内部缓存 + `has_valid_config=1` → 触发 `OnConfigUpdate` 回调 → `Preprocess_Settings_Change()`。与服务器下发配置走完全相同的路径。
### 8.4 启动串口输出示例
```
TCPClient
SystemClk:144000000
TEST_PATTERN=1
UserByte: c0
=== TEST PATTERN MODE === No sensor/DVP hardware needed
net version:1c
WCHNET_LibInit Success
Test config injected: En=1 TrigMode=Internal thresh=800 Tgt=64x64 burst=3
[HB] 0 tick=1010 TEST_MODE frm=9
2D internal trigger
TRIGGER frm=21
2D SEND frm=21 64x64 ret=0
Burst start: 3 frames, interval=200 ms
```
---
## 9. 正常模式详解
### 9.1 启用方式
```c
#define TEST_PATTERN_MODE 0
```
需要:
1. Mini212G2 传感器正确连接 DVP 接口
2. 传感器已通过 USB 预配置为 CMOS/DVP Y16 输出
### 9.2 硬件连接
#### DVP 引脚定义
| 功能 | GPIO | 说明 |
|------|------|------|
| DATA[0] | PA4 | 数据线 bit0 |
| DATA[1] | PA5 | 数据线 bit1 |
| DATA[2] | PA6 | 数据线 bit2 |
| DATA[3] | PA9 | 数据线 bit3 |
| DATA[4] | PA10 | 数据线 bit4 |
| DATA[5] | PB3 | 数据线 bit5 |
| DATA[6] | PB8 | 数据线 bit6 |
| DATA[7] | PB9 | 数据线 bit7 |
| HSYNC | PC8 | 行同步 |
| VSYNC | PC9 | 场同步(高有效) |
| PCLK | PC11 | 像素时钟(上升沿采样) |
#### 传感器 UART仅 USART3 可用)
> ⚠ USART2 (PA2/PA3) 引脚已被占用,不可用于传感器通信。
| 配置 | USART3 |
|------|--------|
| TX | PB10 |
| RX | PB11 |
| 波特率 | 115200 |
> 注意:启用 USART3 传感器通信会占用 printf 调试端口,需通过 JTAG 调试。
### 9.3 正常模式数据流
```
DVP 硬件中断 (DVP_IRQHandler)
├── STR_FRM 中断 → 帧开始line_idx=0
└── ROW_DONE 中断 → 行完成DMA 乒乓切换
│ 设置 Line_Ready_Flag=1
task_business_entry (优先级 5)
│ DVP_Task()
│ ├── 复制 DMA 行缓冲 → FrameBuffer[line_idx]
│ └── 最后一行 → Frame_Ready_Flag=1
├── [TEMP_REQ] 服务器按需截图
└── [自主触发] Config2D.Enabled → 2D 状态机
Config1D.Enabled → 1D 状态机
```
### 9.4 正常模式注意事项
- **无默认配置**:正常模式不注入测试配置,`Preprocess_Init()` 仅设置 `TargetWidth=1, TargetHeight=1`。必须等服务器下发 Config2D/Config1D 后才能工作。
- **传感器初始化**:模组已通过 USB 预配置,`mini212g2.h` 中 UART 配置已关闭。
- **帧率取决于传感器**Mini212G2 在 DVP 模式下的帧率由传感器内部配置决定。
---
## 10. 网络与服务器配置
### 10.1 MCU 网络参数
定义位置:`main.c`
| 参数 | 值 | 说明 |
|------|-----|------|
| IP 地址 | 192.168.7.10 | MCU 静态 IP |
| 网关 | 192.168.7.1 | 默认网关 |
| 子网掩码 | 255.255.255.0 | C 类子网 |
| MAC 地址 | 由芯片自动获取 | 硬件 MAC |
### 10.2 服务器连接参数
定义位置:`qdx_tcp_logic.c`
| 参数 | 值 | 说明 |
|------|-----|------|
| `SERVER_IP` | "192.168.7.50" | 服务器 IP |
| `CONTROL_PORT` | 5511 | 控制通道端口 |
| `DATA_PORT` | 5512 | 数据通道端口 |
### 10.3 TCP KeepAlive
```c
#define KEEPALIVE_ENABLE 1 // main.c
// 探测配置: 20s 空闲后每 15s 探测一次,最多 9 次
```
### 10.4 TCP 内部参数
| 参数 | 值 | 说明 |
|------|-----|------|
| `HEARTBEAT_INTERVAL_MS` | 2000 | 心跳发送间隔 |
| `SERVER_TIMEOUT_MS` | 6000 | 服务器超时断连 |
| `RECONNECT_DELAY_MS` | 3000 | 断连后重连等待 |
| `MAX_FRAGMENT_PAYLOAD` | 1400 | 分片最大载荷 |
---
## 11. 配置下发流程
### 11.1 TLV 消息类型
| TLV Type | 名称 | 方向 | 说明 |
|----------|------|------|------|
| 0x01 | TYPE_HANDSHAKE | ↔ | 握手UUID、版本 |
| 0x02 | TYPE_HEARTBEAT | ↔ | 心跳(上行/下行) |
| 0x05 | TYPE_DEVID_ASSIGN | ← | 设备 ID 分配(触发重连) |
| 0x10 | TYPE_TEMP_FRAME | ← | 请求温度帧TEMP_REQ |
| 0x20 | TYPE_CONFIG_COMMON | ← | 通用配置 |
| 0x22 | TYPE_CONFIG_2D | ← | 2D 配置 |
| 0x23 | TYPE_CONFIG_1D | ← | 1D 配置 |
| 0x30 | TYPE_ACK_PAYLOAD | ← | ACK 响应 |
| 0x40 | TYPE_DETECTION_RESULT | ← | 检测结果OK/NG |
### 11.2 Config2D 关键字段
| 字段 | 偏移 | 类型 | 说明 |
|------|------|------|------|
| Enabled | 0 | u8 | **使能开关** |
| Width | 4 | u16 LE | 设备分辨率宽度(仅标记) |
| Height | 6 | u16 LE | 设备分辨率高度(仅标记) |
| **TargetWidth** | **23** | **u16 LE** | **预处理输出宽度** |
| **TargetHeight** | **25** | **u16 LE** | **预处理输出高度** |
| TriggerMode | 21 | u8 | 0=内部, 1=外部 |
| TriggerCondition | 37 | u8 | 0=平均, 1=最大 |
| TriggerTemperatureThreshold | 28 | i16 LE | 触发阈值 (0.1°C/LSB) |
| TriggerBurstCount | 30 | u8 | 连拍帧数 |
| TriggerInternalIntervalMs | 31 | u16 LE | 连拍间隔 (ms) |
| TriggerDebounceIntervalMs | 35 | u16 LE | 外部触发消抖 (ms) |
| TriggerDelayMs | 23 | u16 LE | 触发后延迟 (ms) |
| TriggerRoiX/Y/W/H | 33-40 | u16 LE ×4 | 内部触发检测 ROI |
| NGioDelay | 41 | u16 LE | NG 脉冲宽度 (ms) |
> **重要**`Width/Height` 与 `TargetWidth/TargetHeight` 是两组不同的字段!前者仅做标识,后者直接控制帧大小。
### 11.3 缓冲区容量约束
```
MAX_TCP_PAYLOAD_SIZE = 9216 字节
HeadOffset = 64 字节(协议头预留)
可用像素空间 = 9216 - 64 = 9152 字节
最大像素数 = 9152 / 2 = 4576 像素
推荐安全目标尺寸:
64 × 64 = 4096 像素 = 8192 字节 ✓
67 × 67 = 4489 像素 = 8978 字节 ✓
68 × 68 = 4624 像素 = 9248 字节 ✗ (触发降尺寸)
```
### 11.4 自动降尺寸保护
TargetWidth × TargetHeight × 2 超过可用缓冲区时,自动等比减半:
```
示例:服务器设 185×70 → 185×70×2=25900 > 9152 → 减半 → 93×35
日志PP: target clamped 185x70 -> 93x35 (buf=10176)
```
### 11.5 配置传递链
```
服务器 TCP 下发 TLV
→ qdx_tcp_logic.c: parse_and_dispatch_tlv()
→ 反序列化 → cached_cfg{2d,1d,common}
→ OnConfigUpdate() 回调
→ Preprocess_Settings_Change() 互斥锁更新
→ 下次帧处理使用新配置
```
---
## 12. RTOS 任务架构
| 任务名 | 优先级 | 栈 (words) | 条件 | 功能 |
|--------|--------|-----------|------|------|
| `wchnet` | 6 (最高) | 512 | 始终创建 | WCHNET 协议栈轮询 (5ms) |
| `business` | 5 | 512 | 始终创建 | DVP + 触发状态机 + 发送 |
| `testpat` | 4 | 256 | `TEST_PATTERN_MODE=1` | 测试图案生成 (~10 FPS) |
| `hb` | 3 (最低) | 256 | 始终创建 | 心跳调试打印 (2s) |
| TcpLogic 内部 | - | - | 始终创建 | 管理线程 (连接/心跳/重连) |
---
## 13. GPIO 引脚分配
| GPIO | 功能 | 方向 | 配置 | 说明 |
|------|------|------|------|------|
| PA15 | 外部触发输入 | 输入 | 下拉 + EXTI15 上升沿 | 2D/1D 共用(互斥) |
| PA8 | NG 输出 | 推挽输出 | 低速 2MHz | 检测 NG 时脉冲拉高 |
| PA4-PA6, PA9-PA10, PB3, PB8-PB9 | DVP 数据线 | 输入 | 浮空 | 仅正常模式使用 |
| PC8, PC9, PC11 | DVP HSYNC/VSYNC/PCLK | 输入 | - | 仅正常模式使用 |
| PA2, PA3 | **已占用** | - | - | USART2不可用 |
---
## 14. 功能完整性对照表
### 协议规范 vs MCU 实现
| 协议功能 | 实现状态 | 备注 |
|---------|---------|------|
| 握手 (Handshake) | ✅ | UUID + HW/FW 版本 |
| 心跳 (Heartbeat) | ✅ | 2s 间隔6s 超时断连 |
| 设备 ID 分配 (DevID Assign) | ✅ | 触发自动重连 |
| Config Common/2D/1D 下发 | ✅ | 解析+缓存+回调 |
| ACK 响应 | ✅ | 发送+接收 |
| TEMP_REQ 截图 | ✅ | 2D 预处理 / 1D 空间采样 |
| Detection Result | ✅ | NG → PA8 脉冲 |
| 2D 外部触发 | ✅ | GPIO → 消抖 → 延迟 → 连拍 |
| 2D 内部触发 | ✅ | ROI Max/Avg → 延迟 → 连拍 |
| 1D 外部触发 | ✅ | GPIO → 消抖 → 采集 → 切片 |
| 1D 内部触发 | ✅ | 3 样本预环形 → 采集 → 切片 |
| 温度矩阵分片发送 | ✅ | 每片 ≤1400 字节 |
| TCP KeepAlive | ✅ | 20s/15s/9次 |
| CRC16-MODBUS 校验 | ✅ | 每帧校验 |
| IsLive 实时流 | ❌ | MCU 资源不足,触发场景不需要 |
| Training 训练模式 | ❌ | 服务器端完成 |
| SyncTime 时间同步 | ❌ | 协议已定义 (0x03),未解析 |
| StatusEvent 状态上报 | ❌ | 服务器通过心跳判断在线 |
| Alarm GPIO | ❌ | 结构体有字段,硬件未接线 |
| 1D StartPointsToRemove / ReferenceLength / TimerCLimit | ❌ | 已解析到结构体,业务逻辑未使用 |
---
## 15. 已知注意事项
### 15.1 温度单位
系统统一使用 **0.1°C/LSB**
- 温度值 350 = 35.0°C
- 温度值 900 = 90.0°C
- `TEMP_RAW(deg_c) = (uint16_t)(deg_c * 10)`
### 15.2 Config2D 字段区分
- **Width / Height**:设备分辨率标识(如 256×192不影响 MCU 预处理
- **TargetWidth / TargetHeight**:预处理实际输出尺寸,**必须正确设置**
### 15.3 正常模式默认目标尺寸
`TargetWidth=1, TargetHeight=1`(最小默认),必须等服务器下发 Config2D 后才能正常输出。
### 15.4 IP 与端口硬编码
网络参数为编译期常量,更改需修改源码并重新编译:
- MCU IP`main.c``IPAddr[]`
- 服务器 IP`qdx_tcp_logic.c``SERVER_IP`
- 端口号:`qdx_tcp_logic.c``CONTROL_PORT` / `DATA_PORT`
### 15.5 printf 限制
使用 newlib-nano仅支持 `%d, %x, %s` 格式。所有 `uint32_t` 必须 `(int)` 强转后打印,否则 HardFault。不支持 `%u, %lu, %f`
### 15.6 双缓冲发送
系统使用 A/B 交替 `TcpTxBuffer_t`,避免发送过程中缓冲区被覆盖。`use_buffer_A` 标志在每次发送后翻转。
### 15.7 2D/1D 互斥
主循环中 `Config2D.Enabled` 优先级高于 `Config1D.Enabled`。若两者同时 Enabled=1仅 2D 管线运行。