文章目录
一、GPIO/AFIO介绍
GPIO:通用输入输出引脚;
AFIO:备用输入输出引脚;
1、GPIO功能描述
每个输入/输出端口有2个32位的配置寄存器(GPIOx_CRL,GPIOx_CRH),2个32位的数据寄存器(GPIOx_IDR,GPIOx_ODR),1个32位的置位/复位寄存器(GPIOx_BSRR),1个16位的复位寄存器(GPIOx_BRR),1个32位的锁存寄存器(GPIOx_LCKR)。
每个输入/输出端口的特有的硬件特点在数据手册中已经列出来了,通用输入/输出的每个端口位可以由软件单独的配置成以下几种模式:
- 输入浮动:此引脚只受外部输入影响;
- 输入上拉:内部有上拉电阻;
- 输入下拉:内部有下拉电阻;
- 模拟输入:将模拟信号直接输入,一般接入AD转换;
- 输出开漏:需要外部接上拉电阻;
- 输出推挽
- 备用推挽
- 备用开漏
每个I/O端口位可以自由的编程,尽管I/O端口寄存器必须以32位字的方式访问(不允许以半字或者字节的方式访问)。GPIOx_BSRR和GPIOx_BRR寄存器的目的就是用来允许GPIO寄存器进行原子的读/写改操作。在这种方式下,当TRQ(中断请求)发生在读和修改之间时,不会存在任何风险。
2、GPIO方框图
3、输入/输出配置模式
4、I/O相关寄存器
- 端口配置寄存器低位:GPIOx_CRL
- 端口配置寄存器低位:GPIOx_CRH
- 端口输入数据寄存器:GPIOx_IDR
- 端口置位/复位寄存器:GPIOx_BSRR
- 端口复位寄存器:GPIOx_BRR
- 端口配置锁存寄存器:GPIOx_LCKR
5、备用功能输入/输出和调试配置
为了优化64引脚或者100引脚封装的可用外设数量,可以将一些备用功能映射到一些其他的引脚,这是通过软件编程AF重映射和调试输入/输出配置寄存器(AFIO_MAPR)实现的。在这种情况下,备用功能不再映射到原始的分配:
- 使用OSC32_IN/OSC32_OUT引脚作为GPIO端口PD0、PD1;
- BXCAN备用功能重映射;
- JTAG/SWD备用功能重映射;
- 定时器备用功能重映射;
- USART备用功能重映射;
- I2C1备用功能重映射;
- SPI1备用功能重映射。
6、AFIO相关寄存器
- 事件控制寄存器:AFIO_EVCR;
- AF重映射和调试I/O配置寄存器:AFIO_MAPR;
- 外部中断配置寄存器1:AFIO_EXTICR1;
- 外部中断配置寄存器2:AFIO_EXTICR2;
- 外部中断配置寄存器3:AFIO_EXTICR3;
- 外部中断配置寄存器4:AFIO_EXTICR4;
- AF重映射和调试I/O配置寄存器2:AFIO_MAPR2。
二、原理图及MDK工程建立
1、原理图接法
- LED端口J19,依次接单片机PB8~PB15;
- GOPI接到LED的负极,故GPIO给低电平,LED亮,反之亦然。
2、工程建立
- 第一步:Project->New Project
- 第二步:设置工程名字保存
- 第三步:在设备选型列表找到你要的设备
注意:这一步当然要先安装好官方提供的pack支持包,不然你的Keil里是找不到你要用的那个芯片型号的。
4. 第四步:根据需要选择外设库文件,也可以全选,只不过编译速度会慢一下,用到哪些外设就选择哪些会比较快一下
-
第五步:工程建立如下,并在Source Group 1文件夹添加C文件。
-
第六步:在新添加的C文件里写main函数
-
第七步:编译,会报错”FCARM - Output Name not specified, please check ‘Options for Target - Utilities’“
原因:用户的.c和.h文件往往都是新建txt,然后改的后缀,这样的文件被导入keil后,有可能会被识别成image file。
-
第八步:选中C文件,右键,选择Option for File ‘gpio.c’…
-
第九步:将image file改成C Source file
-
第十步:确认后重新编译,问题解决
-
注意:将编译器版本改成V5版本,最新版本可能会编译报错
三、代码的编写
1、寄存器确认
- GPIO PortB的基地址:0x4001 0C00;
- 有可能涉及到的寄存器:
寄存器 | 偏移量 | 地址 |
---|---|---|
GPIOB_CRL | 0x00 | 0x40010C00 |
GPIOB_CRH | 0x04 | 0x40010C00 |
GPIOB_IDR | 0x08 | 0x40010C08 |
GPIOB_ODR | 0x0C | 0x40010C0C |
GPIOB_BSRR | 0x10 | 0x40010C10 |
GPIOB_BRR | 0x14 | 0x40010C14 |
2、寄存器的操作
- ARM是内存与IO统一编址的,所以ARM中的所有外设都是通过操作寄存器的方式来操作的;
- 每个寄存器都对应有内存地址,C语言通过这些内存地址来操作这些寄存器,所以用到的C语言知识就是指针;
- 例如:向地址0x40010C00里写一个数32
*(unsigned int *)0x40010C00 = 32;
/*或者*/
unsigned int *p = (unsigned int *)0x40010C00; //将0x40010C00地址强制转换成一个指针
*p = 32; //指针的解引用
3、代码
#define GPIOB_CRH 0x40010C04
#define GPIOB_ODR 0x40010C0C
#define RCC_APB2ENR 0x40021018
int main()
{
*((unsigned int *)RCC_APB2ENR) = 0x00000008; //PortB的RCC使能
//PB8~PB15配置成输出模式
*((unsigned int *)GPIOB_CRH) = 0x33333333; //推挽输出模式,输出速率50MHz
*((unsigned int *)GPIOB_ODR) = 0x00000F00; //输出0,点亮LED
while(1);
return 0;
}
8颗LED全部点亮。