深入浅出 STM32(八):GPIO 寄存器底层原理与 CubeMX 点亮 LED 实战

目录

  • 前言
  • 一、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 时,软件就会自动将 PA13PA14 这两个引脚分配给 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:通用输出模式(我们今天要点灯,所以必须选择这个)。
  1. GPIO output level (输出电平)

    作用:决定芯片刚上电复位、程序还没跑起来时,这个引脚的默认电平状态。

    选项:High(高电平)或 Low(低电平)。

  2. GPIO mode (GPIO 模式)

    作用:决定引脚内部的输出电路结构。

    选项:

    • Output Push Pull (推挽输出)
    • Output Open Drain (开漏输出)
  1. GPIO Pull-up/Pull-down (上下拉配置)

    作用:决定引脚在空闲或输入状态下的默认电平,防止引脚悬空引入外界干扰。

    选项:No pull-up and no pull-down(无上下拉)、Pull-up(上拉,默认高电平)、Pull-down(下拉,默认低电平)。这个选项通常保持默认的"无上下拉"即可。

  2. Maximum output speed (最大输出速率)

    作用:限制引脚电平翻转的最高频率。

    选项:Low (2MHz)、Medium (10MHz)、High (50MHz)。

    这里点个 LED 选 Low 就可以了。

  3. 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,我们可以看到自动生成的代码框架。这里有几个关键点需要理解:

  1. 用户代码保护区 :你会看到很多类似 /* USER CODE BEGIN ... *//* USER CODE END ... */ 的注释。请务必把你的代码写在这些注释之间! 如果你写在外面,下次重新生成代码时,你的代码会被覆盖删除。

  2. 主函数流程:

    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,导致找不到编译器。

解决方法非常简单

  1. 点击工具栏上的"魔术棒"图标(Options for Target)。
  2. 切换到 Target 选项卡。
  3. 找到右侧的 ARM Compiler: 下拉框。
  4. 将其从 Use default compiler version 5 改为 Use default compiler version 6
  5. 点击 OK,再次编译。

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

点击图标2后又会弹出几个错误,再次点击魔法棒

2.5 下载器配置与程序烧录

编译通过后,我们需要把程序下载到芯片里。这涉及到下载器的配置。

  1. 再次点击"魔术棒"图标,切换到 Debug 选项卡。
  2. 在右侧的下拉框中,选择你使用的调试器。如果你使用的是常见的 DAPLink 或类似的 SWD 调试器,通常选择 CMSIS-DAP Debugger
    注:如果是 J-Link 就选 J-Link,ST-Link 就选 ST-Link。
  3. 点击 OK 保存设置。

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

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

结语

相关推荐
单片机杂货铺15 小时前
基于单片机的智能粮仓控制系统设计与实现
stm32·单片机·嵌入式硬件·物联网·计算机外设·51单片机·课程设计
指尖的爷15 小时前
RKNN转化环境搭建(rknn_toolkit2新版本)
嵌入式硬件·深度学习·物联网·目标检测
梁朝辉16 小时前
滴泪的曲线(Curved)还是直线(Line)什么区别,都应用于什么场景!
嵌入式硬件·硬件工程
clear sky .17 小时前
stm32H7进入HardFault_Handler机制
stm32·单片机·嵌入式硬件
小僧景贤18 小时前
STM32 GPIO 详解(含寄存器、HAL 库、电气特性、低功耗深度剖析)
stm32·单片机·嵌入式硬件
远翔调光芯片^1382879887220 小时前
从参数到应用:FP7208如何以0.2V精密反馈提升LED驱动性能
科技·单片机·嵌入式硬件·智能家居·能源
碧海银沙音频科技研究院21 小时前
4 BES2710编译环境搭建方法
嵌入式硬件·算法
别催小唐敲代码1 天前
STM32 定时器学习笔记:TIM 架构、输入捕获与 PWM 一篇讲透
笔记·stm32·学习
csdn杰哥1 天前
瑞萨单片机AI教程【六】导入外部电机状态数据训练模型
人工智能·单片机·嵌入式硬件·瑞萨·ra6m5