stm32用ll库硬件spi发送数据的过程

一、在 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 优化传输过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值