单片机
返回首页

STM32使用LL库实现硬件SPI数据发送流程详解

2025-10-09 来源:cnblogs

一、在 STM32 上使用 LL 库(Low-Layer Library) 通过硬件 SPI 发送数据需要以下关键步骤:

1. 初始化 SPI 外设

使用 LL_SPI_Init() 配置 SPI 参数,例如模式、数据宽度、波特率等:


LL_SPI_InitTypeDef SPI_InitStruct = {0};


SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;  // 全双工模式

SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;               // 主模式

SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;       // 8 位数据

SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;     // CPOL=0

SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;         // CPHA=0

SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; // 波特率分频

SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;             // 高位在前


LL_SPI_Enable(SPI1);                                     //使能 SPI 外设

LL_SPI_Init(SPI1, &SPI_InitStruct);


2. 配置 GPIO 引脚

设置 SPI 相关引脚(SCK, MOSI, MISO, NSS)为复用功能模式:


LL_GPIO_InitTypeDef GPIO_InitStruct = {0};


// 配置 MOSI (PA7) 和 SCK (PA5)

GPIO_InitStruct.Pin = LL_GPIO_PIN_7 | LL_GPIO_PIN_5;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;         // 复用模式

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_5;              // 根据芯片型号选择 AF


LL_GPIO_Init(GPIOA, &GPIO_InitStruct);


3. 使能 SPI 外设

LL_SPI_Enable(SPI1);


4. 发送数据

通过检查 TXE(发送缓冲区空)标志,向数据寄存器写入数据:


// 等待发送缓冲区为空

while (!LL_SPI_IsActiveFlag_TXE(SPI1));


// 发送单字节数据

LL_SPI_TransmitData8(SPI1, data_byte);


// 可选:等待传输完成(避免过早关闭SPI)

while (LL_SPI_IsActiveFlag_BSY(SPI1));


5. 处理接收数据(全双工模式)

如果使用全双工模式,需读取接收的数据:


// 等待接收缓冲区非空

while (!LL_SPI_IsActiveFlag_RXNE(SPI1));


// 读取接收到的数据

uint8_t rx_data = LL_SPI_ReceiveData8(SPI1);


6. 关闭 SPI(可选)

传输完成后可关闭 SPI 以省电:


LL_SPI_Disable(SPI1);

关键点说明

1、时钟配置:确保 SPI 时钟已通过 LL_RCC_SetSPIClockSource() 正确配置。



2、NSS 引脚:硬件 NSS 可通过 LL_SPI_SetNSSMode() 配置为硬件管理,或手动控制 GPIO。


3、中断/DMA:可通过 LL_SPI_EnableIT_TXE() 启用中断,或使用 DMA 提高效率。


7.示例代码(发送单字节)

void SPI_SendByte(uint8_t data) {

    // 等待发送缓冲区就绪

    while (!LL_SPI_IsActiveFlag_TXE(SPI1));

    

    // 写入数据

    LL_SPI_TransmitData8(SPI1, data);

    

    // 等待传输完成

    while (LL_SPI_IsActiveFlag_BSY(SPI1));

}


8.示例代码(接收单字节数据)

在 SPI 主模式下,接收数据需要先发送一个虚拟字节(如 0xFF)以触发时钟,从而读取从机返回的数据。


uint8_t SPI_ReceiveByte(void) {

    uint8_t dummy_data = 0xFF;  // 虚拟数据,用于生成时钟

    uint8_t rx_data = 0;


    // 1. 发送虚拟数据以生成时钟

    while (!LL_SPI_IsActiveFlag_TXE(SPI1));  // 等待发送缓冲区就绪

    LL_SPI_TransmitData8(SPI1, dummy_data);  // 发送虚拟数据


    // 2. 等待接收数据就绪

    while (!LL_SPI_IsActiveFlag_RXNE(SPI1)); // 等待接收缓冲区非空


    // 3. 读取接收到的数据

    rx_data = LL_SPI_ReceiveData8(SPI1);


    // 4. 等待传输完成(可选)

    while (LL_SPI_IsActiveFlag_BSY(SPI1));


    return rx_data;

}


9.同时发送和接收单字节(全双工)

在 SPI 全双工模式下,发送和接收是同步进行的。发送数据的同时,从机的响应数据也会被接收。


uint8_t SPI_TransmitReceiveByte(uint8_t tx_data) {

    uint8_t rx_data = 0;


    // 1. 等待发送缓冲区就绪

    while (!LL_SPI_IsActiveFlag_TXE(SPI1));


    // 2. 发送数据并触发接收

    LL_SPI_TransmitData8(SPI1, tx_data);


    // 3. 等待接收完成

    while (!LL_SPI_IsActiveFlag_RXNE(SPI1));


    // 4. 读取接收到的数据

    rx_data = LL_SPI_ReceiveData8(SPI1);


    // 5. 等待传输完成(避免过早关闭SPI)

    while (LL_SPI_IsActiveFlag_BSY(SPI1));


    return rx_data;

}


10、示例 :连续收发数据

如果需要发送/接收多个字节,可以循环调用上述函数:


void SPI_TransmitReceiveMultiple(uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) {

    for (uint32_t i = 0; i < size; i++) {

        rx_buf[i] = SPI_TransmitReceiveByte(tx_buf[i]);

    }

}


11、关键注意事项

11.1. SPI 模式与时钟配置

CPOL 和 CPHA:确保与从机设备的时序匹配(例如 LL_SPI_POLARITY_LOW + LL_SPI_PHASE_1EDGE 对应模式0)。


波特率:通过 LL_SPI_BAUDRATEPRESCALER_xxx 设置合适的时钟分频,确保不超过从机支持的最大速率。


11.2. NSS(片选信号)管理

如果使用软件 NSS 控制(软件模拟片选),需配置:


LL_SPI_SetNSSMode(SPI1, LL_SPI_NSS_SOFT);  // 软件控制片选

手动控制片选,需要在传输前拉低 GPIO,传输后拉高:


// 拉低片选(假设使用 PA4 作为 NSS)

LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);

SPI_TransmitReceiveByte(data);  // 发送/接收

LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);  // 拉高片选

11.3. 错误处理

检查 SPI 错误标志(如 OVR 溢出错误):


if (LL_SPI_IsActiveFlag_OVR(SPI1)) {

    LL_SPI_ClearFlag_OVR(SPI1);  // 清除溢出错误标志

}


通过以上示例,你可以实现 SPI 的单向接收、全双工通信及批量数据传输。实际应用中,若对性能要求较高,可进一步使用 中断 或 DMA 优化传输过程。


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 设计汽车集群电源

  • 6晶体管H桥

  • USB自供电声卡

  • AVR LCD温度计—LM35

  • AVR PC步进电机驱动器

  • AVR温度计TCN75

    相关电子头条文章