目录
- 前言
- 一、GPIO寄存器体系与硬件结构解析
-
- [1.1 GPIOx与寄存器组的关系](#1.1 GPIOx与寄存器组的关系)
- [1.2 常见GPIO寄存器类型](#1.2 常见GPIO寄存器类型)
- [1.3 配置寄存器(CRL/CRH)的位结构](#1.3 配置寄存器(CRL/CRH)的位结构)
- [1.4 输出数据寄存器(ODR)工作机制](#1.4 输出数据寄存器(ODR)工作机制)
- [二、借助 STM32CubeMX 的相关配置点亮 LED 等](#二、借助 STM32CubeMX 的相关配置点亮 LED 等)
-
- [2.1 开启调试接口:SWD 配置](#2.1 开启调试接口:SWD 配置)
- [2.2 项目生成设置:Project Manager](#2.2 项目生成设置:Project Manager)
- [2.3 自动打开工程与代码结构解析](#2.3 自动打开工程与代码结构解析)
- [2.4 编写业务代码与编译报错处理](#2.4 编写业务代码与编译报错处理)
- [2.5 下载器配置与程序烧录](#2.5 下载器配置与程序烧录)
- 结语


🎬 云泽Q :个人主页
🔥 专栏传送入口 : 《C语言》《数据结构》《C++》《Linux》《蓝桥杯系列》《笔试算法》《AI赋能》《STM32》
⛺️遇见安然遇见你,不负代码不负卿~
前言
大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~
一、GPIO寄存器体系与硬件结构解析
GPIOx除了我们在前面文章学习输出的时候,见到的输出寄存器,还有其他寄存器,通过配置这些寄存器,就可以完成对GPIOx的相关配置,就如同对洗衣机,空调进行参数设定,然后这些家用电器就按照你预设的参数进行工作一般

1.1 GPIOx与寄存器组的关系
STM32的每个GPIO端口(如GPIOA、GPIOB......GPIOG)都是独立的硬件模块,各自拥有一套完整的寄存器组,用于控制其内部16个引脚(如PA0--PA15)。寄存器并不隶属于单个引脚,而是属于整个GPIOx端口,通过寄存器中的特定位(bit)来控制对应引脚的行为。

例如,GPIOA的输出数据寄存器(ODR)是一个32位寄存器,但仅低16位有效,每一位对应一个物理引脚(ODR0 → PA0,ODR1 → PA1,......,ODR15 → PA15)。

由于这是中文版的参考手册,所以里面内容滞后一些,GPIO端口是A...E,英文版就是A...G了,不过这并不影响前期我们使用,对于计算机领域来说,很多技术都是具有前后包容性的。

1.2 常见GPIO寄存器类型
-
配置寄存器:包括CRL(Configuration Register Low)和CRH(Configuration Register High),分别用于配置引脚0--7和8--15。

-
输出数据寄存器(ODR, Output Data Register):用于设置引脚输出高/低电平。

-
输入数据寄存器(IDR, Input Data Register):用于读取引脚当前电平状态。
-
设置/清除寄存器(BSRR, Bit Set/Reset Register):用于原子操作地设置或清除特定位。
-
锁定寄存器(LCKR)等其他辅助寄存器(课程中未深入讲解)。
1.3 配置寄存器(CRL/CRH)的位结构
每个引脚的配置需要4个比特位:低2位为MODEy,高2位为CNFy(y为引脚编号)。
MODEy决定引脚是输入还是输出:
-
00:输入模式; -
01/10/11:输出模式(具体速度由其他机制决定,这里先不展开说)。
CNFy在输出模式下决定输出类型:
-
00:通用推挽输出; -
01:通用开漏输出; -
10:复用推挽输出; -
11:复用开漏输出。
CRL负责引脚0--7,CRH负责引脚8--15,两者共同覆盖GPIOx全部16个引脚。
1.4 输出数据寄存器(ODR)工作机制
ODR是32位寄存器,低16位每一位对应一个引脚的输出电平。向ODR的某一位写入1,对应引脚输出高电平;写入0,则输出低电平。该寄存器支持按字(32位)访问,不允许半字或字节访问。

二、借助 STM32CubeMX 的相关配置点亮 LED 等
这里就以我的开发板为例来说了:

通过查我所购买开发板的手册可以看到LED4对应MCU上的连接的引脚是PF8,我们这里就默认按通用开漏输出来配置


2.1 开启调试接口:SWD 配置

我在开发板上预留了仿真器调试接口,使用的是 SWD (Serial Wire Debug) 模式。在 STM32CubeMX 的配置界面中,需要在 System Core -> SYS -> Debug 下拉菜单中,明确选择 "Serial Wire"。
⚠️ 注意!这一步非常非常重要。
如果没有修改这里,而是使用了默认的 No Debug,会出现一个经典的"坑":第一次烧录程序可以成功,但是后续再次烧录时就会失败,甚至导致芯片无法连接(俗称"锁死"或"烧录丢失")。这是因为默认配置下,调试引脚被释放作为普通 GPIO 使用,导致调试器无法再次介入。
很多初学者容易混淆 DAP Link 和 SWD,这里给大家做一个形象的类比:
- DAP (Debug Access Port) :全称是调试访问端口,它是一个物理仿真器硬件。你可以把它想象成"考试的时候坐在座位上的同学本人"。
- SWD (Serial Wire Debug) :全称是串行线调试,它是一种调试通信协议。你可以把它想象成"用来传递纸条的通道 + 约定好的手势或者暗号"。
两者的关系是: DAP Link 这种硬件仿真器,是通过 SWD 这种协议通道与目标芯片进行通信的。

这就相当于开启了对应GPIO相关寄存器对于该针脚的输出模式

在前面将 Debug 选项从默认的 No Debug 改为 Serial Wire 时,软件就会自动将 PA13 和 PA14 这两个引脚分配给 SWD 调试功能,它们是SWD 调试专用引脚
- PA13 → SWDIO(Serial Wire Data I/O):串行数据线,用于调试器和芯片之间传输数据。
- PA14 → SWCLK(Serial Wire Clock):串行时钟线,提供调试通信的同步时钟。
现阶段了解一下即可
这也是为什么前面强调必须配置 Serial Wire 调试模式------如果你不配置,这两个引脚不会被锁定为调试功能,第一次烧录后它们就可能被你的程序当作普通 GPIO 使用,导致调试器再也连不上芯片(即所谓的"烧录后锁死"问题)

据我们的硬件原理图,控制 LED 的引脚是 PF8,由前面的文章可知,我们在开漏输出模式下,输出数据寄存器如果是0就会导通形成回路,LED就可以被点亮。如果是1就不会导通,我们这里默认配置为不会导通,并选择开漏输出模式,输入模式以及输出速度那里也暂时不用管
在 STM32CubeMX 右侧的芯片引脚图上,我们找到绿色的 PF8 引脚,用鼠标左键点击它,会弹出一个绿色的功能选择下拉菜单:
这里只说两个比较重点的选项:
- Reset_State:复位状态(即不使用该引脚,取消其配置)。
- GPIO_Output:通用输出模式(我们今天要点灯,所以必须选择这个)。
-
GPIO output level (输出电平)
作用:决定芯片刚上电复位、程序还没跑起来时,这个引脚的默认电平状态。
选项:High(高电平)或 Low(低电平)。
-
GPIO mode (GPIO 模式)
作用:决定引脚内部的输出电路结构。
选项:
-
- Output Push Pull (推挽输出)
-
- Output Open Drain (开漏输出)
-
GPIO Pull-up/Pull-down (上下拉配置)
作用:决定引脚在空闲或输入状态下的默认电平,防止引脚悬空引入外界干扰。
选项:No pull-up and no pull-down(无上下拉)、Pull-up(上拉,默认高电平)、Pull-down(下拉,默认低电平)。这个选项通常保持默认的"无上下拉"即可。
-
Maximum output speed (最大输出速率)
作用:限制引脚电平翻转的最高频率。
选项:Low (2MHz)、Medium (10MHz)、High (50MHz)。
这里点个 LED 选 Low 就可以了。
-
User Label (用户标签)
作用:这是个极其好用的功能!你可以给它起一个人性化的名字,比如 LED_RED 或 BEEP。
好处:配置好之后,STM32CubeMX 会在生成的代码中自动帮你定义一个宏。以后你在写代码时,直接调用
HAL_GPIO_WritePin(LED_RED, GPIO_PIN_SET)即可,不用去记GPIOF, GPIO_PIN_8了。


2.2 项目生成设置:Project Manager

配置好引脚和调试接口后,我们紧接着就要进入工程生成的环节了。这一步决定了我们后续代码编写的载体和编译环境。
请点击顶部菜单栏的 Project Manager 选项卡,这里是配置项目属性的核心区域。在 Project 这一栏中,有几个参数需要特别注意:
Project Name:输入你的项目名称,例如 LED_test_08_07。Project Location:这是项目保存的根目录。建议养成好习惯,把代码文件统一放在专门的文件夹里(例如D:\programming_file\STM32\code_project),不要散落在桌面上。Toolchain / IDE:这个下拉菜单至关重要。因为我们后续要使用 Keil 软件来编写和调试代码,所以这里必须选择 MDK-ARM。这里的 MDK-ARM 指的就是 Keil 的开发环境。如果你选了其他的(如 IAR 或 STM32CubeIDE),生成的工程格式将不兼容 Keil。Minimum Heap/Stack Size:堆栈大小设置,一般保持默认即可。
2.3 自动打开工程与代码结构解析
当上面各参数确认无误后,点击右上角醒目的 GENERATE CODE 按钮。STM32CubeMX 会根据之前的图形化配置,自动生成底层的初始化代码和工程文件。

代码生成完毕后,会弹出提示框显示 The Code is successfully generated。此时点击 Open Project,系统会自动查找电脑上的 Keil 软件并直接打开生成的工程。

打开 Keil 后,左侧的项目目录树中有一个核心文件夹:Drivers/STM32F1xx_HAL_Driver。这里面包含了 ST 官方提供的 HAL 库源文件(如 stm32f1xx_hal_gpio.c 等),是我们调用库函数的基础。
双击打开 main.c,我们可以看到自动生成的代码框架。这里有几个关键点需要理解:
-
用户代码保护区 :你会看到很多类似
/* USER CODE BEGIN ... */和/* USER CODE END ... */的注释。请务必把你的代码写在这些注释之间! 如果你写在外面,下次重新生成代码时,你的代码会被覆盖删除。 -
主函数流程:
HAL_Init();:初始化 HAL 库,配置系统滴答定时器(Systick)。SystemClock_Config();:配置系统时钟,比如设置主频为 72MHz。MX_GPIO_Init();:这是 CubeMX 根据我们的引脚配置自动生成的 GPIO 初始化函数。while(1):整个 MCU 只会被你烧写的程序独占运行,你的程序必须是一个周而复始的死循环,防止程序跑飞,这也是常规软件的运行模式。
2.4 编写业务代码与编译报错处理
现在我们要让 LED 亮起来。假设我们要控制 PF8 引脚输出低电平来点亮 LED,可以在 MX_GPIO_Init(); 之后,while(1) 之前添加如下代码:
c
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8, GPIO_PIN_RESET);
/* USER CODE END 2 */

写好代码后,点击工具栏上的 Build (F7) 按钮进行编译。这时候,你很可能会遇到一个红色的报错信息:
这是什么原因呢?
这是因为新版本的 Keil MDK(V6 及以上)默认不再内置老旧的 Compiler V5,而是使用了新的 Compiler V6 (AC6)。但 STM32CubeMX 生成的工程默认配置往往还指向 V5,导致找不到编译器。
解决方法非常简单:
- 点击工具栏上的"魔术棒"图标(Options for Target)。
- 切换到
Target选项卡。 - 找到右侧的
ARM Compiler:下拉框。 - 将其从
Use default compiler version 5改为Use default compiler version 6。 - 点击 OK,再次编译。

此时再看下方的 Build Output 窗口,显示 0 Error(s), 0 Warning(s),说明编译成功了。

点击图标2后又会弹出几个错误,再次点击魔法棒
2.5 下载器配置与程序烧录
编译通过后,我们需要把程序下载到芯片里。这涉及到下载器的配置。
- 再次点击"魔术棒"图标,切换到 Debug 选项卡。
- 在右侧的下拉框中,选择你使用的调试器。如果你使用的是常见的 DAPLink 或类似的 SWD 调试器,通常选择
CMSIS-DAP Debugger。
注:如果是 J-Link 就选 J-Link,ST-Link 就选 ST-Link。 - 点击 OK 保存设置。

最后,点击工具栏上的 Download (Load) 按钮(或者按 F8)。观察下方的输出窗口,如果出现以下信息:

以上是一个初步的利用STM32CubeMX生成所需源代码的演示过程以及可能出现的问题的解决办法,里面有很多地方由于文章篇幅原因都没有说清楚或者没有说,下篇文章将会一一带你解开其中的问题
结语
