STM32-GPIO介绍

news/2025/1/12 4:10:05/

目录

1.概述

2.GPIO工作原理

2.1 保护二极管及上下拉电阻

 2.2 GPIO工作模式

2.2.1 浮空输入模式

2.2.2 上拉输入模式

2.2.3 下拉输入模式

2.2.4 模拟输入模式

2.2.5 开漏输出模式

2.2.6 开漏复用输出模式

2.2.7 推挽输出模式

2.2.8 推挽复用输出模式

2.3 注意事项

2.4 GPIO端口复用

2.5 GPIO端口重映射

3.GPIO相关寄存器

3.1 端口配置低寄存器(GPIOx_CRL )

 3.2 端口配置高寄存器(GPIOx_CRH )

 3.3 端口输入数据寄存器(GPIO_IDR)

  3.4 端口输出数据寄存器(GPIO_ODR)

 3.5 端口位设置/清除寄存器(GPIO_BSRR)

  3.6 端口位清除寄存器(GPIO_BRR)

 4.GPIO库函数配置

4.1 重要函数

4.2 初始化函数

4.3 两个读取输入电平函数:

4.3 四个设置输出电平函数:

4.4 库函数配置程序示例

5. GPIO寄存器配置

5.1 寄存器配置程序示例


1.概述

GPIO是STM32最基本的外设之一,下面我们从三个角度来介绍STM32的GPIO,分别是:①GPIO原理、②相关寄存器、③库函数编程

2.GPIO工作原理

GPIO是通用输入输出端口(General-purpose input/output)的英文简写,是所有的微控制器必不可少的外设之一,可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功能。STM32单片机的GPIO被分为很多组,每组有16个引脚,不同型号的MCU的GPIO个数是不同的,比如STM32F103C8T6只有PA、PB以及个别PC引脚而STM32F103ZET6拥有PA~PG的全部112个引脚。所有的GPIO都有基本的输入输出功能,同时GPIO还可以作为其它的外设功能引脚。

作为STM32最基本的外设,GPIO最基本的输出功能是由STM32控制 引脚输出高低电平,比如可以把GPIO接LED灯来控制其亮灭,也可以接继电器或者三极管,通过继电器或三极管来控制外部大功率电路的通断。

GPIO最基本的输入功能是检测外部电平变化,比如把GPIO引脚连接到按键电路,通过电平的高低变化来识别按键是否被按下。

这是GPIO的硬件结构框图,可以从这个框图中清晰的了解GPIO外设极其各种应用模式,最右端的I/O引脚就是STM32芯片引出的GPIO引脚,其它的部件都位于芯片内部。

2.1 保护二极管及上下拉电阻

为了防止芯片被外部过高或者过低的输入电压烧坏,STM32内置保护二极管,当引脚输入电压高于VDD-FT(FT标识代表可以容忍5V电压,不同的引脚对电压的容忍值不同,需要在芯片数据手册上查找,见下图)时上方的二极管导通,当引脚电压低于Vss时,下方的二极管导通,这样就可以防止不正常的电压引入芯片导致芯片烧毁。

      

 2.2 GPIO工作模式

STM32的GPIO共有8种工作模式,分别是输入模式的模拟输入、上拉输入、下拉输入和浮空输入以及输出模式的推挽输出、开漏输出、推挽复用输出和开漏复用输出

为了便于理解,使用结构框图来详细讲解每一种模式:

2.2.1 浮空输入模式

GPIO工作模式——浮空输入

GPIO作为输入功能的浮空输入时,电信号使由外部流向内部的,从结构图的右侧往左侧看,信号流经顺序是①端口——②施密特触发器——③输入数据寄存器——④读取

2.2.2 上拉输入模式

GPIO工作模式——上拉输入

 上拉输入和浮空输入的区别就是在第①和第②之间多了一个上拉电阻,这样GPIO在没有连接外部部件时的默认电平是高电平,其它流程和原来一样。

2.2.3 下拉输入模式

GPIO工作模式——下拉输入

  下拉输入和浮空输入的区别就是在第①和第②之间多了一个下拉电阻,这样GPIO在没有连接外部部件时的默认电平是低电平,其它流程和原来一样。

2.2.4 模拟输入模式

GPIO工作模式——模拟输入

 模拟输入模式和其它三种输入模式不同,它的外部电平信号没有流入输入数据寄存器,而是直接流入模拟输入部分。模拟输入一般是用来ADC读取和转换的。

