STM32操作GPIO外设(点亮LED灯)的两种方式——使用官方库函数或直接操作寄存器
STM32操作外设(点亮LED灯)的两种方式
准备工作:
- 硬件gec6818开发板、搭载stm32f407zet6芯片
- keil项目模板,准备好官方库函数
- 官方提供的《STM32f407数据手册》、《STM32F4xx中文参考手册》
- 《gec6818开发板原理图》
一、使用ST公司官方提供的库函数
首先获取LED0所使用的芯片引脚,由原理图可以查得LED灯使用的芯片引脚为PF9

PF9意为GPIO外设下F端口第9个引脚(引脚序号为0~15,共16个),根据官方给出的示例代码可以很容易地写出:
/********************************************************************************
* @file GPIO/GPIO_IOToggle/main.c
* @author MCD Application Team
* @version V1.4.0
* @date 2025/4/27
* @brief 使开发板上的LED0灯亮
******************************************************************************/
// ST公司提供的库函数
#include "stm32f4xx.h"
// 定义初始化对象
GPIO_InitTypeDef GPIO_InitStructure;
int main()
{
/* 打开外设时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
/* 配置初始化对象 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // 设置要操作的引脚编号
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 设置引脚模式为输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 设置引脚类型为推挽模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 设置速度为100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 设置上拉还是下拉,即引脚不给输出信号时的默认电平,上拉为高电平,下拉为低电平,nopull为浮空
/* 初始化*/
GPIO_Init(GPIOF, &GPIO_InitStructure);
while(1)
{
// 设置PF8为高电平
// 为什么直接取GPIOF下的BSRRL就能找到对应的比特位呢?(第二节)
GPIOF->BSRRL = GPIO_Pin_9; // GPIOx_BSRR 为置位/复位寄存器(32位),高16位用作复位(BSRRH),低16位用作置位(BSRRL)
//置位的第二种写法
GPIO_SetBits(GPIOF, GPIO_Pin_8);
}
}
问:ST公司提供的库函数使用起来非常方便简洁,但是底层是靠什么逻辑呢?
即答:底层靠预先封装好的寄存器地址寻址
所以,如果操作上完全不使用库函数也是可以直接做到点亮LED0的,只要能找到正确的寄存器地址并赋值。
二、直接使用寄存器地址操作寄存器
首先,地址映射规则由芯片厂商固化,我们可以通过《STM32f407数据手册》先看看STM32F407ZET6整体的编址结构:

找到第4章——Memory mapping,我们可以发现整体编址范围从0x0000_00000xFFFF_FFFF(共4G),分配给外设的部分为0x4000_00000x5FFF_FFFF,即:
- 外设基地址为0x4000_0000
放大这部分可以看到这其中包含了四条总线:AHB2、AHB1、APB2、APB1,查询图后方的表格可知GPIOF位于AHB1总线上,且所属地址为0x4002_1400~0x4002_17FF,:

所以:
- AHB1下的GPIOF的基地址为0x4002_1400
再往下深入的话,数据手册就派不上用场了,接着使用《STM32F4xx中文参考手册》查看具体的寄存器地址,找到7.4章节,其中可以找到每个端口下的寄存器的偏移地址:

逐个查询可知,本次需要配置的几个寄存器的偏移地址如下:
- 端口模式:0x00
- 端口输出类型:0x04
- 端口输出速度:0x08
- 端口上拉/下拉:0x0C
- 端口置位/复位:0x18
问:现在知道寄存器的基地址和偏移地址了,只要用指针取地址下的值就可以操作寄存器了,但是现在要写什么数据进寄存器才能得到我们想要的结果呢?
端口下的每一个寄存器有32位,每2位对应一个引脚配置,例如文档所述的端口模式寄存器:

MODERy中的y即每个端口下的引脚序号(0~15),2个bit可以设置4种状态,因此我们想要设置9号引脚的端口模式为通用输出模式的话,只需设置端口模式寄存器的MODER9(18和19位)为01即可。然后总结一下我们需要设置的参数:
(等号左边为位号,右边为电平值)
- 端口模式:2*9 : 2*9+1 = 0 : 1
- 端口输出类型:9 = 0
- 端口输出速度:2*9 : 2*9+1 = 1 : 1
- 端口上拉/下拉:2*9 : 2*9+1 = 0 : 0
- 端口置位/复位:9 : 25 = 0 : 1
除了以上GPIO寄存器,接下来还有最重要的一个RCC寄存器需要设置,用来打开端口的时钟,这样才能成功配置端口。同样的查询步骤可以得到RCC AHB1外设时钟使能寄存器的地址和要设置的电平:

