一 GPIO介绍:
GPIO 是通用输入输出端口的简称,
简单来说就是 STM32 可控制的引脚,STM32 芯片
的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚。
如型号为 STM32F4IGT6 型号的芯片有 GPIOA、GPIOB、GPIOC 至 GPIOI 共 9 组 GPIO,芯片一共 176 个引脚,其中 GPIO
就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
二基本的输出功能:
由 STM32 控制引脚输出高、低电平,实现开关控制,如把 GPIO
引脚接入到 LED 灯,那就可以控制 LED 灯的亮灭,引脚接入到继电器或三极管,那就可
以通过继电器或三极管控制外部大功率电路的通断。
三GPIO基本结构:
(1). 保护二极管及上、下拉电阻
保护二极管:
引脚的两保护个二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于
VDD_FT时,上方的二极管导通,当引脚电压低于 VSS时,下方的二极管导通,防止不正常
电压引入芯片导致芯片烧毁。(正向导通,反向截止)。
上拉、下拉电阻
GPIO口通常有3种模式, 高电平 低3电平 高阻态(断开或者浮空状态),上拉下拉作用就是防止输入端在悬空状态,使其有确定状态,减少外部对芯片的干扰。上拉时引脚为高电平下拉时为低电平
(2)P-MOS 管和 N-MOS 管
图中:GPIO 引脚线路经过上、下拉电阻结构后,向上流向“输入模式”结构,向下流向“输
出模式”结构。线路经过一个由 P-MOS 和 N-MOS 管组成的单元电路。
这个结构使 GPIO 具有了“推挽输出”和“开漏输出”两种模式
工作过程:
推挽输出模式
该结构中输入高电平时,上方的 P-MOS 导通,下方的 N-MOS 关闭,对外输出高电平;而在该结构中输
入低电平时,N-MOS 管导通,P-MOS 关闭,对外输出低电平。当引脚高低电平切换时,
两个管子轮流导通,一个负责灌电流,一个负责拉电流,使其负载能力和开关速度都比普
通的方式有很大的提高。
开漏输出模式
上方的 P-MOS 管完全不工作。如果我们控制输出为 0,低电平,
则 P-MOS 管关闭,N-MOS 管导通,使输出接地,若控制输出为 1 (它无法直接输出高电平)
时,则 P-MOS 管和 N-MOS 管都关闭,所以引脚既不输出高电平,也不输出低电平,为高
阻态。为正常使用时必须接上拉电阻(可用 STM32 的内部上拉,但建议在 STM32 外部再接
一个上拉电阻。
注意:只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,
此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就
相当于短路接地,使得整条线路都为低电平,0 伏。
应用领域:推挽输出模式一般应用在输出电平为 0 和 3.3 伏而且需要高速切换开关状态的场合。
开漏输出一般应用在 I2C、SMBUS 通讯等需要“线与”功能的总线电路中。除此之外,
还用在电平不匹配的场合,如需要输出 5 伏的高电平,就可以在外部接一个上拉电阻,上
拉电源为 5 伏,并且把 GPIO 设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外
输出 5 伏的电平。
(3)输出数据寄存器
3.1 输出类型寄存器 GPIOx_OTYPER”可以控制 GPIO 端口是推挽模式还是开漏模
式。
3.2 双 MOS 管结构电路的输入信号,是由 GPIO“输出数据寄存器
GPIOx_ODR”提供的,因此我们通过修改输出数据寄存器的值就可以修改 GPIO 引脚的输
出电平。
3.3 而“置位/复位寄存器 GPIOx_BSRR”可以通过修改输出数据寄存器的值从而影响
电路的输出。
(4)模拟输入输出
经过施密特触发器后信号只有 0、1 两种状态,所以 ADC 外
设要采集到原始的模拟信号,信号源输入必须在施密特触发器之前。
四 GPIO工作模式
由 GPIO 的结构决定了 GPIO 可以配置成以下模式
1. 输入模式(上拉/下拉/浮空):
在输入模式时,施密特触发器打开,输出被禁止。数据寄存器每隔 1 个 AHB1 时钟周
期更新一次。
可通过输入数据寄存器 GPIOx_IDR 读取 I/O 状态。
AHB1 的时钟如按默
认配置一般为 180MHz。
2. 输出模式(推挽/开漏,上拉/下拉
推挽模式时双 MOS 管以方式工作,输出数据寄存器GPIOx_ODR 可控制 I/O 输出高低电平。
开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制 I/O 输出高阻态或低电平。
此时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取
I/O 的实际状态。
3. 复用功能(推挽/开漏,上拉/下拉)
输出使能,输出速度可配置。
可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;
4. 模拟输入输出
双 MOS 管结构被关闭
施密特触发器停用
上/下拉也被禁止。
其它外设通过模拟通道进行输入输出。
在GPIO 外设中,通过设置“模式寄存器 GPIOx_MODER”可配置 GPIO 的输入/输出/复用/模
拟模式,“输出类型寄存器 GPIOx_OTYPER”配置推挽/开漏模式,配置“输出速度寄存
器 GPIOx_OSPEEDR”可选 2/25/50/100MHz 输出速度,“上/下拉寄存器 GPIOx_PUPDR”。可配置上拉/下拉/浮空模式,
五实验用32点亮一个灯
(1):用寄存器点亮一盏灯
(2)总线基地址
(3)外设基地址
(4)寄存器地址
由图可知:边界地址=片上外设基址0x4000 0000 + 相对偏移量0x00020000+各个GPIO口偏移地址0x800=0x40020800(GPIOC)
寄存器地址=GPIOH的基地址+相对的偏移地址
总线AHB1挂载的外设:
stm32F4xx.h代码
/片上外设基址/
#define PERIPH_BASE ((unsigned int)0x40000000)
/*总线基地址*/
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
/GPIO外设基地址/
#define GPIOC_BASE (AHB1PERIPH_BASE +0X800)
#define GPIOI_BASE (AHB1PERIPH_BASE +0X2000)
#define GPIOA_BASE (AHB1PERIPH_BASE +0X0000)
/GPIOC寄存器地址,强制转换成指针/
#define GPIOC_MODER *( unsigned int *)(GPIOC_BASE+0x00)
#define GPIOC_OTYPER *( unsigned int *)(GPIOC_BASE+0x04)
#define GPIOC_OSPEER *( unsigned int *)(GPIOC_BASE+0x08)
#define GPIOC_PUPDR *( unsigned int *)(GPIOC_BASE+0x0C)
#define GPIOC_IDR *( unsigned int *)(GPIOC_BASE+0x10)
#define GPIOC_ODR *( unsigned int *)(GPIOC_BASE+0x14)
#define GPIOC_BSRR *( unsigned int *)(GPIOC_BASE+0x18)
#define GPIOC_LCKR *( unsigned int *)(GPIOC_BASE+0x1C)
#define GPIOC_AFRL *( unsigned int *)(GPIOC_BASE+0x20)
#define GPIOC_AFRH *( unsigned int *)(GPIOC_BASE+0x24)
这样就将寄存器地址映射好了
(5)相关寄存器:
因为基本GPIO口挂载在AHB1所以使用AHB1的时钟
RCC寄存器
RCC AHB1 外设时钟使能寄存器 (RCC_AHB1ENR)
位 8 GPIOIEN:IO 端口 I 时钟使能 (IO port I clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 I 时钟
1:使能 IO 端口 I 时钟
位 7 GPIOHEN:IO 端口 H 时钟使能 (IO port H clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 H 时钟
1:使能 IO 端口 H 时钟
位 6 GPIOGEN:IO 端口 G 时钟使能 (IO port G clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 G 时钟
1:使能 IO 端口 G 时钟
位 5 GPIOFEN:IO 端口 F 时钟使能 (IO port F clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 F 时钟
1:使能 IO 端口 F 时钟
位 4 GPIOEEN:IO 端口 E 时钟使能 (IO port E clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 E 时钟
1:使能 IO 端口 E 时钟
位 3 GPIODEN:IO 端口 D 时钟使能 (IO port D clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 D 时钟
1:使能 IO 端口 D 时钟
位 2 GPIOCEN:IO 端口 C 时钟使能 (IO port C clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 C 时钟
1:使能 IO 端口 C 时钟
位 1 GPIOBEN:IO 端口 B 时钟使能 (IO port B clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 B 时钟
1:使能 IO 端口 B 时钟
位 0 GPIOAEN:IO 端口 A 时钟使能 (IO port A clock enable)
由软件置 1 和清零。
0:禁止 IO 端口 A 时钟
1:使能 IO 端口 A 时钟
GPIO 端口模式寄存器 (GPIOx_MODER)
2位控制一位
MODERy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)(x对应gpioc gpioa等 y代表引脚号)
这些位通过软件写入,用于配置 I/O 方向模式。
00:输入(复位状态)
01:通用输出模式
10:复用功能模式
11:模拟模式
GPIO 端口输出类型寄存器 (GPIOx_OTYPER)
OTy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
这些位通过软件写入,用于配置 I/O 端口的输出类型。
0:输出推挽(复位状态)
1:输出开漏
GPIO 端口输出速度寄存器 (GPIOx_OSPEEDR)
OSPEEDRy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
这些位通过软件写入,用于配置 I/O 输出速度。
00:2 MHz(低速)
01:25 MHz(中速)
10:50 MHz(快速)
11:30 pF 时为 100 MHz(高速)(15 pF 时为 80 MHz 输出(最大速度))
GPIO 端口上拉/下拉寄存器 (GPIOx_PUPDR)
PUPDRy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
这些位通过软件写入,用于配置 I/O 上拉或下拉。
00:无上拉或下拉
01:上拉
10:下拉
11:保留
GPIO 端口输入数据寄存器 (GPIOx_IDR)
端口输入数据 (Port input data) (y = 0..15)
这些位为只读形式(不好改),只能在字模式下访问。它们包含相应 I/O 端口的输入值。
GPIO 端口输出数据寄存器 (GPIOx_ODR)
对于原子置位/复位,通过写入 GPIOx_BSRR 寄存器,可分别对 ODR 位进行置位和复
位
GPIO 端口置位/复位寄存器 (GPIOx_BSRR)
位 31:16 BRy:端口 x 复位位 y (Port x reset bit y) (y = 0..15)
位 15:0 BSy:端口 x 置位位 y (Port x set bit y) (y= 0..15)
(六)主函数main.c
(点亮一盏灯GPIOC)
//开启时钟
RCC_AHB1ENR |=(1<<2);
// 设置工作模式为通用输出模式
GPIOC_MODER &=~(3<<2);//11左移两位,先进行清0
GPIOC_MODER |=(1<<2);//置1选择输出模式
//选择输出模式 推挽输出
GPIOC_OTYPER &=~(1<<1);//左移一位选择引脚1
//设置速度 50m
GPIOC_OSPEER &=~(3<<2);//清0
GPIOC_OSPEER |=(2<<2);
//设置上拉还是下拉
GPIOC_PUPDR &=~(3<<2);
GPIOC_PUPDR |=(1<<2);;
//输出电平设置为 高还是低(0到15置位 15 到31复位 )
GPIOC_BSRR |=(1<<1);//0和16对应引脚0 1和17对应引脚1所以要左移一位
(蜂鸣器)
有原理图发现beep在PI11引脚上
/*
RCC_AHB1ENR |=(1<<8);//移动至GPIOI口
// 设置工作模式输出模式
GPIOI_MODER &=~(3<<22);//
GPIOI_MODER |=(1<<22);//
//输出模式 推免模式
GPIOI_OTYPER &=~(1<<11);
//设置速度 50m
GPIOI_OSPEER &=~(3<<22);
GPIOI_OSPEER |=(2<<22);
//设置输出上拉或者下拉
GPIOI_PUPDR &=~(3<<22);
GPIOI_PUPDR |=(1<<22);//选择上拉
//给11脚置1
GPIOI_BSRR |=(1<<11);
*/
按键检测为输入模式
//按键检测
RCC_AHB1ENR |=1;
// 设置工作模式为输入模式
GPIOA_MODER &=~3;//清0
//推挽输出
GPIOA_OTYPER &=~1;
//速度50M
GPIOA_OSPEER &=~3;
GPIOA_OSPEER |=2;
//设置为上拉电阻
GPIOA_PUPDR &=~3;
GPIOA_PUPDR |=1;
while(1)
{
if((GPIOA_IDR &=1) ==0)
{
//输出为
GPIOC_BSRR |=(1<<4);//点亮引脚4的灯
}
}