2.2.5 开漏输出模式

GPIO工作模式——开漏输出

 GPIO 的输出模式比输入模式复杂,首先看开漏输出模式,电平信号由STM32内部流出引脚,因此流向是①写(包括位设置/清除寄存器、输出数据寄存器)——②输出控制电路——③N-MOS管——④I/O端口

位设置/清除寄存器写入的值会映射到输出数据寄存器,最终到达输出控制电路,如果写入的是1,则N-MOS管关闭,由于N-MOS管截止,所以最后输出的电平不会由写入的1来决定,因此此时的输出为高阻态(类似浮空状态),真正的输出电压由外部的上下拉电阻来决定。它具有“线与”特性,也就是说,若有很多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平0伏。若写入0,则N-MOS管处于开启状态,输出电流被拉到VSS,因此可以输出强低电平。输出的电平信号可以被输入数据寄存器读取。

2.2.6 开漏复用输出模式

GPIO模式——开漏复用输出

 开漏复用输出和开漏输出的区别在于信号来源,复用的来源不是内部直接通过输出数据寄存器写的,而是由复用功能的外设决定的。

2.2.7 推挽输出模式

GPIO工作模式——推挽输出

 推挽输出模式和开漏输出模式有一定的区别,其控制输出的寄存器是一样的,但是②部分的写1有效,即输出控制电路输出1的时候,P-MOS管导通,N-MOS管截止,这样I/O口电平就会被P-MOS管拉高,输出强高电平;相反,当输出控制电路输出0时,P-MOS管截止,N-MOS管导通,I/O端口电平被N-MOS管拉低,输出强低电平。同样,输出的电平信号可以被输入数据寄存器读取。

2.2.8 推挽复用输出模式

GPIO工作模式——推挽复用输出

 推挽复用输出和推挽输出的区别在于信号来源,其信号来源是由复用功能相关的通信通道来控制。

2.3 注意事项

注意:

推挽输出可以输出强高低电平(高电平为3.3V),一般用来连接数字器件。在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。

开漏输出只可输出强低电平,高电平需要靠外部电阻拉高。输出端相当于三极管的集电极;要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。开漏输出一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输出5伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5伏,并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5伏电平。

2.4 GPIO端口复用

为了最大限度的利用端口资源,STM32的大部分端口都具有复用功能。

所谓复用,就是一些端口不仅仅可以做为通用IO口,还可以复用为一些外设引脚,比如PA9,PA10可以复用为STM32的串口1引脚。复用情况可以查找数据手册,如下表所示:

 从表格种可以看出,PA9和PA10引脚不仅可以作为GPIO还可以作为串口1的收发引脚使用。

2.5 GPIO端口重映射

为了方便布线  ,STM32配有端口重映射功能,所谓重映射就是可以把某些功能引脚映射到其他引脚。比如串口1默认引脚是PA9,PA10可以通过配置重映射映射到PB6,PB7。

端口的映射情况也可以通过查找数据手册来获得,如下表所示:

 

3.GPIO相关寄存器

STM32的每组GPIO都包含7个寄存器,分别是:

        -  GPIOx_CRL :端口配置低寄存器

        - GPIOx_CRH:端口配置高寄存器

        - GPIOx_IDR:端口输入寄存器

        - GPIOx_ODR:端口输出寄存器

        - GPIOx_BSRR:端口位设置/清除寄存器

        - GPIOx_BRR :端口位清除寄存器

        - GPIOx_LCKR:端口配置锁存寄存器

每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 。

