单片机 - STM32F103“复用功能重映射”完整解析:从JTAG释放到TIM重映射实战详解
本文将详细讲解 STM32F103 系列中常见的“复用功能重映射”(Remap)机制,包括 JTAG 占用、引脚默认功能与复用功能的关系,以及如何通过寄存器或标准库代码实现重映射。以 TIM3 在 PB4/PB5 上输出 PWM 为例,进行实战讲解,适合初学者与进阶开发者参考
一、什么是“复用功能重映射”(Remap)
?
STM32 系列的引脚大多数都具有多种功能,比如既可以做普通 GPIO,也可以作为串口、定时器通道、SPI 等外设使用。
以 STM32F103
为例,有些引脚在芯片上电复位后默认配置为某些外设功能(主功能),而有些引脚默认不是该功能,但可以通过“功能重映射
”将该功能映射过去。
功能重映射机制允许我们在引脚资源有限或外设冲突时,将某些外设的引脚重新映射到其他引脚组,从而获得更大的灵活性。
二、判断是否需要重映射的逻辑
在使用某个外设功能时,我们需要判断是否可以直接使用,还是必须进行重映射。以下是准确的判断逻辑:
1. 如果“主功能名 == 引脚名”
例如:
PA9
是USART1\_TX
(默认功能)PA10
是USART1\_RX
(默认功能)
这类引脚默认即可作为对应外设使用,无需任何重映射设置。
2. 如果“主功能名 ≠ 引脚名”,但手册中支持通过重映射映射到该引脚
例如:
PB4
默认是JNTRST
,但支持通过重映射成为TIM3\_CH1
则必须开启相应的重映射配置,才可以使用该外设功能。
3. 如果手册中未提及该引脚支持该外设
说明该引脚不支持该功能,即便使用重映射也无法达到目的。
三、JTAG默认占用问题与引脚释放
STM32F103
系列默认启用了全功能 JTAG
调试接口,它会占用多个引脚:
引脚 | JTAG功能 |
---|---|
PA13 | JTMS |
PA14 | JTCK |
PA15 | JTDI |
PB3 | JTDO |
PB4 | JNTRST |
如果需要将 PB4
用作其他功能(如 TIM3\_CH1
),必须首先禁用 JTAG 功能,否则该引脚将无法正常输出或输入信号。
禁用 JTAG(保留 SWD)
标准库写法如下:
// 开启 AFIO 外设时钟,这是使用重映射的前提
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 禁用 JTAG,仅保留 SWD(两线调试),释放 PB3、PB4、PA15
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
这行代码会释放 PB3、PB4、PA15
,使其恢复为普通可配置引脚。
四、重映射类型介绍(无重映射 / 部分重映射 / 完全重映射)
STM32F103
系列在设计时为部分外设功能预设了多种映射方式,主要分为以下三类:
1. 无重映射(No Remap)
使用默认引脚。例如 TIM3\_CH1
默认映射到 PA6,TIM3\_CH2
映射到 PA7。
2. 部分重映射(Partial Remap)
将部分通道映射到其他引脚,例如将 TIM3\_CH1
映射到 PB4
,TIM3\_CH2
映射到 PB5
。
标准库代码:
// 将 TIM3 的 CH1 和 CH2 通道映射到 PB4 和 PB5(部分重映射)
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
3. 完全重映射(Full Remap)
将所有通道映射到全新的引脚组,例如 TIM3 的所有通道映射到 PC6\~PC9
。
标准库代码:
// 将 TIM3 所有通道映射到 PC6-PC9(完全重映射)
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
所有重映射配置都可在参考手册(RM0008)第九章 AFIO 章节中查到。
五、实战案例:TIM3
在PB4/PB5
输出PWM控制电机
背景:
在使用 L9110S
电机驱动模块时,需要控制两个引脚(如 PB4 和 PB5
)输出 PWM
信号,实现电机的正反转与调速。但 PB4 默认是 JTAG
口的一部分,TIM3 默认也未映射到 PB4/PB5
。
步骤如下:
1. 释放 PB4 的 JTAG 占用:
// 使能 AFIO 外设的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 禁用 JTAG,仅保留 SWD,释放 PB4 用作普通引脚
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
2. 打开 TIM3 并进行部分重映射:
// 将 TIM3_CH1 和 TIM3_CH2 分别重映射到 PB4 和 PB5
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
3. 配置 GPIO 为复用推挽输出:
GPIO_InitTypeDef GPIO_InitStructure;// 设置为复用推挽输出模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// 设置 IO 输出速度为最大 50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// 选择引脚 PB4 和 PB5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
// 初始化 GPIOB 引脚
GPIO_Init(GPIOB, &GPIO_InitStructure);
4. 配置 TIM3 输出 PWM 到 PB4/PB5:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;// 打开 TIM3 的时钟(APB1总线)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);// 设置 PWM 的频率:PWM_freq = 72MHz / (Prescaler+1) / (Period+1)
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值 ARR:1000 - 1
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 分频系数:72MHz / (71+1) = 1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频因子,通常为0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);// 配置通道1(PB4)为 PWM 输出
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置为 PWM 模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能通道输出
TIM_OCInitStructure.TIM_Pulse = 500; // 设置占空比为 50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效
TIM_OC1Init(TIM3, &TIM_OCInitStructure); // 初始化 TIM3 的通道1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能预装载// 配置通道2(PB5)为 PWM 输出
TIM_OCInitStructure.TIM_Pulse = 500; // 设置占空比
TIM_OC2Init(TIM3, &TIM_OCInitStructure); // 初始化 TIM3 的通道2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能预装载// 启动 TIM3
TIM_Cmd(TIM3, ENABLE);
六、总结与建议
STM32F103
的外设引脚不能随意指定,必须遵守 ST 提供的默认映射或预设重映射规则。- 若默认引脚被 JTAG 或其他功能占用,应先通过
GPIO_PinRemapConfig
释放。 - 想要使用非默认引脚的外设功能,必须启用部分或完全重映射。
- 所有外设的映射组合、支持的重映射模式,都可以在参考手册第九章“AFIO”中查阅。
建议在项目初期就根据引脚分布图和重映射选项合理规划外设引脚,避免开发中途资源冲突。
如需延伸内容(如编码器输入、PWM测频、双路电机控制等),欢迎留言讨论交流。
(完)