- 基地址0x4002_3800,偏移地址0x30,5 = 1
所有数据查询完毕,接下来终于可以着手写代码了:
/********************************************************************************
* @file GPIO/GPIO_IOToggle/main.c
* @author MCD Application Team
* @version V1.4.0
* @date 2025/4/27
* @brief 用直接操作寄存器的方式使开发板上的LED0灯亮
******************************************************************************/
#define RCC_AHB1Periph_GPIOF (*(volatile unsigned int*)(0x40023800 + 0x30)) // RCC AHB1外设时钟使能寄存器
#define GPIOF_MODER (*(volatile unsigned int*)(0x40021400 + 0x00)) // 端口模式
#define GPIOF_OTYPER (*(volatile unsigned int*)(0x40021400 + 0x04)) // 端口输出类型
#define GPIOF_OSPEEDR (*(volatile unsigned int*)(0x40021400 + 0x08)) // 端口输出速度
#define GPIOF_PUPDR (*(volatile unsigned int*)(0x40021400 + 0x0C)) // 端口上拉/下拉
#define GPIOx_BSRR (*(volatile unsigned int*)(0x40021400 + 0x18)) // 端口置位/复位
int main()
{
/* 打开外设时钟 */
RCC_AHB1Periph_GPIOF |= 1 << 5;
/* 设置引脚模式为输出模式 */
GPIOF_MODER &= ~(1 << 9 );
/* 设置引脚类型为推挽模式 */
GPIOF_OTYPER |= 1 << 2*9 ;
GPIOF_OTYPER |= 1 << (2*9 + 1);
/* 设置输出速度为100MHz */
GPIOF_OSPEEDR &= ~(1 << 2*9 );
GPIOF_OSPEEDR |= 1 << (2*9 + 1);
/* 设置上拉/下拉为浮空 */
GPIOF_PUPDR &= ~(1 << 2*9 );
GPIOF_PUPDR &= ~(1 << (2*9 + 1));
while(1)
{
// 设置PF8为高电平
GPIOx_BSRR &= ~(1 << 9 );
GPIOx_BSRR |= 1 << 25;
}
}
以上代码中没有包含任何库文件,即可完成对LED0灯的点亮!!
三、官方库函数底层代码
看过两种方式点亮LED0后,再回头看官方的库函数的底层代码,本质上也是通过封装寄存器的地址来点亮LED的:
// stm32f4xx.h
/**
* @brief General Purpose I/O
*/
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
...
#define PERIPH_BASE ((uint32_t)0x40000000) /* 外设基地址 */
...
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) /* AHB1总线基地址 */
...
#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400) /* GPIOF端口基地址 */
...
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) /* 端口接口体指针 */
看过以上库函数的封装以后,就可以解释一开头的那句 GPIOF->BSRRL = GPIO_Pin_9;为什么可以直接对引脚置位了。
四、总结
点亮LED灯,应该说是“麻雀虽小五脏俱全”,整个过程也蕴含了完整的开发流程和知识体系。总的来说,使用官方提高的库函数确实极大地提高了开发效率,但是却非常的抽象;通过阅读手册,更加深入地理解硬件却能更好地掌控代码与硬件之间的直接联系,这个过程着实能让人学到不少东西。
STM32操作GPIO外设(点亮LED灯)的两种方式——使用官方库函数或直接操作寄存器的更多相关文章
- Visual Studio 2022 开发 STM32 单片机 - 环境搭建点亮LED灯
安装VS2022社区版软件 选择基础的功能就好 安装VisualGDB软件(CSDN资源) 按照提示一步一步安装就好 VisualGDB激活软件(CSDN资源) 将如下软件放在VisualGDB的安装 ...
- [IOT] - 使用 .Net Core 操作 GPIO 引脚点亮 LED 灯泡
1. 在 VS 2019 中创建 .Net Core 控制台应用程序,使用 Nuget 安装程序包: System.Device.GpioIot.Device.Bindings 2. 更新 Main ...
- POI操作Excel详细解释,HSSF和XSSF两种方式
HSSF道路: package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundEx ...
- POI操作Excel详解,HSSF和XSSF两种方式
package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundException; ...
- 第7章 使用寄存器点亮LED灯
第7章 使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- 第7章 使用寄存器点亮LED灯—零死角玩转STM32-F429系列
第7章 使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- C语言版——点亮LED灯,深入到栈
在上一篇进行了汇编语言的编写之后,我们采用C语言来编写程序,毕竟C语言才是我们使用最多的语言. 仅仅是点亮LED灯显然太过于简单,我们需要分析最后的反汇编,了解函数调用栈,深入C语言骨髓去分析代码,并 ...
- 初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯
初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯 前言 随着中美贸易战的加剧,很多公司越来越重视使用国产技术的重要性.使用国产技术,一方面可规避国外对技术的封锁造成产品核心 ...
- Raspberry PI 系列 —— 裸机点亮LED灯
Raspberry PI 系列 -- 裸机点亮LED灯 背景 近期刚买了Raspberry PI B+,配置执行了官方提供的Raspbian系统,折腾了一周Linux系统,感觉没啥意思,于是就试着想了 ...
- stm32F103C8T6通过写寄存器点亮LED灯
因为我写寄存器的操作不太熟练,所以最近腾出时间学习了一下怎么写寄存器,现在把我的经验贴出来,如有不足请指正 我使用的板子是stm32F103C8T6(也就是最常用的板子),现在要通过写GPIO的寄存器 ...
随机推荐
- Xshell不可以删除,退格^H
文件→属性→终端→键盘,把delete和backspace序列改为 ASCII 127即可.
- Iceberg常用命令
一.登录spark客户端 spark-sql --master yarn \ --deploy-mode client \ --queue default \ --name wang \ --driv ...
- Luogu P10581 蓝桥杯2024国A 重复的串 题解 [ 蓝 ] [ KMP ] [ 动态规划 ] [ 矩阵加速 ]
重复的串:KMP + dp 的板子题. 暴力 dp 设计 \(dp_{k,i,j}\) 表示主串匹配到第 \(i\) 位,模式串有 \(j\) 位已匹配完成,目前已完成 \(k\) 次匹配的方案数. ...
- 理解ID3决策树
决策树是一个树形结构,类似下面这样: 上图除了根节点外,有三个叶子节点和一个非叶子节点. 在解决分类问题的决策树中,叶子节点就表示所有的分类,比如这里的分类就有3种:无聊时阅读的邮件.需及时处理的邮件 ...
- 川崎机器人维修kasawaki维护注意事项
为确保川崎机械臂的正确安全操作.防止人员伤害和财产损失,请遵守下述方框符号表达的安全信息. --注意事项 在进行Kasawaki川崎机器人维修操作前,请注意如下事项以确保安全. 1. 在开始检查之前, ...
- autMan奥特曼机器人-实时翻译的用法
一.基本配置 访问并登录百度翻译开放平台:https://api.fanyi.baidu.com/ 进入开发者信息获取 APP ID和密钥,并开通"通用文本翻译"服务 autMan ...
- docker - [06] 安装部署Tomcat
题记部分 一.官方测试镜像 官方文档给出以下命令,一般用来测试,用完即删,下载并运行镜像,退出镜像就会自动删除镜像?亲测不会自动删除 docker run -it --rm tomcat:9.0 使用 ...
- 错误模块名称:vrfcore.dll
记录一下. 应用程序莫名报这个错,其它电脑上正常. 可能是Application Verifier这个工具影响到了. 进入注册表:win+R->regedit->HKEY_LOCAL_MA ...
- Oracle客户端中文显示问号乱码问题
Oracle显示中文显示??乱码 问题如下图 解决方法 打开Oracle客户端,新建一个SQL Window 输入select userenv('language') from dual 复制搜索到的 ...
- 朝花夕拾,帮三年前的自己改bug
三年前,滨海之边马上毕业的老少年 经过几天半死不活的思考之后决定干前端 那个时候为了面试各种css属性js API背的是滚瓜烂熟 然后投简历,企业要项目经验, 我没有工作我哪来的项目经验啊 没人会管你 ...