3.1 端口配置低寄存器(GPIOx_CRL

 3.2 端口配置高寄存器(GPIOx_CRH

 3.3 端口输入数据寄存器(GPIO_IDR)

  3.4 端口输出数据寄存器(GPIO_ODR)

 3.5 端口位设置/清除寄存器(GPIO_BSRR)

  3.6 端口位清除寄存器(GPIO_BRR)

 4.GPIO库函数配置

4.1 重要函数

初始化函数:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

2个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

uint16_t  GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

2个读取输出电平函数:

uint8_t  GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

uint16_t  GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

4个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

4.2 初始化函数

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

作用:初始化一个或者多个IO口(同一组)的工作方式和速度。

           该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的

           时候有设置BSRR或者BRR寄存器

   GPIOx: GPIOA~GPIOG

GPIO_InitTypeDef结构体:

 typedef struct    {

uint16_t GPIO_Pin;                           //指定要初始化的IO口     

GPIOSpeed_TypeDef GPIO_Speed; //设置IO口输出速度    

GPIOMode_TypeDef GPIO_Mode;    //设置工作模式:8种中的一个   

}

注意:外设(包括GPIO)在使用之前,几乎都要先使能对应的时钟。

RCC_APB2PeriphColckCmd();

GPIO输出速度:

typedef enum {

GPIO_Speed_10MHz,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

}

GPIOSpeed_TypeDef;

GPIO模式:

typedef enum

{ GPIO_Mode_AIN = 0x0, //模拟输入

GPIO_Mode_IN_FLOATING = 0x04, //浮空输入

GPIO_Mode_IPD = 0x28, //输入下拉

GPIO_Mode_IPU = 0x48, //输入上拉

GPIO_Mode_Out_OD = 0x14, //开漏输出

GPIO_Mode_Out_PP = 0x10, //推挽输出

GPIO_Mode_AF_OD = 0x1C, //开漏复用输出

GPIO_Mode_AF_PP = 0x18 //推挽复用输出

}GPIOMode_TypeDef;

GPIO_Init函数初始化样例:

GPIO_InitTypeDef  GPIO_InitStructure;  

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz  GPIO_Init(GPIOB, &GPIO_InitStructure);  //根据设定参数初始化GPIOB.5

可以一次初始化一个IO组下的多个IO,前提是这些IO口的配置方式一样。

4.3 两个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平

 作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。

4.3 四个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

作用:设置某个IO口输出为高电平(1)。实际操作BSRR寄存器

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

作用:设置某个IO口输出为低电平(0)。实际操作的BRR寄存器。

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

这两个函数不常用,也是用来设置IO口输出电平。

4.4 库函数配置程序示例

下面我们以流水灯案件为例,把整个GPIO的库函数配置过程展现出来:

//led.h头文件
#ifndef __LED_H
#define __LED_H
#include "sys.h"void LED_Init(void);#endif
//led.c源文件
#include "led.h"
#include "stm32f10x.h"
void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOB和EGPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_Init(GPIOE, &GPIO_InitStructure);GPIO_SetBits(GPIOE, GPIO_Pin_5);	
}
//main.c主程序
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"int main(void)
{
delay_init();
LED_Init();while(1){GPIO_ResetBits(GPIOB, GPIO_Pin_5); //LED0即DS0亮GPIO_SetBits(GPIOE, GPIO_Pin_5);   //LED1即DS1灭delay_ms(500);GPIO_SetBits(GPIOB, GPIO_Pin_5);   //LED0即DS0灭GPIO_ResetBits(GPIOE, GPIO_Pin_5); //LED1即DS1亮delay_ms(500);
}
}

5. GPIO寄存器配置

库函数的优点在于移植性好、便于理解、方便学习,是我们一般编程常常使用的。但是如果只会用库函数编程,寄存器内部工作原理不闻不问,当你拿到一份带有寄存器配置片段的程序时就会一头雾水。因此,理解寄存器的配置对于更深一步的学习掌握STM32这个MCU以及在真正的工程总运用也是尤为重要的。

5.1 寄存器配置程序示例

下面是流水灯例程的寄存器版本程序,其中led.h和库函数一样的,这里就不展示了。

//led.c源文件
#include "led.h"
#include "stm32f10x.h"void LED_Init(void){RCC->APB2ENR|=1<<3;RCC->APB2ENR|=1<<6;//GPIOB.5GPIOB->CRL&=0xFF0FFFFF;//与运算,使GPIOB的CRL寄存器第20~23位(PB5)清零GPIOB->CRL|=0x00300000;//或运算,使GPIOB的CRL寄存器第20~23位置位0011,即设置为推挽输出、速率为50MHzGPIOB->ODR|=1<<5;//或运算,使GPIOB的输出数据寄存器ODR第5位置1即PB5输出高电平GPIOE->CRL&=0xFF0FFFFF;//与运算,使GPIOE的CRL寄存器第20~23位(PE5)清零GPIOE->CRL|=0x00300000;//或运算,使GPIOE的CRL寄存器第20~23位置位0011,即设置为推挽输出、速率为50MHzGPIOE->ODR|=1<<5;//或运算,使GPIOE的输出数据寄存器ODR第5位置1即PE5输出高电平//GPIOE.5
}
//main.c主程序
#include "sys.h"
#include "usart.h"		
#include "delay.h"	 
#include "led.h"int main(void)
{				 while(1){GPIOB->ODR|=1<<5;//或运算,使GPIOB的输出数据寄存器ODR第5位置1即PB5输出高电平GPIOE->ODR|=1<<5;//或运算,使GPIOE的输出数据寄存器ODR第5位置1即PE5输出高电平delay_ms(500);GPIOB->ODR&=~(1<<5);//与运算,使GPIOB的输出数据寄存器ODR第5位置0即PB5输出低电平GPIOE->ODR&=~(1<<5);//与运算,使GPIOE的输出数据寄存器ODR第5位置0即PE5输出低电平delay_ms(500);}
} 


http://www.ppmy.cn/news/724281.html

相关文章

stm32的DMA+ADC多通道数据采集

1前言 硬件&#xff1a;stm32f103rct6&#xff0c;输入大容量产品。 软件&#xff1a;keil MDK5.0 固件库&#xff1a;stm32f1标准外设库。 调试软件&#xff1a;友善串口助手 stm32有多达16个通道&#xff0c;常用的采样方法有两种&#xff0c;一是分时采集每个通道的数据&am…

STM32F407多路串口通信进行数据收发

一直被说是就不能把几个串口放在一起&#xff0c;写个标准例程直接用&#xff0c;非要每次用哪个串口才现场改程序&#xff0c;被迫把usart1,usart2,usart3进行了资源整合&#xff0c;挂在这以备不时之需。 功能简述&#xff1a; 串口1&#xff0c;串口2&#xff0c;串口3串口…

乐鑫Esp32学习之旅 20 一篇好文,开发过程中编译esp32固件太大,无法正常启动?教你如何自定义分区表partitions.csv。

本系列博客学习由非官方人员 半颗心脏 潜心所力所写&#xff0c;仅仅做个人技术交流分享&#xff0c;不做任何商业用途。如有不对之处&#xff0c;请留言&#xff0c;本人及时更改。 1、 爬坑学习新旅程&#xff0c;虚拟机搭建esp32开发环境&#xff0c;打印 “Hellow World”。…

stm32F103C8T6基于FreeRTOS操作系统的多任务

目录 一、FreeRTOS简介1.什么是FreeRTOS?2. FreeRTOS特点 二、创建项目三、编写代码四、编译烧录五、总结参考链接 一、FreeRTOS简介 1.什么是FreeRTOS? 我们看一下FreeRTOS的名字&#xff0c;可以分为两部分:Free和 RTOS&#xff0c;Free 就是免费的、自由的、不受约束的意…

深入理解STM32内存管理

参考&#xff1a;详解ROM和RAM 作者&#xff1a;嵌入式实验楼 网址&#xff1a;https://mp.weixin.qq.com/s/y2aG7kX-6CTyeMzEJW_YHw 内存相关博文&#xff1a; 1、内存四区&#xff08;代码区 静态区 栈区 堆区&#xff09; 2、程序运行时对应的内存分布&#xff08;BSS段、数…

stm32F103C8T6基于FreeRTOS操作系统的多任务(STM32CUBEMX)

文章目录 一、简介二、任务要求三、创建项目三、编写任务代码四、效果五、参考 一、简介 FreeRTOS&#xff0c;是指实时操作系统&#xff0c;是可以多任务进行的一个操作系统&#xff0c;相当于裸机开发而已&#xff0c;任务的实现相对方便很多。FreeRTOS(读作"free-arr-…

32位机器最大支持开多少个线程?

http://blog.csdn.net/tony_wong/article/details/38978185 https://www.zhihu.com/question/29468200?sortcreated 小结&#xff1a;理论上&#xff0c;一个用户进程最大可以分配的内存是2G&#xff08;实际能用的大约为1.5G&#xff09;&#xff0c;一个线程栈需要预留1M内…

STM32—ADC多通道采集电压

文章目录 ADC详解程序说明函数主体引脚配置ADC和DMA配置主函数 ADC详解 前面的博客中详细介绍了STM32中ADC的相关信息&#xff0c;这篇博客是对ADC内容的一个总结提升&#xff0c;ADC的详细介绍&#xff1a;ADC详解 程序说明 为了使这次代码阅读方便&#xff0c;博主没有在头…