SPI协议代码

SPI协议代码软件模拟SPI程序代码概述:   通过两个MCU(STM32F103)来模拟SPI的主从机,完成主机发送从机接收,便于理解SPI协议。SPI协议简介●SPI接口介绍  SCK:时钟信号,由主设备产生,所以主设备SCK信号为输出模式,从设备的SCK信号为输入模式。  CS:使能信号,由主设备控制从设备,,所以主设备CS信号为输出模式,从设备的CS信号为输入模式。  MOSI:主设备数据输出,从设备数据输入,所以主设备MOSI信号为输出模式,从设备的MOSI信号为输入模式。  MISO:主设备数

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

软件模拟SPI程序代码


概述:
   通过两个MCU(STM32F103)来模拟SPI的主从机,完成主机发送从机接收,便于理解SPI协议。

SPI协议简介

●SPI接口介绍

  SCK: 时钟信号,由主设备产生,所以主设备SCK信号为输出模式,从设备的SCK信号为输入模式。
  CS: 使能信号,由主设备控制从设备,,所以主设备CS信号为输出模式,从设备的CS信号为输入模式。
  MOSI: 主设备数据输出,从设备数据输入,所以主设备MOSI信号为输出模式,从设备的MOSI信号为输入模式。
  MISO: 主设备数据输入,从设备数据输出,所以主设备MISO信号为输入模式,从设备的MISO信号为输出模式。
  
SPI接口连接图
在这里插入图片描述
  注意:MOSI和MISO不能交叉连接(可以把主从机理解为一个整体系统,MOSI为系统主机发送从机接收的数据线,MISO为主机接收从机发送的数据线)。

●SPI数据传输方向

SPI作为全双工的的串行通信协议,数据传输时高位在前,低位在后。主机和从机公用由主机产生的SCK信号,所以在每个时钟周期内主机和从机有1bit的数据交换(因为MOSI和MISO数据线上的数据都是在时钟的边沿处被采样)。
  如下图:
 在这里插入图片描述
 SPI协议规定数据采样是在SCK的上升沿或下降沿时刻(由SPI模式决定,下面会说到),观察上图,在SCK的边沿处(上升沿或下降沿),主机会在MISO数据线上采样(接收来从机的数据),从机会在MOSI数据线上采样(接收来自主机的数据),所以每个时钟周期中会有一bit的数据交换。
 SPI数据交换

●SPI传输模式

SPI总线传输一共有4种模式,这4种模式分别由时钟极性(CPOL)和时钟相位(CPHA)来定义。
   在这里插入图片描述

CPOL CPHA
规定了SCK时钟信号空闲状态的电平 规定了数据是在SCK时钟的上升沿还是下降沿被采样
———– ————————————
模式0:CPOL=0,CPHA =0 SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据)
模式1:CPOL=0,CPHA =1 SCK空闲为低电平,数据在SCK的下降沿被采样(提取数据)
模式2:CPOL=1,CPHA =0 SCK空闲为高电平,数据在SCK的下降沿被采样(提取数据)
模式3:CPOL=1,CPHA =1 SCK空闲为高电平,数据在SCK的上升沿被采样(提取数据)

以模式0为例:
SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据),在SCK的下降沿切换数据线的数据。
在这里插入图片描述
  ◐在时钟的第1个上升沿(游标1处)(采样点)
  MOSI上数据为1,则在此边沿从机采样(提取)数据为1,采样点在MOSI数据线的中间。
  MISO上数据为0,则在此边沿主机采样(提取)数据为0,采样点在MISO数据线的中间。
  ◐在时钟的第1个下降沿(游标2处)(切换点)
  MOSI上数据由1切换为0,,数据在时钟下降沿时切换数据。
  MISO上数据由0切换为1,,数据在时钟下降沿时切换数据。
 ◐在时钟的第2~8个上升沿(采样点),主机在MISO上采样数据,从机在MOSI上采样数据。
 ◐在时钟的第2~8个下降沿(切换点),主机在MISO上切换数据,从机在MOSI上切换数据。

通过两个单片机模拟SPI来加深理解

利用了STM32F103VET6和STM32F103C8T6(身边只有这两块了)两款MUC。

※硬件连接方式

主机- STM32F103VET6 从机-STM32F103C8T6
(主机产生) SCK→ →SCK(从机被动)
(主机产生) CS→ →CS (从机被动)
(主机发送)MOSI → →MOSI (从机接收)
(主机接收) MISO ← ←MISO (从机发送)

