STM32笔记归纳2:GPIO

GPIO

目录

GPIO

一、GPIO的四种输出模式

1.1.GPIO的概念

1.2.GPIO的编组

1.3.GPIO的工作模式

1.3.1.输出模式

1.3.2.输入模式

1.4.四种输出模式

1.4.1.四种输出模式命名

1.4.2.IO端口位电路图

1.4.3.输出模式的电路图

1.4.4.推挽模式

1.4.5.开漏模式

1.4.6.通用模式

1.4.7.复用模式

二、IO的最大输出速度

2.1.IO最大输出速度

2.2.上升、下降、保持时间

2.3.限制最大输出速度的原因

2.4.最大输出速度的选取

三、LED闪灯实验

3.1.如何点亮一盏Led

3.2.最小系统板的Led接法

3.3.编码部分

3.3.1.开启GPIOx的时钟

3.3.2.GPIO模块编程接口

3.3.2.1.编程接口1

3.3.2.2.编程接口2

3.3.2.3.编程接口4

3.3.3.初始化IO引脚

3.3.4.写入数据,点亮Led

3.3.5.设计Led闪烁

四、GPIO的4种输入模式

4.1.四种输入模式命名

4.2.输入模式的电路图

4.2.1.保护二极管

4.2.2.上拉电阻

4.2.3.下拉电阻

4.2.4.施密特触发器

五、按钮实验

5.1.Led的接线方法

5.1.1.接线设计

5.1.2.接线安装

5.1.3.测试代码

5.2.按钮的接线方法

5.2.1.接线设计

5.2.2.接线安装

5.2.3.测试代码

5.3.编程接口和代码


一、GPIO的四种输出模式

1.1.GPIO的概念

**GPIO:**通用输入输出端口

**注:**G:general P:purpose I:input O:output

STM32芯片内置的片上外设模块

**功能:**类似于人类的手,控制单片机上的IO引脚

1.2.GPIO的编组

STM32芯片包含四组GPIO模块

GPIOA,GPIOB,GPIOC,GPIOD

每组GPIO模块包含特定的引脚:

  • GPIOA:PA0 PA1 PA2 ... PA15(16个)
  • GPIOB:PB0 PB1 PB2 ... PB15(16个)
  • GPIOC:PC13 PC14 PC15(3个)
  • GPIOD:PD0 PD1(2个)

每组GPIO模块像人的一只手

每个GPIO引脚就是人的手指

1.3.GPIO的工作模式

GPIO的工作模式配置了IO引脚的功能

单个IO引脚需要实现多种功能:

  • 输出高/低电平
  • 输入外部信号
  • 其他特殊功能

因此每个IO引脚都需要配置多种功能

所以GPIO定义了8种不同的工作模式

可分为4种输出4种输入两大类模式

1.3.1.输出模式

信号从【芯片内部】通过IO引脚流向【芯片外部】

**使用示例:**用输出模式控制Led亮灭:

在IO引脚上接一颗Led(发光二极管)

  • 如果输出高电平:Led点亮
  • 如果输出低电平:Led熄灭

通过编程向芯片内部的输出数据寄存器写入数据

  • 写入1:引脚输出高电平,Led点亮
  • 写入0:引脚输出低电平,Led熄灭
1.3.2.输入模式

信号从【芯片外部】通过IO引脚流向【芯片内部】

**使用示例:**通过输入模式判断开关闭合

在IO引脚上接一个开关

  • 如果开关闭合:向引脚输入高电平,输入数据寄存器值为1
  • 如果开关断开:向引脚输入低电平,输入数据寄存器值为0

通过编程从芯片内部的输入数据寄存器读取数据

  • 读取1:当前开关闭合
  • 读取0:当前开关断开

1.4.四种输出模式

1.4.1.四种输出模式命名

通用输出推挽 通用输出开漏

复用输出推挽 复用输出开漏

1.4.2.IO端口位电路图

因为在STM32中一共有32个IO引脚,像这样的电路在芯片中一共有32个

上方为输入模式电路,下方为输出模式电路

1.4.3.输出模式的电路图
1.4.4.推挽模式

