avatar

松果工作室

欢迎光临

  • 首页
  • ESP
  • LVGL
  • CubeMX
  • freeRTOS
  • 快速笔记
  • 个人收藏
  • 我的服务
  • 考察日志
Home [CubeMX] SPI
文章

[CubeMX] SPI

Posted 2026-03-7 Updated 2026-03- 7
By YCP
10~13 min read

在 SPI 总线协议设计上,从机不会主动向主机发送数据。SPI 是一种 严格的主机驱动(Master-driven)通信协议,所有通信都必须由主机发起。常用的 STM32CubeMX SPI 主机 + 中断方案。流程分为三部分:

1️⃣ CubeMX 配置
2️⃣ 代码实现(HAL 中断模式)
3️⃣ 简单测试程序

以下以 SPI1 主机 + 全双工中断通信 为例。


一、CubeMX 配置

1 选择 SPI

在 Pinout & Configuration

选择:

SPI1 → Mode → Full-Duplex Master

CubeMX 会自动分配

引脚功能
SCKSPI 时钟
MISO主机接收
MOSI主机发送
NSS软件管理

建议:

NSS → Software

因为主机通常自己控制 CS。


2 SPI 参数配置

进入

SPI1 → Parameter Settings

推荐配置:

参数设置
ModeFull Duplex Master
Data Size8 Bits
First BitMSB
Clock PolarityLow
Clock Phase1 Edge
NSSSoftware
Baudrate Prescaler16 或 32
CRCDisable

如果不确定 SPI 模式:

Mode0 (CPOL=0 CPHA=0)

最常见。


3 使能 SPI 中断

进入:

NVIC Settings

勾选

SPI1 global interrupt

4 生成代码

Project Manager → Generate Code


二、SPI 中断代码结构

CubeMX 会生成

spi.c
stm32xx_it.c
main.c

HAL SPI 中断 API:

HAL_SPI_Transmit_IT()
HAL_SPI_Receive_IT()
HAL_SPI_TransmitReceive_IT()

通常使用

HAL_SPI_TransmitReceive_IT()

因为 SPI 是同步收发。


三、示例代码

1 全局变量

在 main.c

uint8_t tx_buf[8] = {1,2,3,4,5,6,7,8};
uint8_t rx_buf[8];

volatile uint8_t spi_done = 0;

2 发送函数

void spi_send_test()
{
    spi_done = 0;

    HAL_SPI_TransmitReceive_IT(
        &hspi1,
        tx_buf,
        rx_buf,
        sizeof(tx_buf)
    );
}

3 完成回调

HAL 会自动调用

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi->Instance == SPI1)
    {
        spi_done = 1;
    }
}

4 错误回调(建议加)

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi->Instance == SPI1)
    {
        printf("SPI Error\n");
    }
}

5 主循环测试

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

    MX_GPIO_Init();
    MX_SPI1_Init();

    spi_send_test();

    while (1)
    {
        if(spi_done)
        {
            spi_done = 0;

            printf("SPI RX:");

            for(int i=0;i<8;i++)
                printf("%02X ", rx_buf[i]);

            printf("\n");

            HAL_Delay(1000);

            spi_send_test();
        }
    }
}

四、中断函数(CubeMX 已生成)

在

stm32xx_it.c

会有:

void SPI1_IRQHandler(void)
{
    HAL_SPI_IRQHandler(&hspi1);
}

不用修改。


五、CS 控制(重要)

SPI 主机一般自己控制 CS。

CubeMX:

不要用 NSS

自己用 GPIO。

例如:

#define SPI_CS_LOW()  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET)
#define SPI_CS_HIGH() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET)

发送:

SPI_CS_LOW();

HAL_SPI_TransmitReceive_IT(&hspi1, tx_buf, rx_buf, 8);

完成回调:

SPI_CS_HIGH();

六、完整 SPI 读取流程示例

SPI 是同步全双工通信,在读取的同时,也同时接收。

但是从机不可能在 SPI 读的同时就知道他要读哪个寄存器,从而在收到第一个字节的同时返回寄存器数据。

因此一般 SPI 主机先发送寄存器地址,但不进行读取,然后发送要一定长度的虚拟字节,再让从机返回寄存器数据。

例如读取 SPI Flash:

命令 0x03
地址 0x000010

时序:

MOSI : 03 00 00 10 FF FF FF
MISO : XX XX XX XX D1 D2 D3

代码通常写成:

uint8_t cmd[4]={0x03,0x00,0x00,0x10};
uint8_t data[3] = {0}

HAL_SPI_Transmit(&hspi1, cmd, 4, 100);
HAL_SPI_Receive(&hspi1, data, 3, 100);

或者:

uint8_t tx[7]={0x03,0x00,0x00,0x10,0xFF,0xFF,0xFF};
uint8_t rx[7]={0};

HAL_SPI_TransmitReceive(&hspi1, tx, rx, 7, 100);
CubeMX
License:  CC BY 4.0
Share

Further Reading

OLDER

[adb] 读取屏幕内容与点击,用于测试

NEWER

[CubeMX] 串口 DMA

Recently Updated

  • [adb] 读取屏幕内容与点击,用于测试
  • [CubeMX] SPI
  • [CubeMX] 串口 DMA
  • [CubeMX] 基础工程配置
  • (LVGL)接口预览 样式

Trending Tags

LVGL WCH Linux Elec ThatProject freeRTOS STM ESP Flutter Others

Contents

©2026 松果工作室. Some rights reserved.

Using the Halo theme Chirpy