目录
一、GPIO外设的概念
1.GPIO的概念
GPIO(General Purpose Input/Output)外设是++++用于与外部设备进行交互++++ 。++++GPIO引脚的核心功能是作为通用的数字输入或输出++++ ,++可以++ 通过软件++配置为多种工作模式++ ,以满足不同的应用需求,++++GPIO引脚需要和外设连接在一起的,就可以和外设实现通信以及采集数据等功能++++。

2.GPIO的定义
GPIO指的是++++对芯片的某个引脚进行高低电平的输出(输出),以及可以去检测某个引脚的电平状态(输入)。++++
++++一般电平采用都是TTL电平信号,TTL电平信号规定:+5V等价于逻辑"1",0V等价于逻辑"0"。++++
电平其实有一个电平范围:>2.4V就表示高电平,<0.4V就表示低电平。
3.引脚的分布

电源引脚 :VCC、VDD、VSS、VDDA、VSSA、VREF+等属于电源引脚
晶振引脚 :PC14、PC15、PH0、PH1就属于晶振引脚,也可以作为其他的功能使用
复位引脚 :NRST属于复位引脚
BOOT引脚 :BOOT0是专用引脚,BOOT1就属于功能引脚 (设置芯片的自举模式)
GPIO引脚 :芯片一共有144引脚,但是GPIO引脚有114个
下载引脚 :PA13、PA14、PB3、PB4等都属于下载引脚(JTAG、SWD)
4.引脚的命名
IO口的命名是由P(Pin)开头,分为很多组(端口),以字母A~H来命名,每个组(端口)有16个引脚,引脚的编号为0~15,所以如端口A引脚范围: PA0 ~ PA15 端口B引脚范围:PB0~PB15.....
扩展:51单片机的引脚及引脚分别
51单片机也有IO口,一般8051有40个引脚,其中有1个复位引脚,2个晶振引脚,2个电源引脚,3个存储选择引脚,剩下的32个引脚作为IO口,8051也把32个IO口进行分组,分为4个端口,每个端口有8个引脚,端口是以数字0~3进行区分,每个端口的8个引脚是以数字0~7进行区分,比如 P00 ~ P07 P10 ~ P17 P20 ~ P27 P30 ~ P37

5.引脚的功能
需要注意:++芯片的引脚有很多的功能++ ,一般默认的功能都是作为GPIO(输入输出),但是++引脚也有其他的功能,被称为"第二功能"++ ,++++只有在使用ADC通道和DAC需要把引脚设置模拟模式,其他情况下想要把引脚当做别的功能使用, 需要把引脚设置复用模式。++++ 注意:如果想要了解引脚的功能,应该查阅芯片的数据手册!!!!
++++注意:引脚在芯片复位之后的默认功能一般都是GPIO功能,但是并不绝对,所以用户在使用后任何一个引脚的时候都应该查阅芯片数据手册.++++

FT标记:该GPIO可以容忍5v电压。
因为IO口外设有2个保护二极管,可以一定程度上保护IO口,但是保护的上限是5v。

二、GPIO外设的使用
从点亮LED开始,主要是以基础外设作为入门,掌握外设的控制流程。
为了快速入门编写代码,先使用st公司提供的标准外设库的接口完成入门。
- 查看原理图,找到控制发光二极管的芯片的IO口

- 分析原理图,理解硬件的控制原理(复杂外设还需要结合数据手册)。
当前发光二极管的一端连接正极,为使当前发光二极管亮,则需要MCU输出低电平。
- 3.程序设计,根据ST公司提供的函数库(标准外设库)的帮助手册学习开发流程。

案例
需求:实现利用ST公司的关于GPIO外设的代码案例,来控制点亮开发板的4盏LED灯。
cpp
/**
******************************************************************************
* @file GPIO/GPIO_IOToggle/main.c
* @author
* @version
* @date 03-August-2026
* @brief 利用MCU点亮4盏LED灯的亮
D1 LED0 PF9
D2 LED1 PF10
D3 FSMC_D10 PE13
D4 FSMC_D10 PE14
******************************************************************************
**/
#include "stm32f4xx.h" //必须要包含的头文件
int main()
{
//1.定义GPIO外设的结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
//2.打开GPIOF端口、GPIOE端口的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//3.配置PF9引脚为输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//4.对GPIOF端口进行初始化
GPIO_Init(GPIOF, &GPIO_InitStructure);
//初始化到端口F,而端口F记录了上述的参数,下方再改参数,对端口F都不会有影响了
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_Init(GPIOE, &GPIO_InitStructure);
while(1)
{
//5.控制PF9引脚输出低电平,则LED会亮
GPIOF->BSRRH = GPIO_Pin_9 | GPIO_Pin_10 ;
GPIOE->BSRRH =GPIO_Pin_13 | GPIO_Pin_14;
}
}
三、GPIO外设的细节分析
外设的初始化和配置
|-----------------|
| 1.定义外设的结构体变量 |
| 2.打开外设的时钟 |
| 3.对外设的结构体成员进行赋值 |
| 4.对外设进行初始化 |
- 定义GPIO外设的和初始化相关的结构体变量,结构体类型是定义在stm32f4xx_gpio.h

