3 工程模板建立

工程模板建立

说明:课件示例主要基于 STM32F429ZGTx,当前西门子杯备赛主控是 GD32F470VET6。这份笔记保留“工程模板怎么搭”的思路,但芯片型号、库、烧录算法和时钟参数不能直接照抄。

这节课在讲什么

这节课在讲一件很实际的事:先把一个裸机工程模板搭完整,再去写功能代码。这个模板至少要满足几件事:时钟正确、调试口正确、工程结构清楚、Keil 能编译、烧录器能下载、出了问题能 debug。

结合当前备赛规则,这节课的重点不是 RTOS,而是裸机工程框架、调试能力和模块化习惯。RTOS 这一节先建立概念,当前比赛准备阶段仍然要以裸机开发为主。

先回顾:为什么先学工程模板

裸机与调度器的区别

维度 裸机开发 调度器开发
执行方式 线性执行,常见为阻塞式 按优先级调度,表现为并发
资源开销 比裸机更大
可预测性 强,时序好分析 取决于任务设计和调度策略
扩展性 功能一多就容易乱 更适合多任务系统
适合场景 功能单一、资源紧、实时性强 多任务、强响应、易扩展

课件里的“裸机是单车道公路,调度器是繁忙餐厅”这个比喻很好记。裸机不是“落后”,而是更直接、更可控;调度器也不是“天然效率更高”,它的价值主要在任务组织和响应能力。

当前阶段更该先会的是下面几件事:

  • 会搭工程,不是只会新建一个空项目。

  • 会用调试器,不是只会点下载。

  • 会把自己的代码和自动生成代码分开。

  • 老师没展开的地方要主动补问和验证,不能停在“看到过”。

工程创建总流程

可以先把这节课的操作链记成下面 7 步:

  1. 先确认芯片型号、板卡原理图、外部晶振频率。

  2. RCC / Clock Configuration 里把时钟配对。

  3. SYS 里把调试接口配对。

  4. Project Manager 里把工程生成方式配对。

  5. 理清 NVIC / SysTick 的作用和优先级原则。

  6. 生成 Keil 工程后,建立自己的 APP 目录和分组。

  7. 把烧录器、下载算法、调试器设置一次性打通。

时钟配置

一句结论:时钟决定系统“跑多快、哪些外设能跑、系统稳不稳”,工程模板第一步就是先确认板子的真实晶振和目标主频。

常见时钟源怎么理解

名称 含义 常见用途
HSI 内部高速时钟 启动快,方便,精度一般
HSE 外部高速时钟 主系统时钟常用来源,精度更高
LSI 内部低速时钟 独立看门狗等低速模块
LSE 外部低速时钟,常见为 32.768 kHz RTC、实时时钟
PLLCLK HSI/HSE 经过 PLL 倍频分频后的输出 常作为 SYSCLK

这里最容易混的是 HSEPLLCLK

  • HSE 是外部高速时钟源,本身是“输入源”。

  • PLLCLKHSEHSI 经过 PLL 处理后的“输出结果”。

  • 课件里的常见做法是:HSE -> PLL -> PLLCLK -> SYSCLK

本课的实际配置思路

本课的核心不是死记参数,而是先弄明白“板子上到底焊了什么晶振,再决定怎么配”。

先在 RCC 页面把高速外部时钟模式打开:

RCC 页面将 HSE 设为外部晶振模式

然后在时钟树页面确认输入频率、PLL 输出和总线分频。课件示例里,外部高速晶振输入是 25 MHz,最后把 SYSCLK 配到 180 MHz

时钟树中用 HSE 和 PLLCLK 配出 180MHz 系统时钟

外部晶振频率不是固定值,必须去看原理图或板卡说明。原稿里这个问题问得对:为什么要改下面那个,不是上面那个?因为上面是 LSE 32.768 kHz,下面才是主系统常用的 HSE 25 MHz

原理图里单独标出了 25MHz 外部高速晶振

原理图同时给出了 32.768kHz 和 25MHz 两组晶振,其中 25MHz 才是主系统 HSE

这一组图对应的结论可以直接记成:

  • 32.768 kHz 那组一般是 LSE,主要给 RTC。

  • 25 MHz 那组才是 HSE,通常参与主系统时钟配置。

  • 换板子时不要无脑照抄课件参数,先查原理图。

  • 时钟树不只是配 SYSCLK,还要顺带看 AHB / APB1 / APB2 是否超限。

为什么必须先配时钟

时钟配置的意义主要有四个:

  • 保证系统稳定,时钟错了很多外设会异常。

  • 决定系统性能,主频和总线频率直接影响执行速度。

  • 影响功耗,主频越高一般功耗越高。

  • 满足外设要求,比如串口、定时器、ADC 都依赖时钟。