●注意:MOSI连接MOSI,MISO连接MISO(不能像串口那样交叉连接)。

✯SPI模式

采用模式0(CPOL=0,CPHA =0):SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据) ,在SCK的下降沿被切换。

✯程序思路

★主机拉低CS开始传输数据,在SCK上升沿之前保持MOSI上有稳定的数据输出(因为从机要在SCK的上升沿去采样(提取数据),所以主机在SCK上升沿之前要完成发送数据的放置)。
  ★从机在CS拉低后(CS有下降沿)开始数据的接收(在SCK的上升沿采集MOSI上的数据)。

✯主机C代码+波形

/*SPI发送函数*/
//时钟的上升沿采样数据,下降沿切换数据 先发送高位
void SPI_Write(uint8_t Data)
{ 
   
	uint8_t i=0;
	CS_L;	//片选拉低开始传输数据
	/*循环8次,发送8bit数据*/
	for(i=0;i<8;i++)	
	{ 
   
		
		/*切换数据*/
		if(Data&0x80)//通过8次循环移位,将一个字节的数据,由高到低一位一位的放置到数据线上
		{ 
   
			MOSI_H;
		}
		else
		{ 
   
			MOSI_L;
		}
		SCK_L;//产生下降沿,准备切换数据
		delay_us(1);//(可忽略,这里是因为接收时此单片机外部中断上升沿触发有时延,SCK太快无法准确提取数据)
		SCK_H;	//产生上升沿(从机在此上升沿时采集数据)
		Data <<= 1;
		
	}
	MOSI_L;
	SCK_L;
	CS_H;	//片选拉高等待下次数据传输
}
int main()
{ 
   
	int i=0,j=0;
	SysTick_init();
	SPI_GPIO_Config();
	while(1)
	{ 
   
		SPI_Write(0xA5);
	}
}

●注意:上面1us的延时[delay_us(1)]此处可以忽略,这里是因为接收时此单片机外部中断上升沿触发有时延,SCK太快无法准确提取数据,利用其他方式解析从机数据的请忽略。(详细了解请参考博文:STM32外部中断边沿触发存在延时问题)。
  ★代码解析:要了解代码思路,就要时刻记得我们采用SPI的是模式0(SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据),下降沿被切换 ),所以1Byte数据放置完毕后,SCK要拉低,CS要拉高,MOSI要恢复默认电平,但是每Bit数据在SCK拉低时被放置到MOSI数据线(因为SCK上升沿前要确保稳定的数据(因为接收数据最好是在数据的中间采样),这样从机才可以在上升沿采样到正确的数据)。所谓放置数据,其实就是在每次SCK拉高之前对MOSI引脚赋值。比如我们发送的数据为0xA5(1010_0101)。
在这里插入图片描述
在上图中标号2处的下降沿处切换数据,上升沿之前保证了MOSI上(游标1)处有稳定的1bit数据(1),随后的7个上升沿也一样分析。
✯主机产生的波形
在这里插入图片描述)
  ★波形解析:通道1数据:SCK
        通道2数据:MOSI
        通道3数据:CS
   在上图中可以观察到整个数据的传输是在片选CS为低的时刻进行的。在SCK下降沿时主机对MOSI数据线上的数据进行了切换,在SCK上升沿之前完成了1bit数据的发送。完成1Byte数据的发送后,SC置高,CS置高,MOSI置低,为下一帧数据做准备。

✯从机C代码+波形

/*SPI接收数据*/
uint8_t SPI_Read()
{ 
   
	/*CS下降沿*/
	if(CS_Trigger_Falling == 1)
	{ 
   
		CS_Trigger_Falling = 0;
		/*SCK上升沿*/
		for(i=0;i<8;i++)
		{ 
   
			while(SCK_Trigger_Rising != 1);//等待上升沿
			SCK_Trigger_Rising = 0;
			Data_Rec<<=1;
			if(MOSI_State)//在SCK上升沿时提取数据
			{ 
   		
				Data_Rec ++;	
				Rec_Data1[i] = 1;	
			}
			else{ 
   }
		}
	}
	return Data_Rec;
}
int main()
{ 
   
	SysTick_init();
	SPI_GPIO_Config();
	EXTI_PB1_Config();
	EXTI_PA2_Config();
	while(1)
	{ 
   
	Get_Data = SPI_Read();

	}
}
/*外部中断0中断*/
void EXTI1_IRQHandler(void)//中断服务函数
{ 
   
	if(EXTI_GetITStatus(EXTI_Line1) != RESET )//reset为清零(!=reset等价于IT=1)
	{ 
   
	SCK_Trigger_Rising = 1;
	EXTI_ClearITPendingBit(EXTI_Line1);
	}


}
void EXTI2_IRQHandler(void)//中断服务函数
{ 
   
	if(EXTI_GetITStatus(EXTI_Line2) != RESET )//reset为清零(!=reset等价于IT=1)
	{ 
   
	CS_Trigger_Falling = 1;
	EXTI_ClearITPendingBit(EXTI_Line2);
	
	}


}

