手把手教你国产化嵌入式(3.1)GPIO外设使用-寄存器+库函数介绍

[复制链接]
698|1
手机看帖
扫描二维码
随时随地手机跟帖
nbutjyy|  楼主 | 2024-8-22 22:28 | 显示全部楼层 |阅读模式
GPIO简介
GPIO(General Purpose Input Output)是通用输入输出引脚,它是STM32芯片上的数字接口,可配置为8种输入输出模式,。可以使用寄存器级操作进行配置和控制,因此具有灵活性和可编程性。
引脚电平:0V~3.3V,部分引脚可容忍5V(在GD32F103RCT6引脚定义中,带FT的,可以容忍5V)
每个GPIO引脚可以由软件配置为输出(推挽或开漏)、输入、外设的备用功能或者模拟模式。每个GPIO引脚都可以配置为上拉、下拉或无上拉/下拉。
输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等。
输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等。
以下为用户手册解读:
                                                    5297366c747d338351.png
9317666c747dc1357e.png
8804966c747e2be864.png
3611566c747ea13627.png
         



     
这是官网给的结构框图,但是写的太简陋了,所以我下面又贴了一张STM32的,大家可以对照进行学习
798866c747f3e6ca7.png
3679266c747fb46b03.png





     

GPIO引脚配置
这一块的话看GD32的手册要更好理解一点
     
注意:
在复位期间或复位之后,备用功能并未激活,所有GPIO端口都被配置成输入浮空模式,这种输入模式禁用上拉(PU)/下拉(PD)电阻。但是复位后,串行线调试端口(JTAG/Serial-Wired Debug pins)为输入PU/PD模式:
PA15:JTDI为上拉模式;
PA14:JTCK / SWCLK为下拉模式;
PA13:JTMS / SWDIO为上拉模式;
PB4:NJTRST为上拉模式;
PB3:JTDO为浮空模式。
所以我们这个时候如果想去使用这几个引脚去作为输入输出的时候发现是不行的,大家这个时候可能就会去到处找资料了,
那么这里,我们对PB3PB4进行重映射!
你可能会问,为什么不对PA14PA15重映射呢?
那是因为外面前面两章用到的ST-Link下载代码所需要的引脚,刚好就是这两个引脚,一个是SWCLK另外一个是SWDIO
所以我们这里只需要对PB3和PB4进行重映射就行!
STM32:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);
//使能GPIOB时钟和复用功能(要先打开复用才能修改复用功能)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
//要先开时钟,再重映射;这句表示关闭JTAG,使能SWD
GD32:
//管脚复用时钟使能
rcu_periph_clock_enable(RCU_AF);
//PB4管脚默认是NJTRST,要当GPIO,需要重映射
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
那么我们这里在初始化时钟和复用以后,再调用这两句就可以打开PB3PB4这两个引脚了!
GPIO的八种工作模式
  
模式名称
  
