跳到主要内容

STM32 SPI 数据传输

SPI(Serial Peripheral Interface,串行外设接口)是一种高速、全双工的同步通信协议,广泛应用于微控制器与外部设备(如传感器、存储器、显示器等)之间的数据传输。STM32 微控制器内置了强大的 SPI 外设,支持多种配置模式,能够满足不同应用场景的需求。

SPI 基本概念

SPI 通信通常涉及以下四个信号线:

  1. SCK(Serial Clock):时钟信号,由主设备生成,用于同步数据传输。
  2. MOSI(Master Out Slave In):主设备输出,从设备输入的数据线。
  3. MISO(Master In Slave Out):主设备输入,从设备输出的数据线。
  4. NSS(Slave Select):从设备选择信号,用于选择特定的从设备进行通信。

SPI 通信是全双工的,意味着数据可以同时在 MOSI 和 MISO 线上传输。主设备通过 SCK 信号控制数据传输的速率,并通过 NSS 信号选择要通信的从设备。

STM32 SPI 配置步骤

在 STM32 中使用 SPI 进行数据传输通常需要以下步骤:

  1. 初始化 SPI 外设:配置 SPI 的工作模式、数据帧格式、时钟极性(CPOL)和时钟相位(CPHA)等参数。
  2. 配置 GPIO 引脚:将 SPI 相关的引脚(SCK、MOSI、MISO、NSS)配置为复用功能。
  3. 启用 SPI 外设:启动 SPI 外设,使其进入工作状态。
  4. 发送和接收数据:通过 SPI 数据寄存器发送和接收数据。
  5. 处理中断或 DMA(可选):如果需要高效的数据传输,可以使用中断或 DMA 来处理数据。

代码示例:SPI 初始化与数据传输

以下是一个简单的 STM32 SPI 初始化与数据传输的代码示例:

#include "stm32f4xx.h"

void SPI1_Init(void) {
// 启用 GPIOA 和 SPI1 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

// 配置 GPIOA 引脚为 SPI 复用功能
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);

// 配置 SPI1
SPI_InitTypeDef SPI_InitStruct;
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);

// 启用 SPI1
SPI_Cmd(SPI1, ENABLE);
}

uint8_t SPI1_TransmitReceive(uint8_t data) {
// 等待发送缓冲区为空
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
// 发送数据
SPI_I2S_SendData(SPI1, data);
// 等待接收缓冲区非空
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
// 返回接收到的数据
return SPI_I2S_ReceiveData(SPI1);
}

输入与输出

在上述代码中,SPI1_TransmitReceive 函数用于发送一个字节的数据并接收从设备返回的数据。例如,发送 0x55 并接收返回的数据:

uint8_t receivedData = SPI1_TransmitReceive(0x55);

实际应用场景

SPI 通信在嵌入式系统中有着广泛的应用。以下是一些常见的应用场景:

  1. 传感器数据读取:许多传感器(如温度传感器、加速度计等)通过 SPI 接口与微控制器通信。
  2. 存储器访问:SPI Flash 存储器常用于存储配置数据或固件。
  3. 显示器控制:某些 LCD 或 OLED 显示器通过 SPI 接口接收显示数据。
提示

在实际应用中,SPI 通信的速度和稳定性非常重要。可以通过调整 SPI 的时钟分频器来优化通信速度,同时确保信号完整性。

总结

SPI 是一种高效、灵活的通信协议,适用于多种嵌入式应用场景。通过 STM32 的 SPI 外设,开发者可以轻松实现与外部设备的高速数据传输。本文介绍了 SPI 的基本概念、配置步骤以及代码示例,帮助初学者快速上手 STM32 SPI 通信。

附加资源与练习