**推状态(PUSH):**从里向外推电流

  • 由P-MOS管实现:
  • P-MOS管接Vdd(3.3V正电压)
  • 导通P-MOS管,断开N-MOS管
  • IO引脚与Vdd导通,输出高电平(3.3V)
  • 电流从内部向外推送

**挽状态(PULL):**从外向里拉电流

  • 挽与N-MOS管有关:
  • N-MOS管接Vss(0V负电压)
  • 导通N-MOS管,断开P-MOS管
  • IO引脚与Vss短路,输出低电平(0V)
  • 电流从外部向内拉取

注:

P-MOS管和N-MOS管只能交替导通,不能同时导通,

高电压(Vdd)与低电压(Vss)直接相连会发生短路

1.4.5.开漏模式

**开漏:**MOS管的漏极保持断开状态

在输出模式下,开漏表示P-MOS管一直处于断开状态

**写入0时:**N-MOS管导通,P-MOS管断开,输出低电平

**写入1时:**N-MOS管断开,P-MOS管断开,呈悬空状态

**注:**此时引脚电流趋于0,根据欧姆定律,电阻为无穷大,所以又称高阻态

1.4.6.通用模式

CPU直接向输出数据寄存器写入数据来控制GPIO引脚

**使用示例:**CPU直接控制PA9引脚实现Led亮灭

CPU直接向输出数据寄存器写入数据

**写1:**PA9输出高电平

**写0:**PA9输出低电平

1.4.7.复用模式

片上外设通过GPIO模块控制IO引脚的电平输出

**使用示例:**串口模块控制PA9引脚发送"Hello"数据

CPU向串口模块发送"Hello"数据

串口模块控制PA9引脚输出高低电平变换的波形,从而输出数据

通用 VS 复用:

二、IO的最大输出速度

2.1.IO最大输出速度

**定义:**向IO交替写0和1且输出不失真的最快速度

示例: 假定引脚的模式为推挽模式

  • 输出1时:P-MOS管导通,引脚为高电平
  • 输出0时:N-MOS管导通,引脚为低电平

两个MOS管快速交替导通时,就会形成下面的波形:

每秒钟写10次,每秒中写100次时这个波形都为正常的

当速度加快到每秒钟写100000次后,波形就开始失真

此时能维持正常输出的最高频率即为IO最大输出速度

2.2.上升、下降、保持时间

理想情况:

**向IO引脚写1:**IO引脚电压立即从低电平(0V)跃升至高电平(3.3V)

**向IO引脚写0:**IO引脚电压立即从高电平(3.3V)下降至低电平(0V)

实际情况:

**上升时间:**0V~3.3V的过渡时间

**保持时间:**稳定在3.3V持续时间(输出有效电平的时间)

**下降时间:**3.3V~0V的过渡时间

2.3.限制最大输出速度的原因

随着IO输出速度的提升,上升沿与下降沿之间的间隔缩短

导致有效电平的持续时间减少,即保持时间变短

若数据写入数据速度超过IO引脚的最大输出速度,将无法正确输出电平

通过缩短上升时间下降时间,就可以提高IO最大输出速度

2.4.最大输出速度的选取

STM32芯片提供了三种最大速度:

低速:

  • 上升时间:125ns
  • 保持时间:250ns
  • 下降时间:125ns
  • 总时间:500ns
  • 最大输出速度:2MHz

中速:

  • 上升时间:25ns
  • 保持时间:50ns
  • 下降时间:25ns
  • 总时间:100ns
  • 最大输出速度:10MHz

高速:

  • 上升时间:5ns
  • 保持时间:10ns
  • 下降时间:5ns
  • 总时间:20ns
  • 最大输出速度:50MHz

**选取原则:**选取满足要求的最小值

**注:**如果选择过高的输出速率会增加耗电,还会对其他的电子元器件产生干扰(EMI)

**示例1:**单片机驱动Led

Led的闪烁频率不超过100Hz,所以选择低速(2MHz)来驱动

注:

人眼的临界闪烁频率是45.8Hz,交流电的频率是50Hz

所以当使用50Hz的交流电点亮一盏灯时感受不到闪烁

**示例2:**单片机驱动TLE5012BD芯片(巨磁阻效应编码器)

TLE5012BD芯片使用SPI总线与单片机通信

SPI总线通信的波特率为8Mbit/s(MHz),所以选择中速(10MHz)来驱动

