STM32F103C8T6的GPIO与AFIO功能详解:通用与复用功能I/O及寄存器映射解析
1 GPIO功能描述
1.1 每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL, GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。
根据数据手册中列出的每个I/O端口的特定硬件特征, GPIO端口的每个位可以由软件分别配置成多种模式。
─ 输入浮空
─ 输入上拉
─ 输入下拉
─ 模拟输入
─ 开漏输出
─ 推挽式输出
─ 推挽式复用功能
─ 开漏复用功能
每个I/O端口位可以自由编程,然而必须按照32位字访问I/O端口寄存器(不允许半字或字节访问)。 GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器进行读/更改的独立访问;这样,在读和更改访问之间产生IRQ时不会发生危险。
下图给出了一个I/O端口位的基本结构
Vdd_ft,部分io口可以容忍5V
1.2 端口位配置表
在实际使用中,可以根据具体的需求来选择合适的输出模式。例如,如果需要输出强高低电平并连接数字器件,可选择通用推挽输出模式;如果要连接不同电平的器件或实现特定的电平转换,通用开漏输出模式可能更合适;而当 GPIO 被用作其他外设功能时,则需根据外设的要求选择复用功能推挽输出模式或复用功能开漏输出模式。同时,在使用开漏输出模式时,通常需要接上拉电阻以确保能输出高电平。
1.3 输出模式位
1.4 复用功能(AF)
使用默认复用功能前必须对端口位配置寄存器编程。
● 对于复用的输入功能,端口必须配置成输入模式(浮空、上拉或下拉)且输入引脚必须由外部
驱动。
注意: 也可以通过软件来模拟复用功能输入引脚,这种模拟可以通过对GPIO控制器编程来实现。此时,端口应当被设置为复用功能输出模式。显然,这时相应的引脚不再由外部驱动,而是通过GPIO控制器由软件来驱动。
● 对于复用输出功能,端口必须配置成复用功能输出模式(推挽或开漏)。
● 对于双向复用功能,端口位必须配置复用功能输出模式(推挽或开漏)。这时,输入驱动器被
配置成浮空输入模式。
如果把端口配置成复用输出功能,则引脚和输出寄存器断开,并和片上外设的输出信号连接。如果软件把一个GPIO脚配置成复用输出功能,但是外设没有被激活,它的输出将不确定。
2 GPIO寄存器描述
2.1 调用GPIO初始化函数,就可以直接初始化成为默认值
2.2 两个32位配置寄存器(GPIOx_CRL, GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。
1.端口配置低寄存器(GPIOx_CRL) (x=A..E)可读可写
2.端口配置高寄存器(GPIOx_CRH) (x=A..E)
3.端口输入数据寄存器(GPIOx_IDR) (x=A..E)
4.端口输出数据寄存器(GPIOx_ODR) (x=A..E)
5.端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E) 6.端口位清除寄存器(GPIOx_BRR) (x=A..E)
7. 端口配置锁定寄存器(GPIOx_LCKR) (x=A..E)
当执行正确的写序列设置了位16(LCKK)时,该寄存器用来锁定端口位的配置。位[15:0]用于锁定GPIO端口的配置。在规定的写入操作期间,不能改变LCKP[15:0]。当对相应的端口位执行了LOCK序列后,在下次系统复位之前将不能再更改端口位的配置。
每个锁定位锁定控制寄存器(CRL, CRH)中相应的4个位。
3 寄存器映射
3.1寄存器是特殊的存储器,给寄存器地址命名的过程,就叫做寄存器映射
3.2 寄存器解读
- 寄存器名字
- 偏移量及复位值
- 寄存器位表
- 位功能描述
3.3 寄存器映射举例
3.4 寄存器地址计算
为了方便编写代码及使用,我们将寄存器地址分为三个部分:
1、总线基地址(BUS_BASE_ADDR)
2、外设基于总线基地址的偏移量(PERIPH_OFFSET)
3、寄存器相对外设基地址的偏移量(REG_OFFSET)
寄存器地址= BUS_BASE_ADDR + PERIPH_OFFSET + REG_OFFSET
3.5 总线基地址
3.6 GPIO外设基地址及偏移量
所属总线 |
外设
|
基地址
|
偏移量
|
APB2 0X4001 0000
|
GPIOA |
0X4001 0800 |
0X8000 |
GPIOB |
0X4001 0C00 |
0XC000 |
|
GPIOC |
0X4001 1000 |
0X1000 |
|
GPIOD |
0X4001 1400 |
0x1400 |
|
GPIOE |
0X4001 1800 |
0x1800 |
|
GPIOF |
0X4001 1C00 |
0X1C00 |
|
GPIOG |
0X4001 2000 |
0x2000 |
此表的偏移量:是相对APB2外设的基地址(APB2PERIPH_BASE)来说
3.7 GPIO寄存器地址及偏移量
所属总线 |
所属外设
|
寄存器
|
地址
|
偏移量 |
APB2 0X4001 0000
|
GPIOA 0X4001 0800 (外设基地址) |
GPIOA_CRL |
0X4001 0800
|
0X00 |
GPIOA _CRH |
0X4001 0804 |
0X04 |
||
IGPIOA_IDR
|
0X4001 0808 |
0X08 |
||
GPIOA_ODR
|
0X4001 080C |
0X0C |
||
GPIOA_IDR
|
0X4001 0810 |
0X10 |
||
GPIOA_BRR
|
0X4001 0814 |
0X14 |
||
GPIOA_LCKR |
0X4001 0818 |
0X18 |
寄存器是32位,32位就是4Byte,所以隔着4
3.8 GPIOA ODR寄存器地址计算过程:
1,获取外设挂在哪个总线上面?查:系统结构图
2,获取总线基地址,APB2总线基地址:0X4001 0000
3,获取外设地址偏移量,GPIOA相对APB2总线偏移量是:0X800
4,获取寄存器地址偏移量,ODR相对GPIOA外设基地址的偏移量是:0x011
寄存器地址= BUS_BASE_ADDR + PERIPH_OFFSET + REG_OFFSET
GPIOA_ODR =0X4001 0000 +0X800 + 0X0C = 0X4001 0800C
这就得到了这个寄存器地址了
3.9 使用结构体,可以很方便的完成对寄存器的映射:
结构体指针强转
&GPIOA->CRL: 0X4001 0800
&GPIOA->CRH: 0X4001 0804
&GPIOA->IDR: 0X4001 0808
&GPIOA->ODR: 0X4001 080C
依次4个字节
作者:just a little bit!