STM32 PB3/PB4引脚被JTAG占用?配置为普通IO的完整指南

发布时间:2026/9/20 3:10:24
STM32 PB3/PB4引脚被JTAG占用?配置为普通IO的完整指南 简介针对STM32开发中常见的IO口资源紧张问题这份资源专门讲解如何将JTAG接口占用的PB3、PB4释放为普通GPIO使用适合硬件工程师、嵌入式开发者及遇到引脚冲突的初学者。内容分析了默认JTAG与SWD接口的引脚占用差异指出PB3、PB4、PA15被JTAG占用并给出完整解决流程开启AFIO时钟、调用GPIO_PinRemapConfig禁止JTAG功能再按推挽输出模式初始化GPIOB并清零引脚。资源共1个PDF文件大小仅102KB属于轻量化技术笔记方便下载后随时查阅。目前已有6768人学习可见该问题在STM32开发中颇具代表性。读者通过这份资料可快速获得排错思路和可直接参考的配置代码理解AFIO重映射机制同时了解禁用JTAG对调试功能的影响从而在电路设计与软件开发中更合理地规划引脚资源。1. STM32 JTAG接口的PB3/PB4为什么默认当不了IO口用STM32做项目板子画好了PB3、PB4在原理图上明明接的是按键和LED代码里也做了GPIO初始化但焊上去之后死活不动作。万用表量电平也是不对的——这不是焊接问题也不是芯片坏了而是这两只脚上电之后根本不在GPIO模式它们被芯片内部的JTAG调试逻辑占用了。STM32F1系列的大部分型号在芯片复位之后PA13、PA14、PA15、PB3、PB4这五只引脚不是普通IO而是SWD和JTAG的调试信号脚。其中PA13是SWDIO、PA14是SWCLKPA15是JTDI、PB3是JTDO、PB4是JNTRST。也就是说只要芯片还在默认的调试模式配置下PB3和PB4就连不到你写的GPIO寄存器上。要把它俩当IO口用前提是先把对应的JTAG功能关掉再对引脚做一次完整的重配置。这个过程里如果你只关掉了JTAG而保留了SWD调试器还能正常连接如果图省事把整个调试接口全部关闭下一步下载程序就会报SWD/JTAG Communication Failure。这篇文章就沿着“为什么不能直接用、怎么关、关了之后怎么恢复、配置成IO后有什么坑”这条线展开给出一套能直接抄的完整方案。2. 配置PB3/PB4为IO口前先搞清SWJ_CFG和调试引脚映射2.1 复位后的调试引脚占用范围和你的实际需求STM32F103等F1系列在复位后调试接口默认工作在“全功能SWJ”模式也就是JTAG和SWD同时开启。这个模式下JTAG占了PA15、PB3、PB4SWD占了PA13、PA14。如果你的调试器是ST-Link或者J-Link的SWD模式实际上只用了PA13和PA14两根线JTAG那三个引脚完全是白占的。所以最常见的做法就是只关闭JTAG、保留SWD一次性放出PA15、PB3、PB4三个引脚。这里有一个容易忽略的点关闭JTAG之后PA15、PB3、PB4的引脚功能不会自动变成输入或输出引脚模式寄存器里保留的还是复位时调试功能对应的状态。所以必须在重映射配置之后再做一次GPIO_Init把这三个引脚重新初始化成你要的模式。少这一步引脚一样不工作这也是很多人在配置了AFIO重映射之后依然读不到电平的原因。2.2 AFIO_MAPR寄存器的SWJ_CFG位怎么改F1系列关闭JTAG的入口在AFIO_MAPR寄存器具体是第24、25、26位SWJ_CFG。这个三位组合一共有几种有效配置SWJ_CFG值功能释放的引脚000全功能SWJJTAGSWD无001关闭JTAG保留SWDPA15、PB3、PB4010完全关闭SWJPA13、PA14、PA15、PB3、PB4100关闭JTAG保留SWD部分型号PA15、PB3、PB4注意F1的AFIO_MAPR寄存器在操作前必须先打开AFIO时钟。标准库函数GPIO_PinRemapConfig内部会处理这件事但如果你自己直接写寄存器漏了开AFIO时钟写进去的值会被忽略引脚状态毫无变化。另外还有一个细节F1系列在修改SWJ_CFG时这些位是受保护位。标准库或HAL库的实现里会先关闭JTAG再关闭SWD而不是直接写全量值这是因为在调试会话中还连着调试器时一次性把SWJ全部关掉可能让调试器立刻失去对芯片的控制。按顺序操作能让至少SWD保持到最后一刻。3. 用标准库和HAL库把PB3/PB4配置成IO口的最小可运行代码3.1 标准库写法GPIO_PinRemapConfig与GPIO_Init配合对于仍在使用标准库的项目最常见的释放PB3/PB4并配置成IO口的代码如下void PB3_PB4_As_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 打开AFIO时钟GPIO_PinRemapConfig内部操作AFIO_MAPR寄存器时必须的 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 打开GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 关闭JTAG保留SWD。释放PB3和PB4 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 释放之后必须重新初始化引脚模式否则引脚状态不确定 GPIO_InitStructure.GPIO_Pin GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); // 初始化为低电平 GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4); }代码里最关键的两行是打开AFIO时钟和调用GPIO_PinRemapConfig。GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)这个调用的实际行为是先把SWJ_CFG从000改到001关闭JTAG部分SWD仍然留在PA13/PA14上。这样调试器仍然能连上后续代码修改和烧录不受影响。GPIO_Init的配置参数和普通IO没有区别但务必放在GPIO_PinRemapConfig之后。原因在于重映射寄存器修改的是引脚复用关系不会同步刷新GPIO控制寄存器里的模式配置先配置模式、后改重映射引脚会在一段时间内处于复用状态可能出现短暂的电平跳变如果外部设备对时序敏感可能产生误动作。3.2 HAL库写法__HAL_AFIO_REMAP_SWJ_NOJTAGHAL库的标准库对应物是几个宏定义使用时不需要额外开启AFIO时钟HAL库在初始化时会自动处理void MX_GPIO_Init_PB3_PB4(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // 关闭JTAG保留SWD __HAL_AFIO_REMAP_SWJ_NOJTAG(); // 使能GPIOB时钟 __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin GPIO_PIN_3 | GPIO_PIN_4; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3 | GPIO_PIN_4, GPIO_PIN_RESET); }如果你想完全释放SWJ所有引脚把__HAL_AFIO_REMAP_SWJ_NOJTAG()换成__HAL_AFIO_REMAP_SWJ_DISABLE()即可。但这里要郑重提醒这一行执行之后PA13和PA14的SWD功能立即消失调试器失去连接。如果你把这段代码放在main函数开头程序每次上电都执行一遍那么芯片将永久无法通过SWD口连接开关电也不会恢复只能通过ISP或串口bootloader恢复。整体配置完成后PB3和PB4在功能上就是普通GPIO可以接按键、LED、或者作为软件模拟的I2C数据线。不过要注意PB3和PB4在F1上默认不是五伏容忍引脚。如果外部设备输出5V电平需要确认对应用户手册里引脚表的FT标记没有标记就不能直接接5V逻辑否则可能损坏引脚。4. 关闭JTAG后调试器失联的三种情况与恢复手段4.1 程序里完全关闭了SWJST-Link连不上这是最常见的翻车场景。代码在启动后马上执行了__HAL_AFIO_REMAP_SWJ_DISABLE()或者GPIO_Remap_SWJ_Disable程序正常跑起来但你再点一次下载Keil报错SWD/JTAG Communication Failure。原因不复杂程序一旦运行到那条重映射指令PA13和PA14就变成了普通GPIOSWD协议栈彻底断开。此时调试器“连接-复位-连接”的握手过程全部失败。恢复手段按优先级排列按住复位键再点下载很多调试器支持在目标复位期间建立连接。操作方法是让芯片停在复位状态调试器尝试连接在连接成功的瞬间松开复位。成功率取决于下载速度和连接时序多试几次可以成功。把BOOT0拉高芯片从系统存储器启动STM32片内有一段出厂固化的bootloaderSystem Memory从这一模式启动时用户程序不运行SWJ引脚处于默认调试模式ST-Link可以正常连接。连上之后先擦除整个Flash再把BOOT0拉回低电平重新下载程序。这是最稳妥的恢复方案几乎百分百有效。加一段Flash保护代码或者空程序如果手头有另一个能用的STM32开发板可以写一个只把SWJ配置回全功能模式的程序通过串口ISP下载进目标芯片。注意这个程序会被下载到Flash开头覆盖原来的错误程序执行后芯片就恢复到初始调试模式。阻止这类问题再次出现的做法是把关闭SWJ的操作放到main函数最末尾或者某个条件判断里确保只有在跳转进application时才关闭调试阶段直接注释掉这行。4.2 只关了JTAG但程序跑起来后SWD仍然连不上有些人用了GPIO_Remap_SWJ_JTAGDisable理论上SWD还是应该活的但程序一运行调试器依然掉线。这种问题通常不是AFIO配置本身引起的而是把PA13或PA14初始化成了输出模式且输出电平恰好拉死了SWD的通信线。PA13SWDIO是双向数据线复位后内部上拉PA14SWCLK是时钟线内部下拉。如果你在GPIO初始化里把这两个引脚配置成了推挽输出并且往SWDIO线上持续输出低电平调试器的握手命令就会被这个低电平干扰表现为时连时断或者完全连不上。排查方法是不要碰PA13/PA14的GPIO配置除非你确实需要这两个引脚。真正需要全部释放时也要尽量把PA13配成输入模式而不是强输出减少对调试口的干扰。如果你的设计里PA13、PA14被强制占用无法避免那就只能走ISP下载通道把SWD调试从方案里彻底拿掉。4.3 硬件连接正常但下载时提示找不到Cortex-M设备还有一种情况PB3/PB4已经关闭JTAG并配置为IO口但电路上这两个引脚还接到了2.54mm排针或者JTAG插座上。如果插座上外接了其他调试器或者两根线上有长走线引入了干扰SWD通信一样会失败。检查方向是信号完整性而不是软件。SWDIO和SWCLK走线尽量短、不要跨分割区、不要在线上并联电容超过100pF。对高速下载模式J-Link可以适当降低通信速率Keil里把Max Clock调低或者用ST-Link的“Connect under Reset”模式。需要注意这个模式下芯片必须保持复位状态才能建立初始连接如果你的板上有大容量电容导致复位释放缓慢反而需要适当延长复位时间。5. PB3和PB4释放之后开发中值得关注的几个应用边界PB3和PB4释放成普通IO后它们在F1系列上其实还承担着其他复用功能比如TIM2_CH2PB3和TIM3_CH2PB4以及SPI1的NSSPB4。如果你的代码同时用到了这些外设需不需要额外的重映射要看具体引脚冲突的严重程度引脚释放后的主要复用与IO使用的冲突场景PB3TIM2_CH2、SPI1_SCK部分型号使用SPI1时冲突PB4TIM3_CH2、SPI1_NSS使用SPI1片选时冲突如果确需同时使用SPI1和PB3作为普通IO可以通过AFIO把SPI1重映射到PA5/PA6/PA7等其他引脚或者换用SPI2。多数情况下选择PB3/PB4作为IO口就是因为这几个引脚的复用功能在这块板上用不到所以这类冲突只会在外设模式初始化时暴露。另一个实践技巧是PB3/PB4没有自然上拉或下拉复位后如果外部悬空配置为输入模式时电平是不稳定的。建议在GPIO_InitStruct里根据外部电路明确设置Pull为上拉或下拉。拿来做按键输入时若外部接了上拉电阻就配置GPIO_NOPULL否则直接开启内部上拉省掉一颗电阻做输出驱动MOS管或LED时注意引脚最大输出电流不要直接驱动大电流负载。还有一点和调试器恢复策略相关。如果产品已经量产你出于代码保护目的完全关闭了SWJ这会让后续固件升级只能走串口或CAN bootloader。建议在设计阶段就预留一个串口下载入口把USART1的bootloader烧进去后即使应用代码占用了全部调试引脚也能通过BOOT0跳转完成固件升级。这个能力在排查现场故障时远比省掉一根调试线重要。最后验证一下PB3/PB4是否真正被释放成了IO。简单做法是写一个循环翻转这两个引脚用示波器看波形没有示波器就接两个LED程序里做1秒翻转。如果你在GPIO_PinRemapConfig之后发现引脚毫无反应优先检查AFIO时钟是否开启、GPIO_Init是否在重映射之后执行、PB3/PB4是否在别的初始化里被复用功能占用了。排查顺序从这三个点入手比盲目重刷程序效率高得多。本文还有配套的精品资源点击获取