基于STM32的模拟SPI通讯

    科技2025-09-24  75

    基于STM32的模拟SPI通讯

    1.SPI协议介绍2.SPI通讯时序3.通讯模式代码模拟SPI模式0 模式1模式2模式3

    1.SPI协议介绍

    SPI协议是由摩托罗拉公式提出的通讯协议(Serial Peripheral Interface串行外设接口),是一种高速全双工的通信总线。 SPI通讯使用3条总线(SCK、MOSI、MISO)和片选线CS。

    CS:片选线也叫NSS,当有多个SPI设备与SPI主机相连时,设备的其他信号线SCK、MOSI、MISO同时并联到相同的SPI总线上(无论由多少个从设备,都共用这3条总线),而每个从设备都有独立的CS片选线,有多少个从设备就有多少个CS线。SPI通讯无设备地址,当主机要选择从设备时,把该从设备的CS线拉低该从设备就会被选中,片选有效,主机就可以开始和从设备进行SPI通讯。于是SPI通讯以CS低电平为起始信号,高电平为结束信号SCK:时钟线,由主机产生并决定通讯速率。MOSI ( Master Output , Slave Input):主机输出从机输入MISO ( Master Input, Slave Output ):主机输入从机输出

    2.SPI通讯时序

    NSS、SCK、MOSI由主机产生,MISO由从机产生,在SCK每个时钟周期MOSI、MISO传输一位数据,数据的输入输出是同时进行的。MSB先行或LSB先行无硬性规定。 MOSI和MISO在SCK上升沿期间变换,在SCK下降沿采样,SPI每次数据传输可以8位或16位为单位,每次传输的单位不受限制。

    3.通讯模式

    SPI通讯模式CPOLCPHA空闲时SCK时钟采样时刻000低电平奇数边沿101低电平偶数边沿210高电平奇数边沿311高电平偶数边沿

    主机需要与从机工作在相同模式下才可以正常通讯。

    代码

    模拟SPI

    模式0

    为什么读写函数写在一起:SPI必须生成时钟脉冲才能将数据移出。产生时钟脉冲的唯一方式是发送字节。产生时钟脉冲,才能读取数据。

    u8 Software_SPI_Write_Read(u8 data) { u8 i; u8 redata; for(i=0;i<8;i++) { SPI_SCK_0(); SysTick_Delay_Us(10); if(data & 0x80) { SPI_MOSI_1(); } else { SPI_MOSI_0(); } data <<= 1; SPI_SCK_1(); SysTick_Delay_Us(10); redata<<=1; if(SPI_MISO()) { redata++; } } return redata; }

    代码要点:因为模式0是上升沿进行读取数据。所以在出现上升沿时MISO会出现有效数据,只需要连续8个周期将数据保存下来就能得到8位输入数据。

    模式1

    u8 Software_SPI_Write_Read(u8 data) { u8 i; u8 redata; for(i=0;i<8;i++) { SPI_SCK_1(); SysTick_Delay_Us(10); if(data & 0x80) { SPI_MOSI_1(); } else { SPI_MOSI_0(); } data <<= 1; SPI_SCK_0(); SysTick_Delay_Us(10); redata<<=1; if(SPI_MISO()) { redata++; } } return redata; }

    模式2

    u8 Software_SPI_Write_Read(u8 data) { u8 i; u8 redata; for(i=0;i<8;i++) { SPI_SCK_1(); SysTick_Delay_Us(10); if(data & 0x80) { SPI_MOSI_1(); } else { SPI_MOSI_0(); } data <<= 1; SPI_SCK_0(); SysTick_Delay_Us(10); redata<<=1; if(SPI_MISO()) { redata++; } } return redata; }

    模式3

    u8 Software_SPI_Write_Read(u8 data) { u8 i; u8 redata; SPI_SCK_1(); SysTick_Delay_Us(10); for(i=0;i<8;i++) { SPI_SCK_0(); SysTick_Delay_Us(10); if(data & 0x80) { SPI_MOSI_1(); } else { SPI_MOSI_0(); } data <<= 1; SPI_SCK_1(); SysTick_Delay_Us(10); redata<<=1; if(SPI_MISO()) { redata++; } } return redata; }

    模式0和模式3经过实际验证读取W25Q64的Device ID读取成功,模式1和模式2等遇到支持这两种模式的设备时再进行验证,不过我认为应该是写对了的,毕竟几种模式的区别只有有效电平和读取时间不同,框架都一样。

    Github代码下载 完整工程下载 如有错误请提出

    Processed: 0.009, SQL: 8