SPI通信协议

一、传输方式:

(一)全双工同步传输,硬件上强制性同时收发。只支持一主多从模式。

二、传输类型:

(一)主从式通信:

1.主设备(Master):负责生成时钟信号并控制通信时序

2.从设备(Slave):响应主设备的指令,在时钟信号控制下收发数据

三、引脚数:4

(一)CS/SS:

(二)SCK:

(三)MOSI:

(四)MISO:

四、数据传输流程、方式

(一)通讯开始:

(二)通讯结束:

(三)数据传输--主从设备的配置需要相同

1.根据数据的采样时间和数据的改变时间,分有四种模式。

(1)CPOL(Clock Polarity时钟极性):定义了时钟线在空闲状态(即CS有效但SCK还没开始跳变时)的电平。

(2)CPHA(Clock Phase时钟相位):定义了数据采样的时刻。

2.代码配置相关如下

(1)SPI_CPOL:控制时钟空闲时的电平

        ①SPI_CPOL_Low:时钟空闲时 低电平

        ②SPI_CPOL_High:时钟空闲时 高电平

(2)SPI_CPHA:控制在时钟的哪个边沿采样数据

        ①SPI_CPHA_1Edge:第1个边沿进行数据采样

        ②SPI_CPHA_2Edge:第2个边沿进行数据采样

(3)SPI_FirstBit:控制是先发最高位还是最低位

        ①SPI_FirstBit_MSB:高位先行

        ②SPI_FirstBit_LSB:低位先行

五、引脚配置

(一)输出引脚MOSI:推挽输出

(二)输入引脚MISO:上拉输入/浮空输入

六、主从机连接示意图,及其数据传输方式说明

(一)独立片选

1.共用信号线:SCK、MOSI、MISO

2.连接说明:独立片选,主机为每个从设备提供一条独立的CS信号线

3.数据传输方式:

        ①寻址:主机通过拉低目标从设备专属的 CS 线,来选中并激活该设备。

       ② 通信:主机与被唯一选中的从设备进行全双工SPI通信。其他从设备因 CS 为高电平而忽略总线活动。

        ③结束:主机拉高 CS,结束与该从设备的本次通信。

(二)菊花链

1.共用信号线:SCK、CS

2.连接说明:整个菊花链被看作一个大型的、分布式的移位寄存器。只有第一台从机的MISO是直接连接主机的MOSI,后面的从机都是连接前面的从机的MOSI。

3.数据传输方式:

        ①启动:主机拉低 CS,启动对所有从机的同步通信。

        ②通信:主机产生 N × 数据位 个时钟脉冲(N为从机数量)。数据从主机的 MOSI 移入第一个从机。在后续的每个时钟脉冲,数据依次向后级从机传递,最后一个从机的数据移入主机的 MISO。

        ③结束:当主机拉高 CS 时,所有从机同时锁存并处理各自移位寄存器中的数据。

(三)片选译码器

1.共用信号线:MOSI、MISO、SCK。

2.连接说明:由多个GPIO承担CS的功能,经过N-N²译码器后实现少量IO口控制多个从SPI设备。

3.数据传输方式:

①寻址:主机在地址线上输出目标从设备的二进制地址。

②使能:译码器根据地址,将一条对应的输出线拉低(激活对应从设备的CS)。

③通信:主机与被唯一选中的从设备进行标准的全双工SPI通信。

④结束:主机拉高 CS(通过改变地址线),结束通信。以少量主机引脚(如3个)控制大量从设备(如8个),在节省引脚和通信灵活性之间取得平衡。

七、STM32F103C8T5标准库代码


一、传输方式:

(一)全双工同步传输,硬件上强制性同时收发。只支持一主多从模式。

SPI设备具有移位寄存器,主机的发送和从机的接收都是通过移位最低位的数据进行的。所以主机发送了多少bit,从机也会向主机发送多少bit

无硬件应答机制、占用引脚较多(相比I2C)、无错误校验

=========================================================================

二、传输类型:

(一)主从式通信:

1.主设备(Master):负责生成时钟信号并控制通信时序