本科阶段暂时不用把功耗放到第一位,但“时钟一定要和板子匹配”这件事必须重视。

SYS 配置

一句结论:大多数日常开发默认优先选 Serial Wire,因为它占用引脚少、兼容主流调试器、配置最省事。

SWD 和 JTAG 怎么选

方案 引脚占用 特点 适合场景
SWD 少,常用 SWDIO + SWCLK 简洁、稳定、日常开发最常用 ST-LINK、CMSIS-DAP、常规下载调试
JTAG 多,常见 4 到 5 根线 功能更完整,但占引脚 更复杂的调试场景

这里的 Serial Wire 不是“串口调试”,而是 SWD 调试协议。

在 CubeMX 里把 SYS 设成 Serial Wire 后,PA13PA14 会被调试接口占用:

PA13 和 PA14 被映射给 SWD 调试接口

这一步的实际意义有三点:

  • PA13 = SWDIOPA14 = SWCLK,后面不要再把它们当普通 GPIO 随便改。

  • 如果这里配错,Keil 里就算选了调试器,也可能读不到目标板。

  • CubeMX 里选的调试协议,要和 Keil 里选的调试器设置保持一致。

工程配置

一句结论:Project Manager 的目标不是“先把文件生出来”,而是生成一个后面还能反复迭代、重新生成也不容易把自己代码冲掉的工程。

Project 页面怎么配

原稿里“不要有中文”这个提醒是对的。更准确地说,项目名和专门的工程输出路径尽量避免中文、空格和特殊字符,能减少工具链兼容问题。

课件示例里的基本设置如下:

Project 页面示例:工程名、生成路径、Advanced 结构、MDK-ARM 工具链

这一步重点看这几个字段:

  • Project Name:尽量见名知意。

  • Project Location:尽量放在简洁路径下。

  • Application Structure:本课示例选 Advanced

  • Toolchain / IDE:示例选 MDK-ARM

Code Generator 页面怎么配

库文件建议选择“只复制必要文件”:

代码生成时只复制必要库文件

自动生成代码时,建议至少勾上下面两个选项:

  • Generate peripheral initialization as a pair of '.c/.h' files per peripheral

  • Keep User Code when re-generating

对应截图如下:

为每个外设单独生成 c 和 h 文件,并在重新生成时保留用户代码

这里可以直接记两个结论:

  • 为每个外设单独生成文件,后期维护和定位更清楚。

  • 只有写在 USER CODE BEGIN / END 区域里的内容,重新生成时才更容易被保留;自动生成区外面乱写,后面很容易被覆盖。

NVIC 与 SysTick

这一节课里没有深入配置,但概念不能空着。

一句结论:NVIC 管中断优先级,SysTick 常用作系统时基;即使暂时没配复杂中断,也要知道为什么它重要。

可以先记住三条:

  • 如果工程里用到了 HAL_Delay()、软件定时或系统时基,SysTick 优先级不能太低。

  • 中断服务函数要尽量短,耗时逻辑尽量放回主循环或任务里处理。

  • 中断优先级分配遵循“越实时、越关键,优先级越高”的原则。

当前阶段先知道“为什么以后一定会碰到它”,就够用了。

Keil 工程整理

一句结论:CubeMX 自动生成的工程只是起点,自己的业务代码最好单独放到 APP 目录,和 Core / Drivers 分开。

自动生成后会出现哪些目录

工程生成后,通常能看到下面这类目录和文件:

自动生成后的工程目录包含 Core、Drivers、MDK-ARM、.ioc 等内容

可以先把常见目录理解成这样:

目录/文件 作用
.ioc CubeMX 的外设和引脚配置文件
.mxproject 工程元数据
Core 主程序、启动、系统初始化、中断相关代码
Drivers HAL/CMSIS 等驱动和底层库
MDK-ARM Keil 工程文件和编译配置

为什么还要自己建 APP

原稿里“建立一个新的文件夹 APP,后期可细分”这个思路是对的。理由很简单:自动生成代码会反复变化,你自己的业务代码最好有单独地盘。

手动加上 APP 目录后,工程结构会更清楚:

在工程根目录里手动增加 APP 目录,专门放自己的业务代码

后面可以继续把 APP 拆成更细的模块,例如:

  • bsp_led

  • bsp_key

  • bsp_uart

  • service_protocol

  • app_main

Keil 里需要补的两件事

第一件事,是把 APP 路径加到包含目录里:

在 Keil 的 Include Paths 里加入 APP 目录

第二件事,是在工程分组里单独建一个 APP group,再把你的 .c/.h 文件加进去:

在 Keil 工程分组中单独建立 APP 组

这样整理的好处是:

  • 自动生成代码和自己写的代码边界清楚。

  • 重新生成工程时,不容易把业务代码搞乱。

  • 后面做模块化移植时,直接搬 APP 更方便。

烧录与调试

一句结论:烧录器不只是“把程序写进去”的工具,它更重要的价值是帮你判断“电脑、调试器、芯片”这条链路到底通没通。

烧录器的作用

烧录器至少做两件事:

  • 把编译好的 .hex / .bin / .elf 写进芯片的 Flash。

  • 作为调试器读取芯片状态、断点调试、排查问题。

常见选择可以先这样记:

烧录器 特点 适合场景
ST-LINK 官方生态友好,便宜,常见 STM32 入门、学习、日常开发
J-LINK 速度快、功能强、覆盖广 专业开发、复杂调试
DAPLink / CMSIS-DAP 开源、灵活、成本低 创客、教育、开放工具链

结合当前西门子杯备赛规则:录制演示视频时不能依赖 DAP 的虚拟串口,所以后面做比赛方案时,下载链路和串口方案要分开考虑。

接线时至少记住什么

最常见的是 SWD 接口,至少要确认这几根线:

  • SWDIO

  • SWCLK

  • GND

  • VTref / VCC:不是每次都强制,但强烈建议接

能不能下载,往往不是代码问题,而是下面几项有没有对上:

  • 调试器型号对没对。

  • 驱动装没装。

  • 协议选的是 SWD 还是别的。

  • 目标板有没有供电。

  • GNDVTref 有没有接好。

Keil 里的基础配置

先在 Device 里把芯片型号选准:

Keil 中先选择精确的目标芯片型号

再在 Debug 页选择你实际在用的调试器。原稿截图里用的是 CMSIS-DAP Debugger,如果你手上是 ST-LINKJ-LINK,这里也要对应改:

在 Debug 页面选择实际使用的调试器

下载算法页面通常至少勾上 ProgramVerifyReset and Run

Flash Download 页面里启用 Program、Verify 和 Reset and Run

到这一步,如果能识别到目标芯片或 ID CODE,说明“电脑 → 调试器 → 芯片”这条链基本打通了。

常见报错先怎么查

原稿里的这几张报错图很有价值,因为它们代表的是最常见的两类问题。

No Debug Unit Device found 这类报错,通常先查“电脑认没认出调试器”:

CMSIS-DAP 报 No Debug Unit Device found,先查驱动、USB 连接和调试器本体

ST-LINK connection error 这类报错,通常先查“调试器到目标芯片这段链路通没通”:

ST-LINK connection error 多半要回头查供电、接线、复位方式和时钟

排查时可以按这个顺序来:

  1. 先确认目标板上电。

  2. 再确认 SWDIO / SWCLK / GND / VTref 接线。

  3. 确认 CubeMX 和 Keil 里都用了同一套调试协议。

  4. 确认 Keil 的 Device 和 Flash Algorithm 选的是正确芯片。

  5. 如果还不通,降低 SWD Clock,或尝试 Connect under Reset

  6. 某些情况下可以切换 Reset 方式,例如 SYSRESETREQ,看哪种更稳定。

补一条很重要的迁移提醒:

  • 课件示例是 STM32F429

  • 当前备赛主控是 GD32F470

  • 如果你把 GD32 板子按 STM32F429 的下载算法、芯片型号、库文件去配,出问题是正常的。

本节课结论

  • 工程模板不是“先把文件生成出来”,而是先把时钟、调试、工程结构和下载链路全部打通。

  • 时钟配置里最关键的不是背参数,而是先确认板子的真实 HSE 晶振频率,再决定 PLLCLK 和目标主频。

  • SWD 是日常最常用的调试方式,记住它会占用 PA13 / PA14

  • 自己的代码尽量放在 APP 目录和 USER CODE 区域,不要和自动生成代码混写。

  • 烧录器既是下载工具,也是定位问题的入口;能读到目标芯片,才说明链路真的通了。

后续学习建议

  • 用当前比赛主控 GD32F470VET6 再完整走一遍这套模板,不要停留在 STM32 课件示例上。

  • APP 目录继续细分成模块,练习“一个模块一个 .c/.h”的写法。

  • 单独补 头文件保护启动文件SysTick/NVIC寄存器版外设初始化 这几块。

  • 当前阶段单纯背代码价值不高,更重要的是会搭工程、会移植、会上板验证、会排错。

  • 老师没展开的地方,要主动去问、去查、去试,这部分往往才是后面真正决定你工程能力的内容。