- 2.想要使用GPIO外设,必须提前打开GPIO端口外设时钟

++++STM32的MCU内部有很多外设,每个外设的作用和性能都各不相同++++ ,ST公司为了降低芯片功耗,把不同性能的外设挂载在不同性能的总线上,需要掌握++++3条总线:AHB高级高性能总线(总线频率是168MHZ)、APB1高级外设总线(总线频率是42MHZ)、APB2高级外设总线(总线频率是84MHZ)。++++

MCU总线
而++++MCU内部的外设的性能不同,++++ 所以++++就需要把外设挂载到对应的总线 ,利用总线对外设进行控制。++++

寄存器的组成、触发器的概述
- 寄存器由若干触发器组成。
- ++二值信号++ 不仅需要进行算术运算和逻辑运算 ,还经常需要将这些信号和运算结果保存起来 。为此 ====> ++需要使用具有记忆功能的基本逻辑单元++ 。能够存储1位二值信号的基本单元电路 统称为触发器。
记忆1位二值信号触发器的两个基本特点:
- 双稳态。具有两个能自行保持的稳定状态,用来表示逻辑状态的0和1
- 在触发信号的操作下,根据不同的输入信号可以置成1或0状态。
触发方式:电平触发、脉冲触发和边沿触发三种。

为什么要打开时钟?
++(从功耗的角度)++芯片是低功耗的,为了降低功耗,复位之后,外设都是关闭状态。所以在用外设之前都 要打开时钟。
++(打开时钟的目的,从底层的角度讲)++打开时钟的目的是为了使用寄存器。
++++时钟相当于外设的开关,不打开时钟,则晶振产生的振荡信号就无法输入到++++ MCU内部的外设中,则没有时钟信号,触发器无法触发,则触发器无法锁存数据,而寄存器是由N个触发器组成,所以寄存器就无法工作,而控制硬件,必须通过寄存器实现。
- 3.打开GPIO外设的时钟之后,可以对GPIO外设的初始化结构体中的成员进行赋值
设置GPIO引脚编号
/** @defgroup GPIO_pins_define
* @{
*/
#define GPIO_Pin_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /* All pins selected */
设置GPIO引脚的模式
typedef enum
{
GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ //输入模式
GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ //输出模式
GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ //复用模式
GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */ //模拟模式
}GPIOMode_TypeDef;
设置GPIO引脚的输出速度
指的是引脚电平的切换速度。
输出速度指的是引脚电平的翻转速度,如果选择高速,则会增加功耗和噪声,如果不知道选择哪种,则选择高速即可(为了不影响IO口的性能)。
/**
* @brief GPIO Configuration PullUp PullDown enumeration
*/
typedef enum
{
GPIO_PuPd_NOPULL = 0x00,
GPIO_PuPd_UP = 0x01,
GPIO_PuPd_DOWN = 0x02
}GPIOPuPd_TypeDef;
设置GPIO引脚的输出类型
/**
* @brief GPIO Output type enumeration
*/
typedef enum
{
GPIO_OType_PP = 0x00, //推挽输出
GPIO_OType_OD = 0x01 //开漏输出
}GPIOOType_TypeDef;
设置GPIO引脚的内部电阻
上拉电阻、下拉电阻、不用电阻。
上拉电阻、下拉电阻的作用:在引脚没有外部电平的情况下,选择给引脚提供一个外部电平。
上拉电阻的作用:在引脚没有外部电平的情况下,选择给引脚提供一个高电平。
下拉电阻的作用:在引脚没有外部电平的情况下,选择给引脚提供一个低电平。
/**
* @brief GPIO Configuration PullUp PullDown enumeration
*/
typedef enum
{
GPIO_PuPd_NOPULL = 0x00,
GPIO_PuPd_UP = 0x01,
GPIO_PuPd_DOWN = 0x02
}GPIOPuPd_TypeDef;
4.设置好了GPIO结构体的各个成员的值,需要把结构体中的值写入到GPIO端口寄存器!
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