性质
特征
浮空输入
数字输入
可读取引脚电平,若引脚悬空,则电平不确定
上拉输入
数字输入
可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
下拉输入
数字输入
可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入
模拟输入
GPIO无效,引脚直接接入内部ADC
开漏输出(N-MOS)
数字输出
可输出引脚电平,高电平为高阻态,低电平接VSS
推挽输出(P/N -MOS)
数字输出
可输出引脚电平,高电平接VDD,低电平接VSS
复用开漏输出
数字输出
由片上外设控制,高电平为高阻态,低电平接VSS
复用推挽输出
数字输出
由片上外设控制,高电平接VDD,低电平接VSS
以下8种模式介绍引用自野火stm32论坛:
1.输入浮空模式(Floating Input Mode
在该模式下,GPIO引脚处于高阻态且未选通上拉或下拉电阻。这种模式适用于数字输入信号不需要精度要求的场合,例如控制系统中一些状态量检测、接近传感器等的信号输入。但是,在使用输入浮空模式时,需要注意防止静电干扰和误操作。
举例:在一个控制系统中,检测两个机械部件之间距离的传感器,只需输出0或1两个状态值,可以使用输入浮空模式
2.输入上拉模式(Input with Pull-up Mode
在该模式下,GPIO引脚通过一个上拉电阻与VDD相连。当外部电路未连接时,引脚被拉向高电平。这种模式适用于需要稳定输入信号的场合,如按键开关、震动传感器等的信号输入。此模式适用于数字输入信号需要精度要求的场合。
举例:在嵌入式设备中,如果需要使用按键来进行控制,可以将GPIO引脚配置为输入上拉模式,并将按键连接到引脚和地之间,在此模式下,按键不被按下时,引脚处于高电平状态,当按键被按下时,引脚变为低电平状态。
3.输入下拉模式(Input with Pull-down Mode
在该模式下,GPIO引脚通过一个下拉电阻与GND相连。当外部电路未连接时,引脚被拉向低电平。这种模式同样适用于需要稳定输入信号的场合,如按键开关、震动传感器等的信号输入。此模式同样适用于数字输入信号需要精度要求的场合。
举例:在嵌入式设备中,如果需要使用按键来进行控制,可以将GPIO引脚配置为输入下拉模式,并将按键连接到引脚和VDD之间,在此模式下,当按键不被按下时,引脚处于低电平状态,当按键被按下时,引脚变为高电平状态。
4.模拟输入模式(Analog Input Mode
在该模式下,GPIO引脚被配置为模拟信号输入。ADC模块可以将引脚读取到的模拟信号转换成数字信号进行处理。这种模式适用于需要精确模拟量信号输入的场合,如温度传感器、光传感器等。
举例:在一个机器人系统中,需要使用光传感器来检测周围环境的亮度。可以将GPIO引脚配置为模拟输入模式,并将光传感器连接到引脚和地之间,此时ADC模块可以将读取到的模拟信号转换成数字信号进行处理。
5.开漏输出模式(Open-drain Output Mode
在该模式下,GPIO引脚可以输出低电平信号,但输出高电平信号时变为高阻态。需搭配一个外部上拉电阻使引脚运作正确。开漏输出模式适用于驱动外部设备,如LED灯、数码管等。此模式适用于外部设备控制信号输出的场合。
举例:STM32使用I2C通讯时,SDA和SCL都要使用开漏输出模式。这是因为I2C通讯总线中,SDA和SCL线都可能出现多主机同时发送数据的情况,为避免数据冲突,需要将SDA和SCL配置成开漏输出模式,并且使用外部上拉电阻将它们拉升到高电平。
6.推挽输出模式(Push-pull Output Mode
在该模式下,GPIO引脚可以输出高、低电平信号。推挽输出模式适用于直接驱动负载场合,如电机、继电器等的输出驱动。此模式适用于直接驱动负载的控制信号输出的场合。
举例:在一个机器人系统中,需要通过GPIO引脚来控制机器人的运动方向,例如前进、后退、左转、右转等。可以将GPIO引脚配置为推挽输出模式,并将引脚连接到电机驱动芯片,此时引脚可以直接驱动电机的正反转
7.开漏式复用功能模式(Open-drain Alternate Function Mode
在该模式下,GPIO引脚可以被配置为一些标准的或自定义的功能,例如I2C总线通讯的SCL时钟线。这种模式下,GPIO引脚被配置为开漏输出模式,适用于驱动外部设备或总线通讯。
举例:在一个机器人系统中,需要使用I2C总线来进行控制。可以将GPIO引脚配置为开漏式复用功能模式,并将SCL连接到引脚上。此时,引脚被配置为开漏输出模式,可以驱动I2C总线中的SCL时钟线。
8.推挽式复用功能模式(Push-pull Alternate Function Mode
在该模式下,GPIO引脚可以被配置为一些标准的或自定义的功能,例如USART通信的TX、RX数据线。这种模式下,GPIO引脚被配置为推挽输出模式,适用于直接驱动负载或者数据通讯。
举例:在一个机器人系统中,需要使用串口通信来进行数据传输。可以将GPIO引脚配置为推挽式复用功能模式,并将TX、RX数据线连接到引脚上。此时,引脚被配置为推挽输出模式,可以直接驱动负载或进行数据通讯。
GPIO寄存器
虽然我知道大家对应寄存器这种生涩难懂的东西不是很想接触,但是毕竟是出一个教程,加上很多时候找问题的时候我们都会返回寻找寄存器,所以我这里还是需要讲一下各个寄存器
如果对寄存器不感兴趣的同学,可以跳过本小结!

注意:我在本教程的寄存器讲解会以寄存器+我的解释去书写方便同学们理解
首先要讲的就是外设基地址:
3382066c74958d9b12.png
2 个 32位端口配置寄存器(CTL0 和CTL1)

作用:用来配置模式和端口的速度可写可读
8528466c74974b8aa1.png
2850266c7497af3d90.png
每组GPIO有16个IO引脚,CTL0控制端口的低8个IO引脚, CTL1控制端口的高8个IO引脚,每个IO引脚由4个位控制。

高2位为CTL配置IO口工作方式:
9108666c7498c8389e.png
212966c74993eba80.png
低2位为MD配置IO口的输入/出和端口速度:
9743866c749a10ed37.png
2 个 32 位端口数据寄存器(ISTAT 和OCTL)
作用:用来控制IO口数据输出和检测IO口数据输入。


                                               OCTL(可写可读)
6284966c749bc27091.png
这里低16位输出为全1,对应IO口输出高电平

低16位输出为全0,对应IO口输出低电平
2707566c749ca2d1c8.png
ISTAT(只读)
5610766c749e67a586.png
ISTATy[15:0]端口输入数据(y=0...15
这些位为只读并只能以字(16位)的形式读出。

                                                    读出的值为对应的I/O口的状态。
9200866c749fe4f8f2.png
1 个 32 位端口置位/复位寄存器(BOP)
作用:用来控制IO口输出的高低电平,即OCTL寄存器的低16位为全0还是全1。

只能写不能读。
2302666c74a0f726d5.png
高16位控制OCTL寄存器低16位为全0还是保持:0为保持,1为设置为全0并且IO口输出低电平。

低16位控制OCTL寄存器低16位为全1还是保持:0为保持,1为设置为全1并且IO口输出高电平。
6918966c74a1d59da2.png
1 个 32 位端口锁定寄存器 (LOCK)


作用:用来控制0-15IO口锁定状态(可读可写)
6741666c74a2e87ac3.png
高15位保留,始终为0,第16位控制某个IO口是否被锁,低16位为选定0-15的IO口,第16位实际上是控制ISTAT和OCTL对应某个IO口对应的4个位是否能被修改。
第16位具体使用方式如下:
当LOCK寄存器的第16位被设置为1时,表示将要锁定相应的GPIO端口,此时需要向LOCK寄存器写入两次特定的数据来最终锁定该端口。具体步骤如下:
1.将控制寄存器中的相应引脚配置为输入模式或输出模式,并设置所需的速度、推挽/开漏等其他参数。
2.将LOCK寄存器的第16位设置为1以锁定该端口。
3.将LOCK寄存器的第16位(即LKK位)设置为1表示准备锁定相应的GPIO端口。此时GPIO端口还未被锁定,但已经被预备锁定。如果在锁定状态下尝试修改GPIO端口的配置,则会导致错误发生。
4.向LOCK寄存器中写入任意值,以便进行第4步的确认操作。
5.将LOCK寄存器中的值反转后再次写入相同的值,确认锁定操作。
6.在确认操作之前,需要反转LOCK寄存器中的值(即按位取反),然后再次向LOCK寄存器中写入相同的值。如果确认操作成功,GPIO端口将被锁定并且无法再被修改。
如果需要解除GPIO端口的锁定状态,则需要通过复位整个芯片或者读取LOCK寄存器来检查其状态,并执行相应的解锁操作。例如,可以使用特殊的序列来解锁GPIO端口:先将LOCK寄存器的第16位(LOCK位)清零,然后再向LOCK寄存器中写入任意值,最后再次向LOCK寄存器中写入相同的值即可解锁GPIO端口。需要注意的是,在使用GPIO端口锁定功能时,只有部分引脚支持GPIO端口锁定功能,具体请参考芯片的数据手册或相关技术文档。
1990866c74a41231da.png
GPIO 的锁定机制可以保护 I/O 端口的配置。 被保护的寄存器有 GPIOx_CTL0 和 GPIOx_CTL1。
通过配置 32 位锁定寄存器(GPIOx_LOCK) 可以锁定 I/O 端口的配置。
通过特定的锁定序列配置GPIOx_LOCK 中的 LKK 位和 LKy 位, 相应的端口位被锁定,直到下一个复位前,相应端口位的配置都不能修改。
建议在电源驱动模块的配置中使用锁定功能。
GPIO库函数
GPIO的库函数声明都在"GD32f10x_gpio.h"文件中。
官方资料路径:GD32F10x_Firmware_Library_V2.2.4\Firmware\GD32F10x_standard_peripheral\Include\gd32f10x_gpio.h
将指定GPIO端口配置为指定参数
函数声明如下:
void gpio_init(uint32_t gpio_periph,uint32_tmode,uint32_t speed,uint32_t pin);
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
mode
参数2
GPIO引脚模式
speed
参数3
GPIO输出最大速度最大
pin
参数4
GPIO引脚x(x=0…15)
返回
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO_MODE_AIN: analog input mode(模拟输入)
GPIO_MODE_IN_FLOATING: floating input mode(浮空输入)
GPIO_MODE_IPD: pull-down input mode(下拉输入)
GPIO_MODE_IPU: pull-up input mode(上拉输入)
GPIO_MODE_OUT_OD: GPIO output with open-drain(开漏输出)
GPIO_MODE_OUT_PP: GPIO output with push-pull(推挽输出)
GPIO_MODE_AF_OD: AFIO output with open-drain(复用开漏输出)
GPIO_MODE_AF_PP: AFIO output with push-pull(复用推挽输出)
参数3:
GPIO_OSPEED_10MHZ: output max speed 10MHz(输出速度最大为10MHz)
GPIO_OSPEED_2MHZ: output max speed 2MHz(输出速度最大为2MHz)
GPIO_OSPEED_50MHZ: output max speed 50MHz(输出速度最大为50MHz)
参数4:
GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
将指定引脚设置为指定电平
函数声明如下:
void gpio_bit_write(uint32_t gpio_periph, uint32_t pin,bit_status bit_value);
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
pin
参数2
GPIO引脚x(x=0…15)
bit_value
参数3
SET设置或RESET清除
返回
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
参数3:
RESET: clear the port pin 设置0
SET: set the port pin 设置1
例:将GPIOA的第1个引脚设置为高电平
gpio_bit_write(GPIOA,GPIO_PIN_1,SET)

将指定引脚设置为高电平
函数声明如下:
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
pin
参数2
GPIO引脚x(x=0…15)
返回
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
例:将GPIOA的第1个引脚设置为高电平
gpio_bit_set(GPIOA,GPIO_PIN_1)
将指定引脚设置为低电平
函数声明如下:
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
pin
参数2
GPIO引脚x(x=0…15)
返回
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
例:将GPIOA的第1个引脚设置为低电平
gpio_bit_reset(GPIOA,GPIO_PIN_1)
将指定端口所有引脚设置为指定值
函数声明如下:
void gpio_port_write(uint32_t gpio_periph,uint16_t data)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
data
参数2
GPIO引脚x(x=0…15)要输出的值,取值范围为0到FFFF(16位)
返回
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
要输出的值,取值范围为0到FFFF(16位)
例:将PA0~PA7引脚全部设置为高电平
gpio_port_write(GPIOA, 0xFF);
读取指定GPIO端口和引脚号对应的输入状态
函数声明如下:
FlagStatus gpio_input_bit_get(uint32_tgpio_periph,uint32_t pin)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
pin
参数2
GPIO引脚x(x=0…15)
返回
SET高电平或RESET低电平/0或1
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO引脚x(x=0…15)

返回:
SET高电平或RESET低电平/0或1
实际使用时,要先对GPIO对应的端口和引脚配置为输入模式,然后才能正确读取其输入状态
读取指定GPIO端口的输入数据
函数声明如下:
uint16_t gpio_input_port_get(uint32_t gpio_periph)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
返回
返回值是一个16位的无符号整数,表示指定GPIO端口上各个引脚的电平状态(1为高电平,0为低电平)。
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
返回:
要输出的值,取值范围为0到FFFF(16位)
读取GPIOx端口的输入数据,保存在16位变量input_data中
此时通过观察input_data变量的第五位二进制数可以得到Px5的引脚状态。
读取指定GPIO端口的指定引脚的输出状态
函数声明如下:
FlagStatus gpio_output_bit_get(uint32_t gpio_periph,uint32_t pin)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
pin
参数2
GPIO引脚x(x=0…15)
返回
函数返回值为一个无符号8位整数(uint8_t),表示指定引脚的状态,如果该引脚为高电平,则返回1,否则返回0。
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
参数2:
GPIO引脚x(x=0…15)
返回:
函数返回值为一个无符号8位整数(uint8_t),表示指定引脚的状态,如果该引脚为高电平,则返回1,否则返回0。
(output status of gpiopin: SET or RESET)
例:PA0_state =gpio_output_bit_get(GPIOA, GPIO_Pin_0);
读取指定GPIO端口的输出数据
函数声明如下:
uint16_tgpio_output_port_get(uint32_t gpio_periph)
参数:
  
gpio_periph
  
参数1
GPIO端口x(x = A,B,C,D,E,F,G)
返回
返回值是一个16位的无符号整数,表示指定GPIO端口上各个引脚的电平状态(1为高电平,0为低电平)。
参数1:
GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOF
返回:
返回值是一个16位的无符号整数,表示指定GPIO端口上各个引脚的电平状态(1为高电平,0为低电平)。
(output status of gpio all pins)
例:
uint16_t output_data;
output_data = gpio_output_port_get(GPIOB); // 将GPIOB端口的输出数据读取到 output_data 变量中
配置GPIO引脚重映射
函数声明如下:
void gpio_pin_remap_config(uint32_t remap, ControlStatusnewvalue)
参数:
  
remap
  
参数1
选择重映射
newvalue
参数2
是否使能,ENABLE使能或DISABLE除能
返回
参数1:
选择重映射

(太多了,写不下!)上图片!
3220766c74a64a9c34.png
参数2:
是否使能,ENABLE使能或DISABLE失能
库函数介绍到此完毕,请看下一小结继续!
因为要保持一小结不能太长的原则

7099266c74811e1772.png
2750566c7484b2b69d.png
8593666c7485fc1fdb.png
6207466c74866cdee3.png
7618266c7488a4741f.png
161666c748b765888.png

使用特权

评论回复
发货后已经wi| | 2024-9-30 23:41 | 显示全部楼层
设的备用功能或者模拟模式。每个GPIO引脚都可以配置为上拉、

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

11

帖子

1

粉丝