**示例3:**USB2.0全速接口

USB2.0 Fs通信的最大波特率为12Mbps(MHz),所以选择高速(50MHz)来驱动

三、LED闪灯实验

**实验内容:**通过编程控制PC13引脚连接的Led灯实现闪烁功能

3.1.如何点亮一盏Led

原理:

在二极管的阳极供正电压,阴极供负电压,这样就会有电流流过二极管

当流过二极管的电流足够大时,二极管就会被点亮,电流范围为2~10mA

用以下电路实现Led的点亮:

阳极接Vdd(3.3V), 阴极接Vss(0V),Vdd与Vss间串联一个510Ω的限流电阻

二极管导通时压降为0.7V,所以电流为(3.3-0.7)/510 ≈ 5mA,二极管可以正常发光

推挽接法:

如果把Vdd改为地,阳极为0V,阴极也为0V,就不会有电流流过,二极管就会熄灭

所以我们在Vdd与Led之前设置一个开关,上拨接Vdd,下拨接地,实现二极管闪烁

这种拨动开关控制接Vdd或接Vss的方式与推挽输出类似

所以可以将限流电左边的电路替换成单片机上的IO引脚

并且把IO引脚的输出模式设置为推挽模式:

开漏接法:

如果将开关设置在二极管与Vss之间

开关接上为通路Led点亮,开关断开为开路Led熄灭

这种拨动开关控制接Vss或开路的方式与开漏输出类似

所以可以将Led右边的电路替换成单片机上的IO引脚

并且把IO引脚的输出模式设置为开漏模式:

3.2.最小系统板的Led接法

最小系统板上分别设置了两个Led

一个连接GND:

一个连接PC13引脚

因为Led的阳极只接上了3.3V的高电平

所以最小系统板的Led接法为开漏接法:

3.3.编码部分

3.3.1.开启GPIOx的时钟
cpp 复制代码
/*开启GPIOC的时钟*/
RCC_APB2PriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);

解析:

  • 参数1:设置的GPIO组别
  • 参数2:使能

**注:**要控制板载LED,需通过GPIOC组的PC13引脚进行操作,所以在使用GPIOC之前,要为它开启时钟,时钟可以类比为人的心跳,开启时钟相当于给人身体里的器官供血

3.3.2.GPIO模块编程接口
3.3.2.1.编程接口1
cpp 复制代码
void GPIO_Init(GPIOTypeDef * GPIOx, GPIO_InitTypeDef * GPIO_InistStruct);

解析:

  • 参数1:端口号,取A,B,C,D
  • 参数2:初始化的参数结构体地址

**注:**init(Initialize):初始化

作用: 初始化IO引脚,配置IO引脚的各种参数

  • 引脚的工作模式
  • 引脚的最大输出速度

**补充:**GPIO_InitTypeDef结构(IO参数菜单)

cpp 复制代码
typedef struct GPIO_InitTypeDef
{
	GPIO_Pin;
	GPIO_Speed;
	GPIO_Mode;
}GPIO_InitTypeDef;

分析:

**1.GPIO_Pin:**引脚编

  • GPIO_Pin_0 ...... GPIO_Pin_15

**2.GPIO_Speed:**最大输出速度

  • GPIO_Speed_2MHz
  • GPIO_Speed_10MHz
  • GPIO_Speed_50MHz

**3.GPIO_Mode:**模式

  • GPIO_Mode_Out_PP:通用输出推挽 PP = Push Pull
  • GPIO_Mode_Out_OD:通用输出开漏 OD = Open Drain
  • GPIO_Mode_AF_PP:复用输出推挽 AF = Alternate Function
  • GPIO_Mode_AF_OD:复用输出开漏
  • GPIO_Mode_IPU:输入上拉 IPU = Input Pull-up
  • GPIO_Mode_IPD:输入下拉 IPD = Input Pull-down
  • GPIO_Mode_IN_FLOATING:输入浮空
  • GPIO_Mode_AIN:模拟模式 AIN = Analog Input

**注:**此结构的每个成员变量都为枚举变量

3.3.2.2.编程接口2
cpp 复制代码
void GPIO_WriteBit(GPIOTypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitValue);

