资讯动态

STM32端口复用与重映射详解:AF寄存器配置与F1/F4差异

发布时间:2026/10/13 1:22:38 来源:尧图企业网站定制
1. 从一次调试翻车说起为什么端口复用和重映射值得单独拎出来讲刚接触STM32那会儿我遇到过一个至今印象深刻的坑。当时在做一个多传感器采集的小板子原理图上明明把超声波模块的Trig引脚连到了PA9代码里也老老实实写了GPIO_SetBits(GPIOA, GPIO_Pin_9)结果示波器一挂上去引脚纹丝不动倒是串口那边莫名其妙开始往外吐乱码。折腾了大半天翻数据手册才发现——PA9默认是USART1_TX的复用功能我既没把它配成普通推挽输出也没关掉串口外设的时钟两个外设抢一个引脚最后谁也没干好活。这件事让我意识到端口复用Alternate Function和重映射Remap这两个概念看着像是GPIO章节里不起眼的一小节实际上是STM32开发中绕不开的基本功。你只要用到串口、SPI、I2C、定时器PWM、CAN这些外设就一定会和它打交道。很多初学者卡在“代码没错但引脚没反应”“外设初始化了但收不到数据”这类问题上十有八九就是复用和重映射没搞明白。这篇内容我打算把STM32的端口复用和重映射从头到尾捋一遍。会讲清楚它到底是什么、为什么STM32要这么设计、AF寄存器怎么配、重映射在F1和F4系列上有什么本质区别、实操中怎么一步步把引脚切到想要的外设上以及我自己踩过的那些坑。不管你是刚点亮LED的新手还是已经能跑通串口但说不清底层原理的进阶玩家应该都能从里面找到有用的东西。核心关键词就三个端口复用、重映射、AF寄存器配置围绕它们展开。2. 端口复用和重映射到底在解决什么问题2.1 一个引脚凭什么能干好几件事STM32的引脚数量是有限的。以常见的LQFP64封装为例去掉电源、地、复位、BOOT这些真正能拿来用的IO大概就50个出头。但芯片内部集成的外设有多少呢随便数数3个USART、2个SPI、2个I2C、1个CAN、多个定时器、ADC、DAC、SDIO、FSMC……每个外设都需要引脚。如果每个外设都独占一组引脚那芯片得做成几百个脚才够用。所以STM32的设计思路是一个物理引脚通过内部的多路选择器可以连接到不同的外设信号线上。同一时刻只能选一个但你可以根据需要切换。这就是端口复用的本质——引脚是硬件资源复用是让这个资源在不同外设之间共享的机制。打个比方一个引脚就像一间办公室GPIO是“房东自己用”复用功能是“租给USART当TX”“租给TIM当PWM输出”“租给SPI当SCK”。同一时间只能有一个租客但你可以换租客。默认状态下大部分引脚归GPIO管你要用外设功能就得办个“交接手续”这个手续就是配置AF寄存器。2.2 复用和重映射不是一回事很多人把这两个概念混着说其实它们解决的是不同层面的问题。端口复用解决的是“这个引脚能不能当外设引脚用”的问题。比如PA9它可以是GPIO也可以是USART1_TX还可以是TIM1_CH2。你通过配置AF寄存器F1系列叫AFIOF4系列叫GPIOx_AFRL/AFRH告诉芯片“我现在要PA9走USART1_TX的信号”。重映射解决的是“这个外设的信号能不能换个引脚出来”的问题。还是PA9和USART1_TX在F1系列里USART1的TX默认就在PA9但如果你PA9被占了可以通过重映射把USART1_TX挪到PB6上去。重映射改变的是外设信号和物理引脚之间的对应关系。一句话总结复用是“引脚选功能”重映射是“功能换引脚”。F1系列有独立的重映射机制F4及以后的系列基本用AF矩阵统一管理重映射的概念被弱化了但底层逻辑是一样的。2.3 为什么F1和F4的配置方式差这么多这是我在实际项目里感受最深的一点。F1系列比如STM32F103用的是AFIO外设重映射寄存器的方案。你要用复用功能得先开AFIO时钟然后配置GPIO的模式比如复用推挽输出再通过AFIO_MAPR寄存器决定要不要重映射。这套机制比较“手工”寄存器分散容易漏配。F4系列比如STM32F407换成了AF矩阵方案。每个GPIO引脚有AFRL和AFRH两个寄存器每个引脚占4个bit直接写AF编号0~15就能选中对应的外设功能。比如PA9要当USART1_TX就写GPIO_AF7_USART1。不需要单独开AFIO时钟也不需要重映射寄存器所有复用关系都在数据手册的“Alternate function mapping”表里查。这个差异直接导致了两套代码写法完全不同。你在网上搜到的F1教程放到F4上跑不通很多时候就是卡在这里。下面我会分别讲两套配置流程你对照自己的芯片系列看。3. 核心细节拆解AF寄存器、复用模式和数据手册怎么查3.1 数据手册里的复用表才是唯一权威我见过太多人凭记忆或者凭别人的代码配引脚结果引脚功能不对。配复用功能之前第一件事永远是翻数据手册的Alternate function mapping表。这张表会告诉你每个引脚支持哪些复用功能以及对应的AF编号是多少。以STM32F407的PA9为例数据手册里会列出引脚AF0AF1AF2AF3AF4AF5AF6AF7...PA9SYSTIM1_CH2TIM15_BKIN-I2C3_SMBASPI2_SCK-USART1_TX...你要用USART1_TX就选AF7。要当TIM1_CH2用就选AF1。这个编号是硬件固定的写错了引脚就没信号。F1系列没有AF编号的概念而是通过“默认复用”和“重映射”两种状态来区分查表方式不同但同样以数据手册为准。提示数据手册Datasheet和参考手册Reference Manual要分清。引脚复用表在数据手册里寄存器详细说明在参考手册里。两个都要备着。3.2 GPIO模式必须和复用功能匹配配好了AF编号GPIO的工作模式也得设对。这里有个容易忽略的点复用功能下GPIO的输出模式要设成复用推挽或复用开漏而不是普通的推挽/开漏。为什么因为普通输出模式下GPIO的输出寄存器直接控制引脚电平复用模式下引脚的控制权交给了外设GPIO的输出寄存器不再起作用。如果你把USART1_TX的引脚设成普通推挽输出那串口外设根本控制不了这个引脚发出去的数据自然出不来。输入方向也一样。比如USART1_RX要设成复用输入模式F1里叫浮空输入或上拉输入F4里叫复用模式输入。具体设成上拉还是浮空要看外设要求和外部电路。串口RX一般设上拉或浮空都行I2C的SDA/SCL则必须设成复用开漏因为I2C总线需要线与逻辑。3.3 时钟使能顺序不能乱这是另一个高频翻车点。STM32的外设时钟和GPIO时钟是分开的用哪个外设就得开哪个外设的时钟同时开对应GPIO端口的时钟。以F4系列用USART1为例需要开的时钟有RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE)—— GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)—— USART1时钟F1系列还要多一个RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE)—— AFIO时钟只有F1需要顺序上我习惯先开GPIO时钟再开外设时钟最后配引脚。虽然大多数情况下顺序不影响结果但先开时钟再操作寄存器是更稳妥的习惯避免在时钟没开的时候写寄存器无效。4. 实操过程F1和F4两套配置流程完整走一遍4.1 F1系列端口复用配置步骤以STM32F103把PA9配成USART1_TX为例完整流程如下。第一步开时钟。GPIOA、USART1、AFIO三个时钟都要开RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);第二步配置GPIO模式。TX是输出设成复用推挽速度按需选GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure);第三步如果要重映射配置AFIO_MAPR。比如把USART1重映射到PB6/PB7GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);注意重映射之后引脚就变成PB6和PB7了对应的GPIO初始化也要改成GPIOB的Pin6和Pin7。这一步很多人会忘结果代码里还在配PA9自然没反应。第四步配置USART1本身波特率、字长、停止位等然后使能。F1的重映射有个细节部分重映射和完全重映射是分开的。比如USART1只有完全重映射TX→PB6RX→PB7而USART3有部分重映射TX→PC10RX→PC11和完全重映射TX→PD8RX→PD9两种。用哪个查参考手册的AFIO_MAPR寄存器说明。4.2 F4系列端口复用配置步骤同样以USART1_TX为例F407的PA9配置流程。第一步开时钟。只需要GPIOA和USART1不需要AFIORCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);第二步配置GPIO模式为复用模式GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure);第三步关键一步设置AF编号GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);这个GPIO_AF_USART1在标准库头文件里定义好了值就是7。你也可以直接写7但用宏更清晰。第四步配置USART1并使能。F4没有独立的重映射寄存器因为AF矩阵已经涵盖了所有可能的引脚映射。同一个外设信号可能出现在多个引脚上比如USART1_TX可以在PA9、PB6、PB7等你选哪个引脚就配哪个引脚的AF编号本质上就是“重映射”的灵活版。4.3 用寄存器直接操作的方式如果你用寄存器开发或者想搞清楚底层F4的AF配置就是操作AFRL和AFRH。PA9属于高8位用AFRHGPIOA-AFR[1] ~(0xF ((9 - 8) * 4)); // 清掉PA9的AF位 GPIOA-AFR[1] | (7 ((9 - 8) * 4)); // 设为AF7每个引脚占4个bitAFRH管Pin8~Pin15AFRL管Pin0~Pin7。这个计算方式要记清楚写错了就会配到别的引脚上去。F1的寄存器方式则是操作GPIOx_CRL/CRH设置模式再操作AFIO_MAPR设置重映射。CNF位和MODE位的组合决定复用模式具体位定义查参考手册。5. 常见问题与排查技巧实录5.1 引脚没输出怎么一步步定位这是最高频的问题。我总结了一套排查顺序基本能覆盖90%的情况。排查项检查内容常见错误时钟GPIO和外设时钟是否都开只开了GPIO忘了外设时钟模式GPIO模式是否为复用模式设成了普通推挽/开漏AF编号AF值是否和数据手册一致记错编号或写错引脚重映射F1是否配了AFIO_MAPR配了重映射但引脚没改引脚冲突是否有其他外设占用同引脚两个外设抢一个脚硬件引脚是否被外部电路拉死上拉/下拉电阻冲突我遇到过一次F1的USART1重映射到PB6/PB7之后串口还是没数据。查了半天发现PB6同时接了I2C1的SCL虽然I2C没初始化但硬件上有个上拉电阻加上重映射后两个外设的信号在引脚上打架。后来把I2C的引脚换掉才解决。所以引脚冲突不一定是软件问题硬件上共用引脚也要注意。5.2 复用开漏和复用推挽怎么选这个问题我被问过很多次。简单说复用推挽用于大多数输出场景比如USART_TX、SPI_SCK、PWM输出。推挽能主动输出高和低驱动能力强。复用开漏用于需要线与逻辑的总线比如I2C的SDA和SCL。开漏只能主动拉低高电平靠外部上拉电阻。多个设备挂同一条总线时任何一个拉低总线就是低不会出现推挽那种“一个输出高一个输出低导致短路”的问题。选错了会怎样I2C用推挽多个设备同时通信时可能烧引脚USART_TX用开漏没有外部上拉的话高电平出不来数据全是乱的。5.3 重映射之后原来的引脚还能用吗能但要看情况。F1的重映射是“把外设信号从默认引脚挪到重映射引脚”默认引脚在重映射使能后就释放了可以当普通GPIO用。但要注意如果默认引脚上还接着其他外设或者外部电路有特殊连接释放后可能影响其他功能。F4没有这个问题因为AF矩阵是每个引脚独立配置的。你把PA9配成USART1_TXPB6不配AF就是普通GPIO互不影响。5.4 调试时的一个实用技巧如果你不确定引脚到底有没有配成功可以在初始化之后加一段测试代码把引脚临时切成普通推挽输出翻转几次用示波器或LED看有没有反应。如果有反应说明GPIO本身没问题问题在复用配置或外设上如果没反应说明GPIO模式或时钟有问题。这个二分法能快速缩小排查范围。另一个技巧是查寄存器。在调试器里直接看GPIOx_AFRL/AFRH、GPIOx_MODER、RCC的时钟使能寄存器比看代码更直接。代码可能因为宏定义或者库函数版本问题和你以为的不一样寄存器不会骗人。6. 几个容易忽略的进阶细节6.1 复用功能下的上下拉配置F4的GPIO_PuPd可以设上拉、下拉或浮空。复用输出模式下上下拉一般不影响输出但复用输入模式下就很重要。比如USART_RX如果外部没有上拉建议设内部上拉避免引脚悬空时收到乱码。I2C的SDA/SCL则必须外部上拉内部上拉太弱带不动总线。F1没有独立的上下拉配置输入模式下通过CNF位选浮空、上拉或下拉。复用输入一般选浮空或上拉具体看外设要求。6.2 重映射和中断的关联F1的AFIO还管外部中断的引脚映射。比如EXTI9_5中断默认对应PA5~PA9但通过AFIO_EXTICR寄存器可以把它映射到PB5~PB9或PC5~PC9。这个和端口复用是两套机制但都在AFIO里配置。如果你用了外部中断又改了引脚记得检查EXTICR。6.3 低功耗模式下的引脚状态进入低功耗模式前复用引脚的状置会影响功耗。比如一个配成复用推挽输出的引脚如果外设已经关闭但引脚还保持输出状态可能会有漏电流。稳妥的做法是进入低功耗前把不用的复用引脚重新配成模拟输入或浮空输入降低功耗。这个在电池供电的项目里尤其重要。7. 我个人的实操体会端口复用和重映射这块我最大的体会是别背代码背流程。具体寄存器值、AF编号这些数据手册里都有查一下就行。但配置的流程和逻辑顺序必须刻在脑子里开时钟→配模式→设AF/重映射→配外设→使能。这个顺序乱了或者漏了哪一步就会出现各种“代码看着没错但就是不工作”的问题。另外F1和F4的差异一定要分清。我见过有人拿着F103的代码往F407上移植AFIO那套东西在F4上根本不存在编译都过不了。反过来F4的AF配置方式放到F1上也不行。所以拿到一个新芯片先确认系列再找对应的配置方法。最后分享一个小习惯每次配完复用引脚我都会在代码注释里写清楚“这个引脚配成了什么功能、AF编号是多少、对应数据手册哪一页”。过几个月回头看代码或者别人接手你的项目能省很多时间。这个习惯看起来不起眼但实际项目里真的能救命。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