問題描述
最近在使用 STM32F103ZET6 開發板調試串口時,遇到了一個詭異的問題:單片機能正常向 PC 發送數據,但始終無法接收 PC 下發的數據,甚至連串口接收中斷都沒觸發。更奇怪的是,相同的代碼在STM32F103C8T6 最小系統板上能完美運行收發雙向通信。經過多輪排查,發現串口重定向可以解決問題,在此記錄完整過程,給遇到類似問題的開發者避坑。
解決:引腳重定向
將 USART1 默認引腳(A9/A10)重定向到 GPIOB 的備用引腳,無需修改串口核心配置,僅調整引腳相關代碼即可。
硬件展示
第一個是問題開發板STM32F103ZET6,第二個是STM32F103C8T6


原始代碼 (A9/A10 配置,僅發不收)
以下代碼配置 USART1 默認引腳 A9(TX)、A10(RX),可正常發送但無法接收:
void USART_Init(void) {
// 1. 時鐘使能
// 引腳時鐘
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置USART1時鐘
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// 複用功能時鐘
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
// 2. 引腳配置
// 配置PA9為複用推輓輸出
GPIOA->CRH |= GPIO_CRH_MODE9;
GPIOA->CRH |= GPIO_CRH_CNF9_1;
GPIOA->CRH &= ~GPIO_CRH_CNF9_0;
// 配置PA10為複用輸入浮空
GPIOA->CRH &= ~GPIO_CRH_MODE10;
GPIOA->CRH &= ~GPIO_CRH_CNF10_1;
GPIOA->CRH |= GPIO_CRH_CNF10_0;
// 3. USART1配置
// 波特率
USART1->BRR = 0x271;
// 使能
USART1->CR1 |= USART_CR1_UE; // 使能USART1
USART1->CR1 |= USART_CR1_TE; // 發送使能
USART1->CR1 |= USART_CR1_RE; // 接收使能
// 其他配置
USART1->CR1 &= ~USART_CR1_M; // 數據字長8位
USART1->CR1 &= ~USART_CR1_PCE; // 禁止奇偶校驗
USART1->CR2 &= ~USART_CR2_STOP; // 1個停止位
// 中斷使能
USART1->CR1 |= USART_CR1_IDLEIE;
USART1->CR1 |= USART_CR1_RXNEIE;
NVIC_SetPriorityGrouping(3);
NVIC_SetPriority(USART1_IRQn, 3);
NVIC_EnableIRQ(USART1_IRQn);
}
改進代碼(重定向到 PB6/PB7,收發正常)
通過 AFIO 開啓 USART1 部分重映射,將引腳切換為 PB6(TX)、PB7(RX),核心配置不變:
void USART_Init(void) {
// 1. 時鐘使能
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // 改為GPIOB時鐘
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
11
// 2. 使能部分重映射
AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; // 部分重映射到PB6, PB7
// 3. 引腳配置 - PB6(TX), PB7(RX)
// 配置PB6為複用推輓輸出 (USART1_TX) GPIOB->CRL &= ~GPIO_CRL_CNF6; // 清除配置位
GPIOB->CRL |= GPIO_CRL_CNF6_1; // 複用推輓輸出
GPIOB->CRL |= GPIO_CRL_MODE6; // 輸出模式,最大速度50MHz
// 配置PB7為浮空輸入 (USART1_RX) GPIOB->CRL &= ~GPIO_CRL_MODE7; // 輸入模式
GPIOB->CRL &= ~GPIO_CRL_CNF7; // 清除配置位
GPIOB->CRL |= GPIO_CRL_CNF7_0; // 浮空輸入
// 4. USART1配置 (保持不變)
USART1->BRR = 0x271;
USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
USART1->CR1 &= ~USART_CR1_M;
USART1->CR1 &= ~USART_CR1_PCE;
USART1->CR2 &= ~USART_CR2_STOP;
// 中斷配置
USART1->CR1 |= USART_CR1_IDLEIE | USART_CR1_RXNEIE;
NVIC_SetPriorityGrouping(0);
NVIC_SetPriority(USART1_IRQn, 3);
NVIC_EnableIRQ(USART1_IRQn);
}
總結
問題根源大概率是 STM32F103ZET6 開發板的硬件設計:默認串口引腳 A9/A10 可能被板載其他外設(如 LCD、按鍵、SD 卡等)複用,導致接收引腳信號被佔用或干擾,表現為 “只發不收”。