解析:

  • 参数1:端口号,取A,B,C,D
  • 参数2:引脚编号
  • 参数3:要写入的值 Bit_RESET(写0) Bit_SET(写1)

**作用:**向输出数据寄存器写1个比特位

**示例:**假设IO引脚为通用输出推挽模式,通过调用GPIO_WriteBit向输出数据寄存器写0或1

  • 写入0时:N-MOS管闭合,P-MOS管断开,输出低电平
  • 写入1时:P-MOS管闭合,N-MOS管断开,输出高电平
3.3.2.3.编程接口3
cpp 复制代码
uint8_t GPIO_ReadInputDataBit(GPIOTypeDef * GPIOx,uint16_t GPIO_Pin);

解析:

  • 参数1:端口号,取A,B,C,D
  • 参数2:引脚编号
  • 返回值:Bit_SET(表示1)Bit_RESET(表示0)

**作用:**从输入数据寄存器读1个比特位

3.3.2.4.编程接口4
cpp 复制代码
uint8_t GPIO_ReadOutputDataBit(GPIOTypeDef* GPIOx, uint16_t GPIO_Pin);

解析:

  • 参数1:端口号,取A,B,C,D
  • 参数2:引脚编号
  • 返回值:Bit_SET(表示1)Bit_RESET(表示0)

**作用:**从输出数据寄存器读1个比特位

**注:**读的是最近一次使用GPIO_WriteBit向输出数据寄存器写入的值

3.3.3.初始化IO引脚
cpp 复制代码
/*初始化GPIO_InitTypeDef结构体*/
GPIO_InitTypeDef GPIO_InitStruct = {0};

/*给GPIO_InitTypeDef结构体成员赋值*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;

/*调用GPIO_Init函数*/
GPIO_Init(GPIOC,&GPIO_InitStruct);

解析:

1.初始化GPIO_InitTypeDef结构体

2.给GPIO_InitTypeDef结构体成员赋值:

  • IO引脚编号设置为13
  • IO引脚最大输出速度为2MHz
  • IO引脚模式设置为通用输出开漏模式

3.调用GPIO_Init函数:

  • 参数1:端口号GPIOC
  • 参数2:GPIO_InitTypeDef结构体的地址
3.3.4.写入数据,点亮Led
cpp 复制代码
/*向输入数据寄存器中写1*/
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
/*向输入数据寄存器中写0*/
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);

解析:

调用GPIO_WriteBit函数:

  • 参数1:端口号CPIOC
  • 参数2:引脚编号设置为13
  • 参数3:写入1,或写入0

**注:**写入1后Led熄灭,写入0后Led点亮

3.3.5.设计Led闪烁
cpp 复制代码
#include <delay.h>

while(1)
{
	/*写1点亮Led*/
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
		
	/*延迟100ms*/
	Delay(100);
		
	/*写0熄灭Led*/
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
		
	/*延迟100ms*/
	Delay(100);
}

解析:

使用delay延迟函数,使用while循环

  • 写入1时,点亮Led,延迟100ms
  • 写入0时,熄灭Led,延迟100ms

**注:**调用delay函数需包含头文件<delay.h>

四、GPIO的4种输入模式

4.1.四种输入模式命名

输入上拉 输入下拉

输入浮空 模拟模式

4.2.输入模式的电路图

4.2.1.保护二极管

作用: 由于人体含有静电,静电的电压一般高达几千伏,如果用手直接触碰IO引脚,高电压进入单片机内部,会把芯片烧坏,所以要设计保护电路来防静电

示例:

假设手指产生+10000V静电,Vdd电压为3.3V,此时上方保护二极管导通,电流从Vdd流出

假设手指产生-10000V静电,Vss电压为0V,此时下方保护二极管导通,电流从引脚口流出

4.2.2.上拉电阻

闭合上拉电阻开关,将输入模式设置为输入上拉

**作用:**给IO引脚提供一个默认的高电压,起到稳定作用

4.2.3.下拉电阻

闭合下拉电阻开关,将输入模式设置为输入下拉

**作用:**给IO引脚提供一个默认的低电压,起到稳定作用

注:

当给IO引脚输入3.3V的高电压时,输入数据寄存器当前数据为1

当给IO引脚输入0V的低电压时,输入数据寄存器当前数据为0

