You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 SPI的RXNE标志位始终未置位问题求助

STM32F303RE SPI2接收时RXNE标志始终未置位问题

问题描述

使用Nucleo开发板上的STM32F303RE微控制器开发SPI设备通信程序时功能异常,简化为单字节接收的最小实现代码后,程序卡在while (!(SPI2->SR & SPI_SR_RXNE));循环处,RXNE标志位始终未置位。

已尝试的解决方案

  • 设置SPI_CR2_FRXTH和SPI_CR2_SSOE位
  • 确保GPIO及SPI时钟已使能
  • 完成所有寄存器配置后再使能SPI2

最小复现代码

volatile char data = 'A';

int main(void) {
  HAL_Init();
  SystemClock_Config();

  RCC->AHBENR |= RCC_AHBENR_GPIOBEN;    // Enable GPIOB clock
  RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;   // Enable SPI2 clock

  // PB12 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER12_0;
  GPIOB->MODER |= GPIO_MODER_MODER12_1;

  // PB13 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER13_0;
  GPIOB->MODER |= GPIO_MODER_MODER13_1;

  // PB14 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER14_0;
  GPIOB->MODER |= GPIO_MODER_MODER14_1;

  // PB15 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER15_0;
  GPIOB->MODER |= GPIO_MODER_MODER15_1;

  // PB12 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12_1;

  // PB13 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_1;

  // PB14 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14_1;

  // PB15 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_1;

  // Alternate function 5 [0101]
  GPIOB->AFR[1] = 0;                                // Reset register
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH4_Pos;    // PB12
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH5_Pos;    // PB13
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH6_Pos;    // PB14
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH7_Pos;    // PB15

  SPI2->CR1 |= SPI_CR1_MSTR;    // Master Mode
  SPI2->CR2 |= SPI_CR2_FRXTH;   // 8-bit reception threshold

  // 8-bit data length [0111]
  SPI2->CR2 &= ~SPI_CR2_DS_Msk;
  SPI2->CR2 |= 0b0111 << SPI_CR2_DS_Pos;

  SPI2->CR2 |= SPI_CR2_SSOE;  // SS output enable
  SPI2->CR1 |= SPI_CR1_SPE;   // SPI enable

  while (!(SPI2->SR & SPI_SR_TXE));   // Wait for TX

  SPI2->DR = 'T';                     // Send some byte

  while (!(SPI2->SR & SPI_SR_RXNE));  // Wait for RX (Hangs)

  data = SPI2->DR;                    // Receive byte

  while (1) {

  }
}

问题分析与解决建议

1. GPIO复用功能寄存器赋值错误

代码中配置GPIOB的AFR[1]时,每次使用=赋值会覆盖之前的配置,最终只有PB15的复用功能被正确设置,PB12(NSS)、PB13(SCK)、PB14(MISO)的复用功能未生效,导致SPI硬件无法正常通信,RXNE标志无法置位。

修复方式:使用|=代替=,保留已配置的位:

GPIOB->AFR[1] = 0;                                // Reset register
GPIOB->AFR[1] |= 0b0101 << GPIO_AFRH_AFRH4_Pos;    // PB12
GPIOB->AFR[1] |= 0b0101 << GPIO_AFRH_AFRH5_Pos;    // PB13
GPIOB->AFR[1] |= 0b0101 << GPIO_AFRH_AFRH6_Pos;    // PB14
GPIOB->AFR[1] |= 0b0101 << GPIO_AFRH_AFRH7_Pos;    // PB15

2. 检查SPI时钟模式匹配性

SPI主模式下,CPOL(时钟极性)和CPHA(时钟相位)必须与从设备一致。默认配置为CPOL=0、CPHA=0,若从设备使用不同模式,需修改SPI_CR1寄存器的对应位:

  • 若需CPOL=1:SPI2->CR1 |= SPI_CR1_CPOL;
  • 若需CPHA=1:SPI2->CR1 |= SPI_CR1_CPHA;

3. 增加传输完成等待

发送字节后,可先等待BSY位清零确保传输完成,再检查RXNE标志:

SPI2->DR = 'T';                     // Send some byte
while (SPI2->SR & SPI_SR_BSY);      // Wait for transfer complete
while (!(SPI2->SR & SPI_SR_RXNE));  // Wait for RX

内容的提问来源于stack exchange,提问作者nhg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:49:58