diff --git a/README.md b/README.md index e8197a72..a3d23746 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,26 @@ ## 项目架构 -``` -┌─────────────────────────────────────────────────────────────┐ -│ 应用层 (App/) │ -│ app_main.c │ net_task.c │ ui_task.c │ time_sync.c │ -├─────────────────────────────────────────────────────────────┤ -│ 驱动层 (Drivers/BSP/) │ -│ CH395F/ │ GD5F2GQ5UE/ │ TPAFE5160/ │ SD2506/ │ RS485/ │ UI/ │ -├─────────────────────────────────────────────────────────────┤ -│ 中间件 (Middlewares/ & Lib/) │ -│ FreeRTOS │ FatFs │ dhara FTL │ LVGL │ -├─────────────────────────────────────────────────────────────┤ -│ HAL 层 (Drivers/STM32F4xx_HAL_Driver/) │ -│ CMSIS (Drivers/CMSIS/) │ -├─────────────────────────────────────────────────────────────┤ -│ 硬件 (STM32F407ZGTx) │ -└─────────────────────────────────────────────────────────────┘ +```mermaid +flowchart TB + subgraph APP["应用层 (App/)"] + direction LR + A1["app_main.c"] ~~~ A2["net_task.c"] ~~~ A3["ui_task.c"] ~~~ A4["time_sync.c"] + end + subgraph BSP["驱动层 (Drivers/BSP/)"] + direction LR + B1["CH395F"] ~~~ B2["GD5F2GQ5UE"] ~~~ B3["TPAFE5160"] ~~~ B4["SD2506"] ~~~ B5["RS485"] ~~~ B6["UI"] + end + subgraph MW["中间件 (Middlewares/ & Lib/)"] + direction LR + C1["FreeRTOS"] ~~~ C2["FatFs"] ~~~ C3["dhara FTL"] ~~~ C4["LVGL"] + end + subgraph HAL["HAL 层 / CMSIS"] + direction LR + D1["STM32F4xx_HAL_Driver/"] ~~~ D2["CMSIS/"] + end + HW["硬件 (STM32F407ZGTx)"] + APP --> BSP --> MW --> HAL --> HW ``` ### 启动流程 @@ -46,11 +50,13 @@ main.c ├─ HAL_Init() ├─ SystemClock_Config() // 168MHz 系统时钟 ├─ MX_GPIO/DMA/UART/SPI/I2C_Init() // CubeMX 外设初始化 - ├─ app_main_init() // 应用层初始化(时间→RS485→NAND→ADC→RTC) + ├─ app_main_init() // 应用层初始化(时间→RS485→NAND→ADC→诊断) │ ├─ sd2506_init() + sys_clock_init() // 时间子系统优先 │ ├─ rs485_init() │ ├─ gd5f2gq5ue_init() - │ └─ tpafe5160_init() + │ ├─ tpafe5160_init() + │ ├─ SD2506 诊断(ID/时间/温度/电池) + │ └─ tpafe5160_start_conv_irq() // 首次 ADC 转换 ├─ osKernelInitialize() ├─ MX_FREERTOS_Init() // 创建任务和事件组 └─ osKernelStart() // 启动调度器 @@ -114,7 +120,8 @@ STM32F4-Base/ │ │ │ ├── net_socket.c/h # Socket API │ │ │ ├── net_select.c/h # select/poll 多路复用 │ │ │ └── lftpd/ # 轻量 FTP 服务器 -│ │ └── UI/ # LVGL UI 组件 +│ │ ├── UI/ # LVGL UI 组件 +│ │ └── dbg_log.h / dbg_cfg.h # 调试日志(DBG_INFO 等) │ ├── STM32F4xx_HAL_Driver/ # ST HAL 库 │ └── CMSIS/ # ARM CMSIS ├── Lib/ # 第三方库 @@ -132,20 +139,42 @@ STM32F4-Base/ │ ├── run_boot_test.ps1 # 自动化启动测试 │ ├── verify_log.ps1 # 日志校验脚本 │ ├── serial_capture.ps1 # 串口捕获脚本 +│ ├── test_config.c/h # 测试任务配置 │ ├── ch395f_test_task.c/h # CH395F 硬件测试 │ ├── gd5f_test_task.c/h # NAND Flash 测试 │ ├── net_test_task.c/h # 网络层测试 │ ├── sd2506_test_task.c/h # RTC 测试 -│ └── storage_test_task.c/h # 存储性能测试 +│ ├── storage_test_task.c/h # 存储性能测试 +│ ├── ch395f_socket_test.py # Socket 通信测试(主机端) +│ ├── ftp_test.py # FTP 服务器测试(主机端) +│ ├── ftp_up_dl_test.py # FTP 上传下载测试(主机端) +│ ├── ftp_speed_test.py # FTP 传输速度测试(主机端) +│ ├── ftp_capture.py # FTP 流量抓取(主机端) +│ └── time_sync_server.py # 时间同步推送服务(主机端) ├── docs/ # 项目文档 │ ├── 代码规范/ # C 代码规范、pre-commit / cppcheck 使用说明 │ ├── 问题记录/ # 已知陷阱与解决方案 │ ├── 测试说明/ # 测试指南 │ ├── 芯片手册/ # 硬件数据手册 +│ ├── 测试开发标准流程.md # 测试开发标准流程 +│ ├── 测试文档模板规范.md # 测试文档模板规范 │ └── *.md # 存储架构 / UI 规划 / 墙钟时间 / 启动顺序 / LVGL 模拟器 +├── scripts/ # pre-commit 本地钩子脚本 +│ ├── check_coding_standard.py # 代码规范机械检查 +│ └── check_mojibake.py # U+FFFD 乱码检查 +├── simulator/ # LVGL PC 模拟器(CMake + SDL2) +│ ├── CMakeLists.txt # 模拟器构建脚本 +│ ├── main.c / sim_port.c/h # 模拟器入口与移植层 +│ ├── lv_conf.h # LVGL 配置(1bpp + SDL) +│ └── SDL2/ # SDL2 2.32.10 预编译库 ├── tools/ # 开发工具 │ └── font_gen/ # 中文字体生成工具 +├── ui_cn_chars.txt # 中文字体字符集 ├── STM32F407-Demo.ioc # CubeMX 工程文件 +├── .pre-commit-config.yaml # pre-commit 钩子配置 +├── .gitlint # commit message 检查规则 +├── opencode.json # opencode 配置 +├── .opencode/ # opencode 本地配置(串口等) └── AGENTS.md # AI 开发规范 ``` @@ -177,6 +206,17 @@ MDK-ARM\build.bat MDK-ARM\download.bat ``` +### LVGL PC 模拟器 + +PC 端 UI 开发调试(无需烧录 MCU),详见 `docs/LVGL模拟器部署与使用说明.md`: + +```powershell +cd simulator +cmake -B build -G "Visual Studio 16 2019" -A x64 +cmake --build build --config Debug +# 运行 simulator\build\Debug\lvgl_sim.exe +``` + ## 驱动开发指南 ### CH395F 以太网 @@ -226,6 +266,17 @@ powershell -ExecutionPolicy Bypass -File test\run_boot_test.ps1 | RTC | `sd2506_test_task.c` | 时间读写、温度、电池 | | 存储性能 | `storage_test_task.c` | FTL/FatFS 读写速度 | +### 主机端测试脚本(Python) + +| 脚本 | 说明 | +|------|------| +| `ch395f_socket_test.py` | Socket 通信测试 | +| `ftp_test.py` | FTP 服务器基础测试 | +| `ftp_up_dl_test.py` | FTP 上传/下载测试 | +| `ftp_speed_test.py` | FTP 传输速度测试 | +| `ftp_capture.py` | FTP 流量抓取 | +| `time_sync_server.py` | 时间同步推送服务(PC → 板子) | + ### 串口调试 通过 `serial-mcp-server` 自主读取 USART1 串口打印: @@ -267,6 +318,8 @@ powershell -ExecutionPolicy Bypass -File test\run_boot_test.ps1 - U+FFFD 乱码(拦截,不可逆损坏) - commit message 格式(gitlint,拦截) +本地钩子脚本:`scripts/check_coding_standard.py`、`scripts/check_mojibake.py`(由 `.pre-commit-config.yaml` 引用)。 + ```bash # 新机器启用钩子 pre-commit install diff --git a/docs/系统墙钟时间维护说明.md b/docs/系统墙钟时间维护说明.md index 757b251f..daae1be4 100644 --- a/docs/系统墙钟时间维护说明.md +++ b/docs/系统墙钟时间维护说明.md @@ -95,21 +95,29 @@ static volatile uint32_t s_base_unix_secs = UINT32_MAX; /* 基准对应的 Unix ## 6. 初始化流程(`sys_clock_init`) -``` -Step 1 从 SD2506 读取初始时间 sd2506_get_time(&sd_time) - ├─ 注意:sd_time.year 已是完整年份(驱动内已 +2000), - │ 后续换算【不得】再加 2000,否则年份虚增 → Unix 秒数超 uint32 回绕 - └─ 可选校时(见第 9 节 RTC_DEFAULT_INIT_* 宏) +```mermaid +sequenceDiagram + autonumber + participant SC as sys_clock_init + participant RTC as SD2506 RTC + participant HAL as HAL Tick -Step 2 将 RTC 时间换算为 Unix epoch 秒数 - ├─ 累计 1970 至当前年份的整年天数(含闰年 366 天判定) - ├─ 加上当年 1 月至当前月的累计天数 - ├─ 加当月已过天数、时/分/秒 - └─ 用 int64_t 累加,避免中间溢出;结果截断存入 uint32_t(受 2038 限制,见第 12 节) + Note over SC,RTC: Step 1 从 SD2506 读取初始时间 + SC->>RTC: sd2506_get_time(sd_time) + RTC-->>SC: sd_time(year 已是完整年份) + Note right of SC: 后续换算【不得】再加 2000
否则年份虚增 → Unix 秒数超 uint32 回绕 + Note right of SC: 可选校时(见第 9 节 RTC_DEFAULT_INIT_* 宏) -Step 3 建立基准 - s_base_tick = HAL_GetTick(); - s_base_unix_secs = (uint32_t)unix_secs; + Note over SC: Step 2 将 RTC 时间换算为 Unix epoch 秒数 + SC->>SC: 累计 1970 至当前年份的整年天数(含闰年 366 天判定) + SC->>SC: 加上当年 1 月至当前月的累计天数 + SC->>SC: 加当月已过天数、时/分/秒 + SC->>SC: 用 int64_t 累加,避免中间溢出;结果截断存入 uint32_t(受 2038 限制,见第 12 节) + + Note over SC,HAL: Step 3 建立基准 + SC->>HAL: HAL_GetTick() + HAL-->>SC: 当前 tick + Note right of SC: s_base_tick = HAL_GetTick()
s_base_unix_secs = (uint32_t)unix_secs ``` 初始化后,所有后续取时都基于 Step 3 的基准推算,不再访问 RTC。