当IO引脚没有电压输入时,处于悬空状态,相当于一根天线,接收空间高低变换的电磁波

导致转换结果不能确定,若不闭合上拉电阻与下拉电阻,输入模式就为输入浮空

但闭合上拉电阻或闭合下拉电阻就可以解决这个问题

**补充:**上拉电阻的工作原理

只闭合上拉电阻开关,不处于悬空状态时,上拉电阻对电路没有影响

处于悬空状态时,施密特触发器的电阻值为无穷大,而上拉电阻值是

常数,根据分压原理,施密特触发器分得的电压为3.3V,转换为数字1

输入数据寄存器可以稳定地读取到1

4.2.4.施密特触发器

**作用:**用于将IO引脚输入的高低电平转换为数字信号0或1

**注:**由于输入电流始终为0,根据欧姆定律,可以等效为一个无穷大的电阻

五、按钮实验

**实验内容:**按下按钮,Led点亮;松开按钮,Led熄灭

5.1.Led的接线方法

5.1.1.接线设计

采用通用推挽模式,接在芯片的PA0引脚上

  • 写入1时:Led点亮
  • 写入0时:Led熄灭
5.1.2.接线安装

Led阳极接限流电阻,然后接在PA0引脚上

Led阴极直接接在最小系统板的GND引脚

**注:**Led较长的一根针为阳极,较短的一根针为阴极

5.1.3.测试代码
cpp 复制代码
/*开启GPIOA的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

/*初始化IO引脚,PA0 通用输出推挽模式 2MHz*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
	
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	
GPIO_Init(GPIOA,&GPIO_InitStruct);

/*向输入数据寄存器写1*/
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);

5.2.按钮的接线方法

5.2.1.接线设计

采用输入上拉模式,接在芯片的PA1引脚上

  • 按钮松开:PA1处于悬空状态,上拉电阻将电压拉高为3.3V,输入值为1
  • 按钮按下:PA1接GND,施密特触发器前的电压为0V,所以输入值为0
5.2.2.接线安装

将按钮安装在PA1引脚与GND之间

5.2.3.测试代码
cpp 复制代码
/*开启GPIOA的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

/*初始化IO引脚,PA1 输入上拉模式*/
GPIO_InitTypeDef GPIO_InitStruct = {0};

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(GPIOA,&GPIO_InitStruct);

5.3.编程接口和代码

cpp 复制代码
#include "stm32f10x.h"

int main(void)
{
	/*开启GPIOA的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	/*初始化IO引脚,PA0 通用输出推挽模式 2MHz*/
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	/*初始化IO引脚,PA1 输入上拉模式*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	while(1)
	{
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1) == Bit_RESET)
		{
			GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
		}
		else
		{
			GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
		}
	}
}

解析:

  • 按钮按下,输入寄存器数据为0,编程接口4返回Bit_RESET,向输出寄存器写1,点亮Led
  • 按钮松开,输入寄存器数据为1,编程接口4返回Bit_SET,向输出寄存器写0,熄灭Led
相关推荐
9稳2 小时前
基于单片机的家庭安全系统设计
开发语言·网络·数据库·单片机·嵌入式硬件
π同学2 小时前
基于RT-Thread的STM32开发第十二讲SD卡篇——DFS文件系统
stm32·dfs·rtthread·sdio
一路往蓝-Anbo2 小时前
第37期:启动流程(二):C Runtime (CRT) 初始化与重定位
c语言·开发语言·网络·stm32·单片机·嵌入式硬件
longxiangam3 小时前
基于esp32p4 的掌机
单片机·嵌入式硬件
代码游侠3 小时前
ARM嵌入式开发代码实践——LED灯闪烁(C语言版)
c语言·开发语言·arm开发·笔记·嵌入式硬件·学习
Aliex_git3 小时前
大模型相关概念 - LLM对话
人工智能·笔记·prompt·ai编程
张祥6422889043 小时前
线性代数本质十笔记
笔记·线性代数·机器学习
Analog1113 小时前
电子秤采用 SIG5530 国产平替 CS5530
人工智能·嵌入式硬件·目标检测·硬件架构·信号处理·智能硬件
这就是佬们吗3 小时前
力扣---leetcode48
java·笔记·后端·算法·leetcode·idea