前言:
前段时间在做一个项目的时候遇到一个问题,使用GPIO引脚的PB3和PB4的时候,发现不能正常使用,后来无论怎么改怎么配置都用不了,后来才想起来GPIO引脚还有一个叫重映射的概念,今天就顺便跟大家分享一下自己的看法。
先剧透一下,像这样不能直接当作普通GPIO的引脚还有:
JTAG引脚:
PB3 (JTDO) //数据输出
PB4 (NJTRST) //复位
PA15 (JTDI) //数据输入
PA13 (JTMS) //数据输入/输出
PA14 (JTCK) //JTAG时钟
SWD引脚:
PA13 (SWDIO) //数据输入/输出
PA14 (SWCLK) //SWD时钟
什么是GPIO引脚的重映射?
GPIO引脚重映射是指STM32微控制器将某些外设(如USART、SPI等)的默认引脚重新分配到其他可用引脚的过程。通过重映射,可以灵活地调整外设引脚的连接方式,以满足不同的硬件设计需求,提高引脚资源的利用率。
简单来说,GPIO引脚重映射就是把STM32芯片上原本连接某个功能的引脚,换到别的引脚上。
如图:
1.GPIO重定义
从图中不难看出,PB3和PB4的主功能已经变成JTDO和NJTRST,而不是PB3跟PB4,那他们的主功能是什么意思呢?
PB3 (JTDO):用于JTAG调试输出
PB4 (NJTRST):是JTAG的复位信号,用于复位JTAG接口
看得出来,应该是跟JTAG调试相关的,所以说,如果正常配置这些引脚的话肯定是行不通的。
使用在使用这些引脚的时候,我们需要加入如下语句:
1.这一步是必须的,因为AFIO模块是负责引脚的重映射功能。
//开启AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
2.这一步确保PB3从JTAG功能中释放出来,可以作为普通GPIO使用。
//禁用JTAG功能
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
下面是初始化PB3的示例代码:
// 初始化PB3为GPIO输出模式
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO初始化结构体变量
// 1. 开启GPIOB时钟
// 使能GPIOB和AFIO(备用功能I/O)的时钟,
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
// 2. 配置PB3为普通GPIO模式(禁用JTAG功能)
// 禁用JTAG功能,将PB3从JTAG功能中释放出来,用于普通GPIO功能
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
// 3. 初始化PB3为推挽输出模式,无上拉/下拉,输出低电平
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 指定要初始化的引脚为PB3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置为推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置GPIO速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 根据上述配置初始化GPIOB的PB3引脚
}
这样我们的特殊引脚就可以配置成普通GPIO了。
2.GPIO重映射
严谨一点来说,应该叫作复用功能重映射,GPIO重映射又分为部分重映射和完全重映射两大类,下面就来简单分析一下这两大类:
部分重映射
“部分重映射”(Partial Remapping)是STM32系列单片机中一个与引脚功能配置相关的概念。它指的是将某些引脚的功能重新映射到其他引脚上,但仅对部分引脚进行映射,而不是对该外设的所有引脚进行完全的重新分配。这种功能通常用于解决引脚资源冲突或优化引脚布局。
说人话,部分重映射就是把单片机某个外设的某些引脚的功能“搬家”到其他引脚上,但只搬一部分功能引脚,而不是全部功能都换地方。比如:USART1的默认引脚映射为PA9(TXD)PA10(RXD)
然后PA9(TXD)可以重映射到PB6引脚上,而PA10(RXD)保持不变,也可以PA9(TXD)保持不变,PA10重映射到PB7引脚上。到这里相信你也会有一个疑问,能不能随便重映射到某一个引脚上呢?我个人认为是不能的,因为在STM32F10XX参考手册里面已经给我们列出来了它们的对应的重映射引脚。如图:
没有参考手册的朋友可以通过下面的链接访问官网获取:
(这个是STM32F10XX中等容量系列的参考手册链接,适用于STM32C8T6芯片)
http://www.st.com/stonline/products/literature/ds/13587.pdf
下面是USART1的示例参考代码,本代码是将USART1的TXD引脚从PA9重映射到PB6上,同时保留PA10(RXD)引脚。
void USART1_Config(void) {
// 1. 启用AFIO和GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
// 2. 配置USART1部分重映射(将TX从PA9映射到PB6)
GPIO_PinRemapConfig(GPIO_PartialRemap_USART1, ENABLE);
// 3. 配置PB6为USART1的TX引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 4. 配置USART1
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200; // 115200波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 接收和发送模式
USART_Init(USART1, &USART_InitStructure);
// 5. 使能USART1
USART_Cmd(USART1, ENABLE);
}
这样我们的重映射引脚就配置好啦。
完全重映射
“完全重映射”(Full Remapping)是指将某个功能的所有相关引脚的功能全部重新映射到另一组引脚上。这意味着原来用于该功能的所有引脚都会被释放,而新的引脚会完全接管这个功能。
与部分重映射不同的是:完全重映射是将某个外设的全部引脚重映射到指定的引脚上,原来的引脚被完全释放。下面是USART1完全重映射的示例代码:
void USART1_Config(void)
{
// 1. 使能GPIOB和USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE);
// 2. 配置PB6和PB7为USART功能
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 3. 启用完全重映射
GPIO_PinRemapConfig(GPIO_FullRemap_USART1, ENABLE);
// 4. 配置USART1
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200; // 115200波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 发送和接收模式
USART_Init(USART1, &USART_InitStructure);
// 5. 使能USART1
USART_Cmd(USART1, ENABLE);
}
第一个不同之处:
部分重映射只配置外设需要重映射的某个引脚,而完全重映射是配置外设的重映射的全部引脚。
第二个不同之处:
GPIO_PinRemapConfig重映射函数里面的参数不同,GPIO_PartialRemap_USART1为部分重映射USART1的部分引脚,GPIO_FullRemap_USART1为完全重映射USART1的全部引脚。
总结
完全重映射:所有相关引脚的功能都被重新分配,原来的引脚完全释放。
部分重映射:只改变部分引脚的功能,原来的引脚部分释放,部分保留原功能。
通过这种方式,STM32单片机的引脚功能可以更加灵活地配置,以满足不同的硬件设计需求。
(注:本文只是个人看法,如有不足,欢迎指出)