复用映射

Tutorial: 卓越工程师 Category: 嵌入式 Published: 2026-10-23 11:05:29 Views: 0 Likes: 0 Comments: 0

138.5.10复用映射

/*
 * 整体目的:解释 07PWM 工程如何把 TIM3_CH1/CH2 从默认引脚重映射到 PB4/PB5。
 * 概念区分:复用模式决定“引脚由外设驱动”,重映射决定“外设信号走哪组合法引脚”。
 * 引脚冲突:PB4 默认还承担 JTAG 的 NJTRST,因此必须关闭 JTAG、保留 SWD 后才能稳定输出 TIM3_CH1。
 * 配置顺序:开启 AFIO/GPIOB 时钟 → 释放 JTAG 引脚 → 选择 TIM3 部分重映射
 *           → 将 PB4/PB5 配为复用推挽 → 启动 PWM 通道。
 * 代码范围:摘自 CubeIDE/07PWM 的 stm32f1xx_hal_msp.c 与 tim.c;HAL 宏内部不展开。
 */

/* ==================== Core/Src/stm32f1xx_hal_msp.c:AFIO 与调试口 ==================== */

void HAL_MspInit(void)                     /* HAL_Init() 调用的全局芯片级底层初始化函数。 */
{                                           /* 全局 MSP 初始化函数体开始。 */
    __HAL_RCC_AFIO_CLK_ENABLE();           /* 开启 AFIO 时钟,之后才能可靠修改 AFIO_MAPR。 */
    __HAL_RCC_PWR_CLK_ENABLE();            /* 开启电源控制模块时钟,保留 CubeMX 生成的基础配置。 */
    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* 设置 NVIC 优先级分组。 */
    __HAL_AFIO_REMAP_SWJ_NOJTAG();         /* 关闭 JTAG、保留 SWD,释放 PB3/PB4/PA15。 */
}                                           /* 全局 MSP 初始化函数结束。 */

/* ==================== Core/Src/tim.c:TIM3 通道重映射与 GPIO ==================== */

void HAL_TIM_MspPostInit(                  /* 定时器基础/通道配置后执行的 GPIO 后初始化。 */
    TIM_HandleTypeDef *timHandle)           /* 参数指出需要为哪一个定时器配置通道引脚。 */
{                                           /* 定时器 GPIO 后初始化函数体开始。 */
    GPIO_InitTypeDef GPIO_InitStruct = {0}; /* 清零 GPIO 配置结构体,避免未填写字段含随机值。 */

    if (timHandle->Instance == TIM3)       /* 只为 TIM3 执行 PB4、PB5 的通道配置。 */
    {                                       /* TIM3 GPIO 分支开始。 */
        __HAL_RCC_GPIOB_CLK_ENABLE();      /* 开启 GPIOB 时钟,使 PB4、PB5 配置寄存器可访问。 */
        GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5; /* 同时选择 PB4 和 PB5。 */
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; /* 设为复用推挽,让定时器输出级驱动引脚。 */
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; /* 100 Hz PWM 使用低速 GPIO 已足够。 */
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* 把复用输出配置写入 PB4、PB5。 */
        __HAL_AFIO_REMAP_TIM3_PARTIAL();   /* 设置 TIM3_REMAP=10:CH1→PB4、CH2→PB5。 */
    }                                       /* TIM3 GPIO 分支结束。 */
}                                           /* 定时器 GPIO 后初始化函数结束。 */

/* ==================== 同一外设的另一示例:USART1 重映射 ==================== */

__HAL_RCC_AFIO_CLK_ENABLE();               /* USART1 重映射同样要求 AFIO 时钟已经开启。 */
__HAL_AFIO_REMAP_USART1_ENABLE();          /* 将 USART1_TX/RX 从 PA9/PA10 改到 PB6/PB7。 */

一、GPIO配置详解

1.1 AFIO_REMAP配置解析

STM32F1 的 AFIO 负责部分外设引脚重映射。复用功能和重映射是两个相邻但不同的概念:

  • 复用功能:引脚由 GPIO 输出数据寄存器切换为某个外设信号控制;
  • 重映射:在芯片规定的几组合法引脚之间,改变某个外设信号的外部出口。

AFIO 必须先开启时钟,才能可靠写入 AFIO_MAPR。工程中的 __HAL_AFIO_REMAP_TIM3_PARTIAL() 会修改 TIM3_REMAP 位域。

1.2 复用和映射的概念

它们可以看作芯片内部的固定多路选择器:

                    ┌── PA6(默认)
TIM3_CH1 ──[映射选择]├── PB4(部分重映射)
                    └── PC6(完全重映射)

选择某一路后,还要把该引脚配置为复用输出;
没有出现在手册映射表中的引脚不能通过软件任意连接。
1.2.1 例题: 重映射配置示例

TIM3 的四个通道映射如下:

TIM3_REMAP[1:0]模式CH1CH2CH3CH4
00不重映射PA6PA7PB0PB1
01保留————
10部分重映射PB4PB5PB0PB1
11完全重映射PC6PC7PC8PC9

因此工程使用 PB4、PB5 时选择的是部分重映射,不是把 TIM3 通道随意搬到 PA4、PA5。

完整配置次序为:

  1. 使能 AFIO、GPIOB、TIM3 时钟;
  2. 若使用 PB4,关闭 JTAG 并保留 SWD;
  3. 把 TIM3 设置为部分重映射;
  4. 把 PB4、PB5 配置为复用推挽输出;
  5. 配置并启动 TIM3 对应通道。

PB4 复用 NJTRST,若仍启用完整 JTAG,定时器波形可能无法正常输出。__HAL_AFIO_REMAP_SWJ_NOJTAG() 只关闭 JTAG,保留 SWDIO/SWCLK,仍可使用常见两线调试。

1.3 应用案例

重映射的价值是解决 PCB 布线、引脚冲突和功能分配问题。但它也可能把信号搬到已经连接 LED、按键、调试口或其他外设的引脚,因此软件配置必须与原理图同时核对。

改变 AFIO_MAPR 只改变内部路由,不会自动配置 GPIO 模式。发送引脚通常要配置为复用推挽,接收引脚则按芯片系列与电气要求配置输入模式。

1.3.1 例题: USART1配置复用

USART1 的合法映射是:

模式TXRX
默认PA9PA10
重映射PB6PB7

使用 PB6/PB7 时,可调用:

__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_USART1_ENABLE();

随后应把 PB6 配为 USART1_TX 的复用推挽输出,把 PB7 配为接收输入,并确认 PB6 没有同时承担 TIM4_CH1 舵机输出。重映射不能解决同一物理引脚被两个外设同时使用的问题,只是为系统设计提供另一组固定选择。