工程结构
项目文件浅说明

① 组HALLIB下面存放的是ST官方提供的HAL库文件,每一个源文件stm32f4xx_hal_ppp.c
都对应一个头文件 stm32f4xx_hal_ppp.h。分组内的源文件我们可以根据工程需要添加和删除。
这里对于跑马灯实验,我们需要添加 11 个源文件。
② 组 CORE 下面存放的是固件库必须的核心头文件和启动文件。这里面的文件用户不需要
修改。大家可以根据自己的芯片型号选择对应的启动文件。
③ 组 SYSTEM 是 ALIENTEK 提供的共用代码,这些代码在第五章都有详细讲解。
④ 组 HARDWARE 下面存放的是每个实验的外设驱动代码,他的实现是通过调用 HALLIB
下面的 HAL 库文件函数实现的,比如 led.c 中函数调用 stm32f4xx_hal_gpio.c 内定义的函数对 led
进行初始化,这里面的函数是讲解的重点。后面的实验中可以看到会引入多个源文件。
⑤ 组 USER 下面存放的主要是用户代码。但是 system_stm32f4xx.c 文件用户不需要修改,
同时 stm32f4xx_it.c 里面存放的是中断服务函数,这两个文件的作用在 3.3 节有讲解。main.c 函
数主要存放的是主函数了。
项目运行前置
USE_HAL_DRIVER,STM32F429xx

来对于 STM32F429 系列的工程,还需要添加全局宏定义标识符,所谓全局宏定义标识符,就是在工程中任何地方都可见
包含头文件

这里大家需要注意,这里添加的路径必须添加到头文件所在目录的最后一级。比如在 SYSTEM
文件夹下面有三个子文件夹下面都有.h 头文件,这些头文件在工程中都需要使用到,所以我们
必须将这三个子目录都包含进来。这里我们需要添加的头文件路径包括:\CORE, \USER\,
\SYSTEM\delay ,\SYSTEM\usart,SYSTEM\sys 以及\HALLIB\Inc。这里还需要提醒大家,HAL
库存放头文件子目录是\HALLIB\Inc,不是 HALLIB\Src,其次很多朋友都是这里弄错导致报
很多奇怪的错误。
头文件包含准则
仅在必要时在头文件中包含其他头文件:当头文件中的声明直接依赖另一个头文件的内容时(如使用某个类或结构体的定义),必须在头文件中包含该头文件。否则,应尽量在源文件中包含。
优先使用前向声明:如果可能,使用前向声明代替包含头文件,特别是在头文件中使用指针或引用时。
减少头文件依赖:尽量让头文件独立,减少对其他头文件的依赖。这可以通过前向声明或接口设计来实现,从而降低编译时间和耦合度。
源文件包含实现所需的头文件:源文件需要包含所有其实现所需的头文件,包括对应的头文件(例如B.cpp包含B.h),以及B.h中未包含但实现需要的其他头文件。
处理循环依赖:如果出现头文件之间的循
环依赖,可能需要重新设计代码结构,或者使用前向声明来打破循环。
重复定义:只要包含了#ifndef #endif就不会发生
#incldue“main.h”
#include “gpio.h” gpio.h里面又包含了main.h,但不会影响
else和if
清晰性:else if更直观地表达了“或者”的逻辑,代码意图更明确,避免了潜在的逻辑错误。
性能:虽然性能差异微乎其微,但在复杂条件下,else if可以避免不必要的条件检查。
互斥性用else if
什么时候可以用if替换else if?
只有在以下情况下可以用独立if代替else if,且不会改变逻辑:
条件之间没有依赖关系,且不需要互斥性。
extern实现变量跨文件使用
为什么能跨文件使用?
这种机制依赖于以下几点:
外部链接
在 C 中,未使用 static 修饰的全局变量(如 uint32_t usy)默认具有外部链接(external linkage)。这意味着它可以在整个程序中通过名称访问,只要其他文件正确声明它(用 extern)。
编译器在编译每个 .c 文件时独立工作,生成目标文件(.o)。链接器随后将这些目标文件合并,解析 usy 的地址,确保 main.c 和 stm32g4xx_it.c 操作的是同一个变量。
2.链接器的魔法
在编译阶段,stm32g4xx_it.c 中的 usy 是一个未解析的符号。
在链接阶段,链接器会扫描所有目标文件,找到 main.c 中定义的 usy,并将所有对 usy 的引用指向同一个内存地址。
只要使用当前文件extern声明了,并且在任意文件里有定义,使用都不会报错
函数也是一样,函数默认extern,不用包含任何头文件都行
#include <stdio.h>
void say_hello() {
printf("Hello from func.c!\n");
}
``>
---
### 👉 `main.c` —— 声明并调用该函数,但**不包含任何头文件**
```c
// 不 include 任何东西
// 直接声明函数(不写 extern 也行)
// 这里我们写 extern 来体现“极端共享”
extern void say_hello();
int main() {
say_hello();
return 0;
}