2.从设备(Slave):响应主设备的指令,在时钟信号控制下收发数据

        一个SPI主设备可以连接多个从设备,通过片选信号选择要通信的特定从设备。片选信号默认高电平,当下拉成低电平时,从机就会接收主机的数据。

=========================================================================

三、引脚数:4

(一)CS/SS:

        Slave Select,片选引脚。用于选择不同设备,每根片选线对应一个设备

(二)SCK:

        Serial Clock,时钟引脚。保证通信双方的使用同一频率时钟通信,完全由主机提供

(三)MOSI:

        Master Out Slave In,主机输出,从机输入。(主机输出的数据,输入给从机)

(四)MISO:

        Master In Slave Out,主机输入,从机输出。(从机输出的数据,输入给主机)

=========================================================================

四、数据传输流程、方式

(一)通讯开始:

        主机拉低SS/CS电平,表示选中目标从机。(SS/CS空闲高电平)

(二)通讯结束:

        主机拉高SS/CS电平,表示结束通讯

(三)数据传输--主从设备的配置需要相同

相关参数有:高/低位先行,上/下边沿检测、上/下边沿修改数据

1.根据数据的采样时间数据的改变时间,分有四种模式。

(1)CPOL(Clock Polarity时钟极性):定义了时钟线在空闲状态(即CS有效但SCK还没开始跳变时)的电平。

        CPOL = 0:空闲时,时钟是低电平

        CPOL = 1:空闲时,时钟是高电平

(2)CPHA(Clock Phase时钟相位):定义了数据采样的时刻

        CPHA = 0:在时钟的第一个边沿采样数据。

        CPHA = 1:在时钟的第二个边沿采样数据。

模式CPOLCPHA时钟空闲状态数据采样时刻数据移位时刻
000低电平时钟的上升沿时钟的下降沿
101低电平时钟的下降沿时钟的上升沿
210高电平时钟的下降沿时钟的上升沿
311高电平时钟的上升沿时钟的下降沿
(3)以模式0说明
初始状态:

        SCLK 保持低电平(CPOL=0)。

        主设备将待发送数据的最高位(MSB)放到MOSI线上。

        从设备将其待发送数据的最高位(MSB)放到MISO线上。

        此时数据线已经稳定。

第一个时钟上升沿(采样时刻):

        主设备产生一个时钟上升沿。

        在这个上升沿瞬间,主设备会读取(采样) MISO线上的电平(即从设备发来的bit),并将其移入自身移位寄存器的最低位(LSB)。

        同样在这一瞬间,从设备会读取(采样) MOSI线上的电平(即主设备发来的bit),并将其移入自身移位寄存器的最低位(LSB)。

        简单说:时钟上升沿是“收数据”的时刻。

第一个时钟下降沿(设置时刻):

        主设备将时钟拉低。

        在时钟变为低电平后,主设备和从设备会同时将各自移位寄存器中的下一个bit(原次高位)推到MOSI和MISO线上。

        简单说:时钟下降沿之后是“准备新数据”的时刻。

重复:

        上述过程重复8次(对于8位数据)。每一个时钟周期(一个上升沿+一个下降沿),主从设备都互相交换一个bit

传输完成:

        8个时钟脉冲后,最初在主设备移位寄存器里的8位数据,已经全部移到了从设备的移位寄存器中。

        同时,最初在从设备移位寄存器里的8位数据,也全部移到了主设备的移位寄存器中。

        一次完整的SPI通信,总是同时完成数据的发送和接收

2.数据传输示意图

3.三个重要参数代码配置相关如下

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//SPI的时钟极性,低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//SPI的时钟相位,第一边沿
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI的数据传输顺序,MSB先行
(1)SPI_CPOL:控制时钟空闲时的电平
        ①SPI_CPOL_Low:时钟空闲时 低电平
        ②SPI_CPOL_High:时钟空闲时 高电平
(2)SPI_CPHA:控制在时钟的哪个边沿采样数据
        ①SPI_CPHA_1Edge:第1个边沿进行数据采样
        ②SPI_CPHA_2Edge:第2个边沿进行数据采样
(3)SPI_FirstBit:控制是先发最高位还是最低位
        ①SPI_FirstBit_MSB:高位先行
        ②SPI_FirstBit_LSB:低位先行

=========================================================================