★代码解析:从机采用了外部中断的方式去采集CS的下降沿和SCK的上升沿(从机以CS下降沿为数据接收的开始,以SCK的上升沿作为每bit数据的采样点)。(★★★有好的方法欢迎指导)
  ●CS下降沿提取波形:图中紫色信号为CS下降沿点。
  在这里插入图片描述
  ●SCK上升沿提取波形:下图中紫色信号为SCK上升沿的提取(即从机接收MOSI数据线上的采样点)。
在这里插入图片描述
  ●提取数据(数据采样):紫色信号处(采样点)MOSI上的数据即为从机接收到的数据,仔细观察采样点几乎在稳定数据的中间点(因为之前所说的边沿检测存在延迟,所以采样点略微偏移中心点,参考链接STM32外部中断边沿触发存在延时问题)。
在这里插入图片描述
✯从机接收数据结果:0xA5
在这里插入图片描述

如有兴趣可查看类似的
IIC协议详解

★★★如有错误欢迎指导。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181500.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • directshow是什么_direction arrow

    directshow是什么_direction arrow3.1DirectShow的功用(1)保证数据量庞大的多媒体数据处理的高效性;(2)时刻保持音频和视频的同步;(3)用简单的方法处理复杂的媒体源问题,包括本地文件,计算机网络,广播电视以及其他数码产品;(4)处理各种各样的媒体格式问题,包括AVI,ASF,MPEG,DV,MOV等;(5)支持目标系统中不可预知的硬件;DirectShow的设计初衷就是尽量要让

    2022年10月12日
    4
  • Windows server 2012 R2 部署WSUS补丁服务[通俗易懂]

    Windows server 2012 R2 部署WSUS补丁服务[通俗易懂]一、WSUS安装要求1、硬件要求:对于多达13000个客户端的服务器,建议使用以下硬件:*4CoreE5-26092.1GHz的处理器*8GB的RAM2、软件要求:要使

    2022年7月2日
    60
  • 手把手教你写上位机软件(c#、winform)

    手把手教你写上位机软件(c#、winform)一、需求分析

    2022年5月6日
    317
  • 静态路由与默认路由的配置_静态路由和默认路由哪个快

    静态路由与默认路由的配置_静态路由和默认路由哪个快原理简述:1。静态路由:是指用户或网络管理员手工配置的路由信息。当网络拓扑结构或链路状态发生改变时,需要网络管理员手工配置静态路由信息。相比较动态路由协议,静态路由无需频繁的交换各自的路由表,配置简单,比较适合小型、简单的网络环境。不适合大型和复杂的网络环境的原因是:当网络拓扑结构和链路状态发生改变时,网络管理员需要做大量的调整,工作量繁重,而且无法感知错误发生,不易排错。2。默认路由…

    2022年9月25日
    4
  • C++滑动窗口算法_最短连续包含子串

    C++滑动窗口算法_最短连续包含子串滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。如下题给你两个长度相同的字符串,s和t。将s中的第i个字符变到t中的第i个字符需要|s[i]-t[i]|的开销(开销可能为0),也就是两个字符的ASCII码值的差的绝对值。用于变更字符串的最大预算是maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。如果你可以将s的子字符串转

    2025年7月10日
    5
  • vs2017当前页面的脚本发生错误_win10当前页面脚本发生错误

    vs2017当前页面的脚本发生错误_win10当前页面脚本发生错误今天使用金山卫士对IE8进行组件升级,此后再此使用VS2008查看项目界面中的控件变量类型,或者添加变量,都弹出“当前页面脚本错误”。在网上进行查找。解决办法如下:1、进入到注册表编辑器。2、按照以下路径“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet  Settings\Zones”查看是否存在

    2022年8月30日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号