基于寄存器、基于库函数
引脚描述
GPIO是MCU与外设设备连接、实现人机交互的基本接口
通过GPIO端口内部寄存器动态地配置为输入或输出,可以同时对任意个输出引脚进行置位或清零,也可以读出输出寄存器的值以及引脚的当前状态。
STM32F103微控制器最多可以提供112个多功能双向I/O引脚
端口号:端口号通常以大写字母命名,从A开始,依次类推。例如,GPIOA、GPIOB、GPIOC、…等。 引脚号:每个端口有16个I/O引脚,分别命名为0-15。例如,STM32F103RCT6微控制器的GPIOA端口有16个引脚,分别为PA0、PA1、PA2、PA3、…、PA14和PA15。
通用输入输出、复用为其他接口的引脚 ,通过内部寄存器的设置
流水灯、按键控制LED灯(仿真proteus)
内部结构
工作模式
输入模式
输入浮空(GPIO_Mode_IN_FLOATING) ****
在此状态下,I/O口的电平信号进入输入数据寄存器,此时的I/O电平信号是不确定的,完全由外部输入决定,如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的,且电压具有不确定性。
输入上拉 (GPIO_Mode_IPU) ******
上拉就是将一个不确定的信号拉到一个固定的值,如上图所示,通过I/O口来的信号就被上拉电阻拉到了VDD。所以,和浮空输入相比来说,当I/O口被悬空的状态下,输入端的电平可以保持在高电平。
输入下拉 (GPIO_Mode_IPD) *****
下拉与上拉类似,通过I/O口来的信号被下拉电阻拉到了VSS,当I/O口被悬空的状态下,输入端的电平可以保持在低电平。
模拟输入 (GPIO_Mode_AIN)
模拟输入模式下,I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块,比如ADC模块等等。
输出模式
开漏输出 (GPIO_Mode_Out_OD)
输出寄存器上的‘0’激活N-MOS,而输出寄存器上的‘1’将端口置于高阻态(P-MOS从不被激活)。 N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平。所以开漏输出只能输出强低电平,高电平得靠外部电阻拉高。
开漏复用功能 (GPIO_Mode_AF_OD)
开漏复用与开漏类似,只是电平信号的来源不是来自CPU的输出数据寄存器,而是来自片上外设模块。
推挽式输出 (GPIO_Mode_Out_PP) ****
输出寄存器上的‘0’激活N-MOS,而输出寄存器上的‘1’将激活P-MOS。P-MOS管和N-MOS管,当设置输出的值为高电平的时候,P-MOS管处于开启状态,N-MOS管处于关闭状态,此时I/O端口的电平就由P-MOS管决定:高电平;当设置输出的值为低电平的时候,P-MOS管处于关闭状态,N-MOS管处于开启状态,此时I/O端口的电平就由N-MOS管决定:低电平。所以推挽输出可以输出强高低电平,连接数字器件。
推挽式复用功能 (GPIO_Mode_AF_PP)
推挽复用与推挽类似,只是电平信号的来源不是来自CPU的输出数据寄存器,而是来自片上外设模块。
STM32F103R6 具有GPIOA(PA[15:0])、GPIOB(PB[15:0])、GPIOC(PC[15:0])、GPIOD(PD[2:0])四个GPIO端口,共51个输入/输出引脚。这些GPIO引脚都可以通过软件动态配置为输出(推挽输出或开漏输出)、输入(带或不带上拉或下拉电阻)或复用的外设功能端口。多数GPIO引脚都与数字或模拟的复用外设共用。除了具有模拟输入功能的端口外,其他所有GPIO引脚都有大电流通过能力。GPIO寄存器可以同时对任意若干个输出引脚进行置位或清零操作。用户可以读出输出寄存器的值及引脚的当前状态。
GPIO引脚的输出速度
STM32微控制器I/O引脚内部有多个响应速度(2MHz,10MHz,50MHz)不同的驱动电路,用户可根据自己的需要选择合适的驱动电路。
对于连接LED、数码管和蜂鸣器等外部设备,一般设置为2MHz。
对于串口来说,这样只需要用2MHz的GPIO的引脚速度就可以了。
对于I2C接口,可以选用10MHz的GPIO引脚速度。
对于SPI接口,需要选择呢50MHz的GPIO引脚速度 对于用作FSMC复用功能连接存储器的输出引脚,一般设置为50MHz的I/O引脚速度。
内部寄存器
用户使用通用GPIO接口来实现人机交互的过程就是通过编程来操作相应GPIO端口内部寄存器的过程。编程时,可以通过端口地址来访问对应的GPIO端口中相应的寄存器。
*配置寄存器GPIOx_CRL和GPIOx_CRH:
32位,设置GPIO引脚的工作模式和输出速率。
GPIOx_CRL——[7:0], GPIOx_CRH ——[15:8]
输入数据寄存器GPIOx_IDR:32位
输出数据寄存器GPIOx_ODR:32位
*置位/复位寄存器GPIOx_BSRR:32位*
复位寄存器GPIOx_BRR: 16位
锁定寄存器GPIOx_LCKR: 32位
配置寄存器GPIOx_CRL
GPIOx_CRH
输入数据寄存器 GPIOx_IDR
输出数据寄存器GPIOx_ODR
位设置/清除寄存器BSRR(之前的图里)
端口位设置/清除寄存器 GPIOx_BSRR
低十六位输出高电平。高十六位输出低电平
端口位清除寄存器 GPIOx_BRR
APB2外设时钟使能寄存器 RCC_APB2ENR
GPIO库函数开发原理
(1)直接操作端口寄存器 (移位)
假设GPIO端口的引脚PA0连接了LED灯,其电路连接为低电平点亮LED灯,高电平熄灭LED灯。其底层操作过程如下:
使能外设时钟
初始化GPIO引脚
操作控制
GPIOA_CRL的地址:0x4001 0800 + 0x00 = 0x4001 0800
GPIOA_ODR的地址:0x4001 0800 + 0x0C = 0x4001 080C
RCC_APB2ENR的地址:0x4002 1000 + 0x18 = 0x4002 1018
宏定义
bite2
按照CRL进行配置
(2)将端口寄存器封装成结构体
定义一种 GPIO 端口的结构体,结构体的地址为端口的基地址,结构体的成员为端口寄存器,成员的顺序按照寄存器的偏移地址从低到高排列,成员类型跟寄存器类型相同。操作寄存器时,操作该结构体的成员即可。
(3)封装成库函数
库函数是架设在寄存器和用户代码之间的代码,向下与寄存器相关,向上为用户提供相关接口,开发人员不需要特别关注底层寄存器的操作,可以提高程序的可读性和可移植性,有利于快速开发和维护。 在外设结构体的基础上按照功能的不同进一步封装成不同的库函数 把外设寄存器的每个位置为 1 都用宏定义来实现