五、引脚配置

(一)输出引脚MOSI:推挽输出

        推挽模式的高低电平都有驱动性,且电平变化快

(二)输入引脚MISO:上拉输入/浮空输入

=========================================================================

六、主从机连接示意图,及其数据传输方式说明

(一)独立片选

1.共用信号线:SCK、MOSI、MISO

2.连接说明:独立片选,主机为每个从设备提供一条独立的CS信号线

3.数据传输方式:

        ①寻址:主机通过拉低目标从设备专属的 CS 线,来选中并激活该设备。
       ② 通信:主机与被唯一选中的从设备进行全双工SPI通信。其他从设备因 CS 为高电平而忽略总线活动。
        ③结束:主机拉高 CS,结束与该从设备的本次通信。

———————————————————————————————————————————

(二)菊花链

1.共用信号线:SCK、CS

2.连接说明:整个菊花链被看作一个大型的、分布式的移位寄存器。只有第一台从机的MISO是直接连接主机的MOSI,后面的从机都是连接前面的从机的MOSI。

3.数据传输方式:

        ①启动:主机拉低 CS,启动对所有从机的同步通信。
        ②通信:主机产生 N × 数据位 个时钟脉冲(N为从机数量)。数据从主机的 MOSI 移入第一个从机。在后续的每个时钟脉冲,数据依次向后级从机传递,最后一个从机的数据移入主机的 MISO
        ③结束:当主机拉高 CS 时,所有从机同时锁存并处理各自移位寄存器中的数据。

———————————————————————————————————————————

(三)片选译码器

1.共用信号线:MOSI、MISO、SCK。

2.连接说明:由多个GPIO承担CS的功能,经过N-N²译码器后实现少量IO口控制多个从SPI设备。

3.数据传输方式:

①寻址:主机在地址线上输出目标从设备的二进制地址。
②使能:译码器根据地址,将一条对应的输出线拉低(激活对应从设备的CS)。
③通信:主机与被唯一选中的从设备进行标准的全双工SPI通信。
④结束:主机拉高 CS(通过改变地址线),结束通信以少量主机引脚(如3个)控制大量从设备(如8个),在节省引脚和通信灵活性之间取得平衡。

=========================================================================

七、STM32F103C8T6标准库代码(硬件SPI)

#include "spi.h"
#include "delay.h"

// SPI初始化 - 修改函数名
void RC522_SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // 使能GPIO和SPI时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // 配置SPI引脚 (SCK->PA5, MISO->PA6, MOSI->PA7)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置CS引脚 (PA4)
    GPIO_InitStructure.GPIO_Pin = RC522_CS_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(RC522_CS_PORT, &GPIO_InitStructure);
    
    // 配置RST引脚 (PA0)
    GPIO_InitStructure.GPIO_Pin = RC522_RST_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(RC522_RST_PORT, &GPIO_InitStructure);
    
    // SPI1配置
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI的工作模式,双线全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//SPI的工作模式,主模式
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI的数据大小,8位
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//SPI的时钟极性,低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//SPI的时钟相位,第一边沿
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI的数据传输顺序,MSB先行
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//SPI的片选方式,软件控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI的波特率预分频

    SPI_InitStructure.SPI_CRCPolynomial = 7;
    
    // 使用SPI_Init函数,传入参数
    SPI_Init(SPI1, &SPI_InitStructure);
    
    // 使能SPI1
    SPI_Cmd(SPI1, ENABLE);
    
    // 初始化引脚状态
    RC522_CS_HIGH();
    RC522_RST_HIGH();
}

// SPI读取一个字节
uint8_t SPI_ReadByte(void)
{
    // 等待发送缓冲区空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送虚拟数据以接收数据
    SPI_I2S_SendData(SPI1, 0xFF);
    
    // 等待接收缓冲区非空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 返回接收到的数据
    return SPI_I2S_ReceiveData(SPI1);
}

// SPI写入一个字节
void SPI_WriteByte(uint8_t data)
{
    // 等待发送缓冲区空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送数据
    SPI_I2S_SendData(SPI1, data);
    
    // 等待接收完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 读取接收到的数据(丢弃)
    SPI_I2S_ReceiveData(SPI1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值