STM32的SPI双机通信实现

可实现STM32间稳定可靠的SPI通信。实际项目需根据具体需求调整缓冲区大小、传输模式和错误处理策略。建议先通过逻辑分析仪验证基础时序,再逐步优化性能参数。

一、硬件连接规范

1. 标准4线SPI连接

主机(STM32F103C8T6)       从机(STM32F103ZET6)
-------------------------------
SCK  →  SCK(PA5→PA5)
MOSI →  MOSI(PA7→PA7)
MISO ←  MISO(PA6←PA6)
NSS  →  NSS(PA4→PA4)
GND  →  GND
3.3V →  3.3V

2. 关键参数匹配

参数 主机配置 从机配置
SPI模式 主模式(Master) 从模式(Slave)
时钟极性 CPOL=1(空闲高电平) CPOL=1
时钟相位 CPHA=1(边沿采样) CPHA=1
数据位宽 8位 8位
片选方式 软件控制(NSS=Soft) 硬件控制(NSS=Hard)

二、软件实现方案

1. HAL库配置流程

// 主机初始化(CubeMX生成)
void MX_SPI1_Init(void) {
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;      // 主模式
    hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;  // 8位数据
    hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; // CPOL=1
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;    // CPHA=1
    hspi1.Init.NSS = SPI_NSS_SOFT;            // 软件片选
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // 36MHz/2=18MHz
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;   // 高位优先
    HAL_SPI_Init(&hspi1);
}

// 从机初始化
void MX_SPI2_Init(void) {
    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_SLAVE;         // 从模式
    hspi2.Init.Direction = SPI_DIRECTION_2LINES; 
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi2.Init.NSS = SPI_NSS_HARD;            // 硬件片选
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
    HAL_SPI_Init(&hspi2);
}

2. 数据传输模式对比

模式 主机代码示例 从机代码示例 适用场景
阻塞模式 HAL_SPI_Transmit(&hspi1, data, 1, 1000); HAL_SPI_Receive(&hspi2, buffer, 1, 1000); 简单单次通信
中断模式 HAL_SPI_Transmit_IT(&hspi1, data, 1); HAL_SPI_Receive_IT(&hspi2, buffer, 1); 实时响应需求
DMA模式 HAL_SPI_Transmit_DMA(&hspi1, data, 100); HAL_SPI_Receive_DMA(&hspi2, buffer, 100); 大数据量传输

三、关键算法实现

1. CRC校验(增强可靠性)

// CRC16-CCITT计算
uint16_t SPI_CRC16(uint8_t *data, uint16_t len) {
    uint16_t crc = 0xFFFF;
    for(uint16_t i=0; i<len; i++) {
        crc ^= (uint16_t)data[i] << 8;
        for(uint8_t j=0; j<8; j++) {
            if(crc & 0x8000) crc = (crc << 1) ^ 0x1021;
            else crc <<= 1;
        }
    }
    return crc;
}

// 发送带CRC的数据
void Send_With_CRC(uint8_t *data, uint16_t len) {
    uint16_t crc = SPI_CRC16(data, len);
    HAL_SPI_Transmit(&hspi1, data, len, 1000);
    HAL_SPI_Transmit(&hspi1, (uint8_t*)&crc, 2, 1000);
}

2. 双缓冲DMA配置

// 主机DMA配置(STM32F103)
void DMA_SPI_Config() {
    DMA_InitTypeDef DMA_InitStruct = {0};
    
    // 发送通道配置
    DMA_InitStruct.DMA_Channel = DMA_Channel_3;  // SPI1_TX对应DMA1_CH3
    DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStruct.DMA_BufferSize = 1024;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PINC_DISABLE;
    DMA_InitStruct.DMA_MemoryInc = DMA_MINC_ENABLE;
    HAL_DMA_Init(&DMA_InitStruct);
    
    // 接收通道配置
    DMA_InitStruct.DMA_Channel = DMA_Channel_2;  // SPI1_RX对应DMA1_CH2
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
    HAL_DMA_Init(&DMA_InitStruct);
}

// 启动DMA传输
HAL_DMA_Start_IT(htim1.Instance, (uint32_t)data_tx, (uint32_t)data_rx, 1024);
HAL_SPI_Transmit_DMA(&hspi1, data_tx, 1024);
HAL_SPI_Receive_DMA(&hspi1, data_rx, 1024);

四、扩展应用场景

  1. 传感器网络

    • 主机轮询多个从机(通过GPIO模拟多片选)
    void Select_Slave(uint8_t slave_id) {
        switch(slave_id) {
            case 0: HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); break;
            case 1: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); break;
        }
    }
    
  2. 固件升级

    • 通过SPI传输Bootloader数据
    void SPI_Firmware_Update(uint8_t *fw_data, uint32_t size) {
        while(size--) {
            HAL_SPI_Transmit(&hspi1, fw_data++, 1, 1000);
            HAL_SPI_Receive(&hspi1, ack_buf, 1, 1000);  // 等待ACK
        }
    }
    
  3. 高速数据采集

    • 使用DMA+双缓冲实现连续采样
    #define BUFFER_SIZE 2048
    uint16_t adc_buffer[2][BUFFER_SIZE];
    
    void MX_DMA_Init() {
        HAL_DMA_Start_IT(&hdma_spi_rx, (uint32_t)adc_buffer[0], 
                         (uint32_t)adc_buffer[1], BUFFER_SIZE);
    }
    

参考代码 STM32 SPI双机通信 www.youwenfan.com/contentcnm/72372.html

五、调试工具推荐

  1. 逻辑分析仪 Saleae/DSView捕获SPI时序 关键参数设置:时钟频率≥2倍SPI速率
  2. 示波器探头 使用差分探头测量SCK/MOSI/MISO信号 探头带宽≥500MHz
  3. 协议分析工具 Saleae Logic 2支持SPI协议解析 自动识别主从设备交互过程

六、注意事项

  1. 硬件设计要点 使用屏蔽双绞线(如Cat5e网线) 总线长度≤1米(>1米需加信号中继) 电源滤波:0.1μF+10μF并联

  2. 软件健壮性设计

    • 添加超时机制防止死锁
    #define SPI_TIMEOUT 1000
    HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi1, data, len, SPI_TIMEOUT);
    if(status != HAL_OK) {
        Error_Handler();  // 进入错误处理流程
    }
    
    • 实现软件复位功能
    void SPI_Reset() {
        HAL_SPI_DeInit(&hspi1);
        MX_SPI1_Init();  // 重新初始化
    }
    
posted @ 2025-11-27 16:46  徐中翼  阅读(0)  评论(0)    收藏  举报