STM32 SPI通信详解:从原理到实战代码

一、SPI通信基础

1.1 什么是SPI?

SPI(Serial Peripheral Interface)是由Motorola提出的全双工同步串行通信协议,广泛用于微控制器与外围设备(Flash、传感器、显示屏等)的高速数据传输。

核心特性:

  • 全双工通信(同时收发)

  • 最高时钟频率可达数十MHz

  • 主从架构(一主多从)

  • 硬件连接简单(4线制)

1.2 SPI物理接口

信号线全称作用
SCKSerial Clock同步时钟(由主机产生)
MOSIMaster Out Slave In主机发送,从机接收
MISOMaster In Slave Out主机接收,从机发送
NSSSlave Select从机片选(低电平有效)

二、SPI工作原理及时序

2.1 四种工作模式

由CPOL(时钟极性)CPHA(时钟相位)组合决定:

模式CPOLCPHA特性
000时钟空闲低电平,第一个边沿采样
101时钟空闲低电平,第二个边沿采样
210时钟空闲高电平,第一个边沿采样
311时钟空闲高电平,第二个边沿采样

关键点:

  • CPOL=0:SCK空闲时为低电平

  • CPOL=1:SCK空闲时为高电平

  • CPHA=0:在SCK第一个边沿(奇数边沿)采样数据

  • CPHA=1:在SCK第二个边沿(偶数边沿)采样数据

2.2 典型时序分析(模式0)

以主机发送0xAA(10101010)为例:

  1. NSS拉低:选中从机

  2. SCK产生脉冲:CPOL=0,空闲低电平

  3. 数据采样

    • MOSI在SCK上升沿改变数据

    • 从机在SCK下降沿采样数据

  4. 数据传输:高位(MSB)先发


三、STM32 SPI外设配置

3.1 硬件设计

以STM32F103C8T6与W25Q64 Flash芯片通信为例:

  • SCK -> PA5

  • MOSI -> PA7

  • MISO -> PA6

  • NSS -> PA4(软件控制)

3.2 CubeMX配置步骤

  1. 启用SPI1(模式选择为全双工主模式)

  2. 配置参数:

    • 时钟分频(PCLK2为72MHz时,分频256得281.25kHz)

    • 数据宽度:8位

    • 模式选择:Mode 0(CPOL=0, CPHA=0)

    • NSS选择:软件模式

  3. 生成代码

3.3 关键代码解析

初始化代码
SPI_HandleTypeDef hspi1;

void SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    HAL_SPI_Init(&hspi1);
}
数据收发函数
// 发送单字节并接收返回
uint8_t SPI_TransmitReceive(uint8_t data)
{
    uint8_t rx_data;
    HAL_SPI_TransmitReceive(&hspi1, &data, &rx_data, 1, 100);
    return rx_data;
}

// 读取Flash芯片ID(以W25Q64为例)
uint16_t W25Q_ReadID(void)
{
    uint8_t cmd = 0x9F; // JEDEC ID命令
    uint8_t id[3];
    
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 拉低NSS
    HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
    HAL_SPI_Receive(&hspi1, id, 3, 100);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 释放NSS
    
    return (id[1] << 8) | id[2]; // 返回厂商ID和设备ID
}

四、调试技巧与常见问题

4.1 示波器诊断

  • 检测SCK波形:确认频率和极性是否符合预期

  • 观察MOSI/MISO:验证数据发送是否正确

  • 检查NSS信号:确保片选信号正常拉低

4.2 常见问题排查

  1. 无数据通信

    • 检查硬件连接是否短路/断路

    • 验证SPI模式(主/从)设置是否正确

    • 确认NSS信号是否有效

  2. 数据错位

    • 检查MSB/LSB设置

    • 确认时钟相位设置是否匹配从机要求

  3. 通信速率问题

    • 降低波特率测试

    • 检查电源稳定性


五、进阶应用:DMA+SPI

5.1 使用DMA提升效率

// 启用DMA传输
void SPI_DMA_Transmit(uint8_t *pData, uint16_t Size)
{
    HAL_SPI_Transmit_DMA(&hspi1, pData, Size);
    while (hspi1.State != HAL_SPI_STATE_READY); // 等待传输完成
}

// 接收数据
void SPI_DMA_Receive(uint8_t *pData, uint16_t Size)
{
    HAL_SPI_Receive_DMA(&hspi1, pData, Size);
    while (hspi1.State != HAL_SPI_STATE_READY);
}

六、总结

本文详细解析了SPI协议的工作原理,并通过STM32实战代码演示了通信流程。实际开发中需注意:

  1. 严格匹配主从设备的SPI模式

  2. 合理选择通信速率(兼顾稳定性和速度)

  3. 复杂场景建议使用DMA减轻CPU负担


创作不易,如果本文对您有帮助,请点赞收藏支持!
关于SPI的更多问题,欢迎在评论区留言讨论

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值