stm32端口复用和重映射
端口复用和重映射都是和单片机的I/O口有关系,端口复用是将一个I/O赋予多个功能,通过设置I/O的工作模式来切换不同的功能。重映射是将某些I/O口上面的功能映射到其他I/O口上面去。但是注意一点:重映射的I/O都是厂家设置好的,不能自己更改。
端口复用
外设
在说端口复用之前先明白一个概念:什么是外设?什么是内置外设?
外部设备简称“外设”,是指连在计算机主机以外的硬件设备。对数据和信息起着传输、转送和存储的作用,是计算机系统中的重要组成部分。
—百度百科
内置外设就是集成在单片机内部的外设,存在对应的寄存器。可参考:单片机里内部外设和外设分别是什么
端口复用
STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。
例如串口1的发送接收引脚是PA9,PA10,当我们把PA9,PA10不用作GPIO,而用做复用功能串口1的发送接收引脚的时候,叫端口复用。
端口复用设置步骤
- GPIO时钟使能;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); - 复用外设时钟使能
比如你要将端口PA9,PA10复用为串口,所以要使能串口时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); - 端口模式配置。 GPIO_Init()函数。
具体说下第3步 端口模式配置,在使用I/O时,首先要进行初始化,
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
第一个参数是哪组I/O口,第二组I/O是一个结构体指针
typedef struct
{
uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIOSpeed_TypeDef */
GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
主要看一下 GPIO_Mode 这个参数的取值
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;
在数据手册中可以看到 PA9和PA10可以复用为串口(Default),
从上两张图中可以看出,复用为串口发送需要将 PA9设置为 推挽复用输出,
代码示例:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//GPIO时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//外设时钟(串口)使能
//初始化IO为对应的模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10 PA.10 浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
总结
GPIO复用功能就是同样的几个I/O口可以通过设置I/O模式,使能相应时钟, 从而实现不同的功能。具体的设置可以参考 stm32中文参考手册和相应芯片的 dataSheet。
重映射
每个内置外设都有若干个输入输出引脚,一般这些引脚的输出端口都是固定不变的,为了让设计工程师可以更好地安排引脚的走向和功能,在STM32中引入了外设引脚重映射的概念,即一个外设的引脚除了具有默认的端口外,还可以通过设置重映射寄存器的方式,把这个外设的引脚映射到其它的端口。
重映射技术的需求背景:
- I/O的复用:GPIO和内置外设共用引出管脚
- I/O的重映射:复用功能(AFIO)从不同的GPIO管脚引出
- 方便了PCB的设计,减少了信号交叉干扰
- 分时复用某些外设,虚拟地增加了端口数目
- 为了使不同器件封装的外设IO功能数量达到最优,可以把一些复用功能重新映射到其他一些引脚上。STM32中有很多内置外设的输入输出引脚都具有重映射(remap)的功能。
还是以串口1为例
上图中的,Remap对应的I/O就是可以重映射到的I/O,Default就是该I/O默认可复用的功能。
从上图中可以看出 串口1 可以重映射到 PB6和PB7引脚,也就是说如果PA9和PA10引脚不好用的时候,或者已经被占用了;那么可以用PB6和PB7来实现串口1的功能。
AFIO重映射的操作步骤:
- 使能倍重新映射到的I/O端口时钟
- 使能被重新映射的外设时钟
- 使能AFIO功能的时钟(勿忘)
- 进行重映射
注意第三步,使能AFIO功能时钟,为什么需要使能这个时钟 & 什么时候需要使能这个时钟, 可以参见下面这个回答
那么,问题来了!
AFIO 是什么?AFIO 时钟什么时候需要开启?
我们从《STM32中文参考手册_V10》中找到:对寄存器 AFIO_EVCR、AFIO_MAPR 和 AFIO_EXTICRX 进行读写操作前,应当首先打开 AFIO 的时钟(设置 APB2 外设时钟使能寄存器 RCC_APB2ENR)。
也就是说:当你需要配置 AFIO 这些寄存器的时候,就需要把 RCC_APB2ENR 寄存器的 AFIO 位置‘1’打开 AFIO 时钟。
跟 AFIO 相关的寄存器有:
1、 事件控制寄存器(AFIO_EVCR)
2、 复用重映射和调试I/O 配置寄存器(AFIO_MAPR)
3、 外部中断配置寄存器1(AFIO_EXTICR1)
4、 外部中断配置寄存器2(AFIO_EXTICR2)
5、 外部中断配置寄存器3(AFIO_EXTICR3)
6、 外部中断配置寄存器4(AFIO_EXTICR4)
看看这些寄存器的定义,我们就明白,这些寄存器是用于“事件控制”、“重映射”、“调试IO配置”、“外部中断”的。例如 AFIO_EXTICRX 用于选择 EXTIx 外部中断的输入源。
总结:当我们需要配置这些 AFIO 寄存器的时候,就需要打开 RCC_APB2ENR 寄存器的 AFIO 时钟,而不是用到引脚复用功能的时候打开。
——-来自于: STM32的AFIO时钟什么时候需要开启
部分重映射 & 完全重映射
- 部分重映射:功能外设的部分引脚重新映射,还有一部分引脚是原来的默认引脚。
- 完全重映射:功能外设的所有引脚都重新映射。
如何配置部分重映射 & 完全重映射在后面
引脚重映射配置过程(串口3为例):
1. 使能GPIO时钟(重映射后的IO);
2. 使能功能外设时钟(例如串口3);
3. 使能AFIO时钟。重映射必须使能AFIO时钟:
4. 开启重映射。
GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE);
//根据第一个参数,来确定是部分重映射还是全部重映射
查看第一个参数的取值,如下图:
以串口3为例,如果想部分映射:GPIO_PinRemapConfig()的第一个参数取值应该是:上图红框框里面的第一个参数,即 GPIO_PartialRemap_USART3,如果是完全映射就是:GPIO_FullRemap_USART3
总结
重映射就是将在某个I/O实现的功能映射到另外的I/O口, 主要是为了布线的方便以及信号的干扰。具体配置步骤与部分重映射 & 完全重映射前面都已说明。
参考资料
正点原子视频
STM32中GPIO的8种工作模式
STM32的AFIO时钟什么时候需要开启
单片机里内部外设和外设分别是什么