3. 开发环境搭建
拿到一个TouchGFX工程,很多人第一反应是「这么多文件夹,从哪下手?」
说实话,我刚开始接触时也懵过。目录里又是 Target 又是 generated,看着就头大。但摸清规律后你会发现,这套结构其实很清晰——它把硬件、平台、应用三层剥开了,各管各的事。
这一章,我就带你把这棵「目录树」从头捋一遍。
3.1 顶层目录:一眼看穿骨架
一个典型的TouchGFX项目,顶层大概长这样:
MyProject/
├── Core/ # 应用层核心代码
├── TouchGFX/ # TouchGFX 框架相关
├── Drivers/ # 硬件驱动(HAL层)
├── Middlewares/ # 中间件(RTOS、文件系统等)
├── project.eww # IAR 工程文件
└── .cproject / .project # 其他IDE配置
嗯,这里要注意:TouchGFX 文件夹才是我们的主战场。它里面又细分了几个子目录:
| 子目录 | 作用 | 我常改它吗? |
|---|---|---|
app/ |
应用层代码(屏幕、逻辑、Model) | 天天改 |
generated/ |
TouchGFX Designer 自动生成的代码 | 几乎不动 |
gui/ |
UI 视图层(View、Presenter) | 经常改 |
target/ |
平台层与HAL层适配代码 | 偶尔改 |
generated/ 目录加入.gitignore。因为它是自动生成的,多人协作时容易冲突,而且你根本不需要手动改它。
3.2 三层架构:HAL层、平台层、应用层
TouchGFX 把整个项目拆成了三层。说白了,就是「硬件—中间件—业务」的经典套路。但它的边界划得特别清楚,我画了张图帮你理解:
3.3 HAL层:跟硬件打交道的「翻译官」
HAL层在 TouchGFX/target/ 目录下。它的任务很简单:把TouchGFX的通用接口,翻译成你板子上的具体硬件操作。
举个例子,TouchGFX要刷屏时,会调用一个叫 flushFrameBuffer() 的函数。HAL层就得把这个函数实现成「往LTDC数据寄存器里写像素」。不同的MCU,写法完全不同。
HAL层核心文件:
STM32F7HAL.cpp/STM32H7HAL.cpp— 具体芯片的HAL实现TouchGFXHAL.cpp— TouchGFX框架与HAL的胶水代码OSWrappers.cpp— 操作系统抽象(信号量、互斥锁等)
setFrameBufferStartAddress() 没正确配置——帧缓冲地址指向了SRAM的无效区域。从那以后,我每次移植都会先打印帧缓冲地址,确认它落在有效的内存区间。
3.4 平台层:操作系统的「遮羞布」
平台层在 TouchGFX/target/ 里也有份,但它更偏向软件抽象。如果你用了FreeRTOS,平台层会帮你封装好任务创建、队列、信号量等接口。
TouchGFX本身不依赖任何特定RTOS,它通过 OSWrappers 这个抽象层来调用底层的OS服务。你换RTOS时,只需要重写 OSWrappers.cpp 里的几个函数就行。
| OSWrappers 函数 | 作用 | 对应RTOS实现 |
|---|---|---|
initialize() |
初始化OS资源 | 创建信号量、队列 |
takeFrameBufferSemaphore() |
获取帧缓冲访问权 | xSemaphoreTake() |
giveFrameBufferSemaphore() |
释放帧缓冲访问权 | xSemaphoreGive() |
signalVSync() |
通知垂直同步事件 | xQueueSend() |
说白了,平台层就是给TouchGFX套了一层「OS无关」的外壳。你换RTOS时,改这一个文件就够了。
3.5 应用层:你的业务代码大本营
应用层在 TouchGFX/app/ 和 TouchGFX/gui/ 里。这是你每天打交道最多的地方。
- Model: 数据模型,负责与后端(传感器、通信等)交互。我习惯把所有的业务逻辑都塞在Model里,View只负责显示。
- View: 界面显示,由TouchGFX Designer生成。你可以在里面添加自定义控件,但核心布局建议用Designer拖出来。
- Presenter: 中间人,接收View的事件,调用Model的接口。说白了,就是「View不知道Model,Model不知道View,Presenter两头传话」。
3.6 避坑指南:目录结构常见问题
- 不要手动修改
generated/目录下的文件。 你改了,Designer一重新生成,全没了。我见过有人直接在generated/Screen1ViewBase.cpp里加代码,结果下次改UI时全部丢失。 - HAL层的配置在
TouchGFX/target/里,别去Drivers/里乱翻。Drivers/是STM32CubeMX生成的底层驱动,TouchGFX的HAL层会调用它们,但你不应该直接改。 - 平台层的
OSWrappers.cpp一定要跟你的RTOS匹配。 如果你用FreeRTOS,却用了ThreadX的封装,编译不会报错,但运行时帧缓冲访问会死锁。 - 应用层的
Model.hpp是全局单例。 所有屏幕共享同一个Model实例。我早期犯过错误:在每个View里各自维护一份数据,结果屏幕切换时数据不同步。
嗯,目录结构就这些。你只要记住「HAL管硬件、平台管OS、应用管业务」这个口诀,以后找文件就不会迷路了。