SPI通信时序

前言:

        作为Motorola的又一伟大发明的SPI总线通信协议,在理解和应用上也是十分复杂且难以理解,博主想通过这篇文章想把SPI的原理和应用大概讲一下,同时也是记录自己对于I2C的学习和理解。

SPI概述:

        SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。

     SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI信号线:

SCK:主机的时钟线,由主机产生脉冲,一个脉冲传输、接收一位数据,另名:C  SCL  SCLK

CS:使能控制端(主机控制从机),选定哪个从机可以工作,当有多个从机连接主机的SPI总线时,从机的CS分别连接主机的不同引脚,主机通过控制引脚输出低电平(通常是低电平)来选中指定从机进行通信,输出高电平来结束或者不选中从机通信。

MOSI:Master Output Slave Input,主机输出,从机输入

MISO:Master Input Slave Output, 主机输入,从机输出

这里我们重点讲一下这张图,在SPI中,这里我们考虑一主多从模式,当连接在主机上的从机的CS输出低电平时,从机被选中指定与主机进行SPI通信。

主机的SCLK每发出一个脉冲,主机的移位寄存器高位移出一位数据,(高位先行,SPI通常是高位先行),通过MOSI线移位数据到从机的移位寄存器低位,同时,从机的移位寄存器高位移位一位数据,通过MISO线移位到主机的移位寄存器的低位,这样主从机的一位数据就交换完成。

如此往复八次脉冲,主机和从机的移位寄存器的八位数据就成功交换。

SPI工作原理总结:

硬件上为4根线:SCLK(传输脉冲),CS(片选使能线),MISO(主机输入,从机输出端线),MOSI(主机输出,从机输出端线)

主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。

串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。

外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字符(任意字符)节来引发从机的传输。

SPI四种工作方式:

        SPI有四种工作方式,根据输出串行同步时钟极性CPOL和相位CPHA进行选择工作方式,具体可通过从机设备的手册查找从机的SPI工作方式为哪种。

  时钟极性选择CPOL:为0时SPI总线空闲为低电平,时钟线工作开始电平为低电平;为1时SPI总线空闲为高电平,时钟线工作开始电平为高电平;

        时钟相位选择CPHA,为0时在SCK输出脉冲的第一个跳变沿采样,为1时在SCK输出脉冲的第二个跳变沿采样。

时钟极性CPOL为0时,SPI总线空闲电平即SPI开始电平为低电平,

时钟极性CPOL为1时,SPI总线空闲电平即SPI开始电平为高电平。

CPHA时钟相位为0时,在SCK第一个跳变沿采样,

CPHA时钟相位为1时,在SCK第二个跳变沿采样。

SPI工作方式0:

CPOL=0,CPHA=0,SPI总线工作方式为工作方式0,SCK空闲电平即开始电平为低电平,主机的MISO在SCK时钟线的上升沿进行采样,MOSI在SCK的下降沿把数据发送出去。

SPI工作方式1:

CPOL=1,CPHA=0,SPI总线工作方式为工作方式1,SCK空闲电平即开始电平为高电平,主机的MISO在SCK时钟线的下降沿进行采样,MOSI在SCK的上升沿把数据发送出去。

SPI工作方式2:

CPOL=0,CPHA=1,SPI总线工作方式为工作方式2,SCK空闲电平即开始电平为低电平,主机的MISO在SCK时钟线的下降沿进行采样,MOSI在SCK的上升沿把数据发送出去。

SPI工作方式3:

CPOL=1,CPHA=1,SPI总线工作方式为工作方式3,SCK空闲电平即开始电平为高电平,主机的MISO在SCK时钟线的上升沿进行采样,MOSI在SCK的下降沿把数据发送出去。

SPI软件实现:(STM32F407主机和Flash从机)

接线:

从设备(这里指SPI串行Flash)的F_CS接到STMF407的F_CS使能端,低电平有效,SO(从设备SPI输出引脚)接到主机的SPI1_MISO输入引脚,SI(从设备SPI输入引脚)接到主机的SPI1_MOSI引脚,CLK(从设备时钟线)接到主机的SPI1_SCK时钟线。

代码思路:

(1)使能SPIx和IO口时钟

    RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd();

(2)初始化IO口为复用功能

    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

(3)设置引脚复用映射:

    GPIO_PinAFConfig();

(4)初始化SPIx,设置SPIx工作模式

    void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

(5)使能SPIx

    void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

(6)SPI传输数据

    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

    uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;

(7)查看SPI传输状态

   SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);

SPIFlash.c:

#include "spiflash.h"

/*********************************
引脚说明

使用SPI1
SCK连接PB3
MISO连接PB4
MOSI连接PB5
CS连接PB14


**********************************/
void Spiflash_Init(void)
{

	
	GPIO_InitTypeDef 	GPIO_InitStructure;
	SPI_InitTypeDef		SPI_InitStruct;
	//使能SPIx和IO口时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
	
	
	//GPIO 初始化设置:要设置模式为复用功能。
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;  	//引脚3 4 5
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;	//复用模式 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;	//速度 
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;		//推挽输出
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP ;		//上拉
	//初始化IO口为复用功能
	GPIO_Init(GPIOB, &GPIO_InitStructure); 	
	
	
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_14;  		//引脚14
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;		//输出模式 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;	//速度 
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;		//推挽输出
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP ;		//上拉
	//初始化IO口为复用功能
	GPIO_Init(GPIOB, &GPIO_InitStructure); 	
		
	
	//设置引脚复用映射:
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);


	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //84/4 = 21MHZ
	//工作方式0
	SPI_InitStruct.SPI_CPHA 	= SPI_CPHA_1Edge;
	SPI_InitStruct.SPI_CPOL 	= SPI_CPOL_Low;
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; //字长:1字节
	SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex; //全双工
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //先发高位
	SPI_InitStruct.SPI_Mode     = SPI_Mode_Master;  //主机
	SPI_InitStruct.SPI_NSS		= SPI_NSS_Soft;    //软件控制
	SPI_InitStruct.SPI_CRCPolynomial = 7;   //CRC校验

	//初始化SPIx,设置SPIx工作模式
    SPI_Init(SPI1, &SPI_InitStruct);
	
	//使能SPIx
	SPI_Cmd( SPI1, ENABLE);
	
	//不使能芯片
	F_CS = 1;

}


u8 Spi1_Send_Recv_Byte(u8 txdata)
{
	u8 rxdata = 0x00;
	
	//查找是否满足发送条件
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == 0);
	//缓冲区为空,发送数据
	SPI_I2S_SendData(SPI1, txdata);
	
	
	//查找是否满足接受条件
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == 0);
	//缓冲区为非空,接受数据
	rxdata = SPI_I2S_ReceiveData(SPI1);
	
	return rxdata;
	
	
}

u16 W25q128_id(void)
{
	u16 id = 0x00;
	
	//使能芯片
	F_CS = 0;	
	
	//发送读生产商与设备ID命令
	Spi1_Send_Recv_Byte(0x90);
	
	//地址拆分,发送地址
	Spi1_Send_Recv_Byte(0x00);
	Spi1_Send_Recv_Byte(0x00);
	Spi1_Send_Recv_Byte(0x00);
	
	//主机发送任意字节,得到从机的数据
	id |= Spi1_Send_Recv_Byte(0xFF)<<8; //生产商ID存储在高八位
	id |= Spi1_Send_Recv_Byte(0x66);    //设备ID存储在低八位


	//不使能芯片
	F_CS = 1;	
	
	return id;
}

SPIFlash.h:

#ifndef __SPIFLASH_H
#define __SPIFLASH_H



#include "stm32f4xx.h"
#include "sys.h"
#include "delay.h"



#define F_CS  PBout(14)
#define SCK		PBout(3)
#define MOSI	PBout(5)
#define MISO	PBin(4)


void Spiflash_Init(void);
u16 W25q128_id(void);

void Erase_Sector(u32 addr);
void Page_Write(u32 addr, u8 *write_buff, u32 len);
void Read_Data(u32 addr, u8 *read_buff, u32 len);

#endif

结语:

        感谢您能读到这里,希望通过这篇博客能解答您心中关于SPI的疑惑!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/892170.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言复习专题】函数调用

【C语言复习专题】函数调用 1.递归是什么&#xff1f;1.1递归的思想&#xff1a;1.2递归的限制条件 2.递归举例2.1eg1&#xff1a;求n的阶乘2.1.1 分析和代码实现2.1.2作图演示过程 2.2 eg2&#xff1a;顺序打印一个整数的每一位2.2.1分析 3.递归与迭代 1.递归是什么&#xff1…

2-124 基于matlab得结构稀疏字典实现SAR图像低秩重建

基于matlab得结构稀疏字典实现SAR图像低秩重建&#xff0c;通过K-SVD和W-KSVD结合OMP进行重建。K-SVD算法是一种字典学习算法&#xff0c;能够对字典进行优化&#xff0c;使其能够更好地表示训练样本集。W-KSVD算法是K-SVD算法的扩展&#xff0c;它能够利用权重信息对字典进行优…

华为---Super VLAN简介及示例配置

目录 1. Super VLAN技术产生背景 2. Super VLAN概念 3. Super VLAN应用场景 4. Super VLAN工作原理 5. Super-VLAN主要配置命令 6. Super-VLAN主要配置步骤 7. 示例配置 7.1 示例场景 7.2 网络拓扑 7.3 配置代码 7.4 代码解析 7.5 测试验证 1. Super VLAN技术产生背…

【开源免费】基于SpringBoot+Vue.JS房屋租赁系统(JAVA毕业设计)

本文项目编号 T 020 &#xff0c;文末自助获取源码 \color{red}{T020&#xff0c;文末自助获取源码} T020&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

ubuntu20.4环境下gcc-aarch64交叉编译器的安装

交叉编译器&#xff08;Linux环境&#xff09;arm gcc 8.3一共有5个版本&#xff0c;常用的有4个版本&#xff08;另外一个为大端linux版本&#xff09;&#xff0c;分别是32bit裸机版本&#xff08;arm-eabi&#xff09;、64bit裸机版本&#xff08;aarch64-elf&#xff09;、…

2015年-2016年 软件工程程序设计题(算法题)实战_c语言程序设计数据结构程序设计分析

文章目录 2015年1.c语言程序设计部分2.数据结构程序设计部分 2016年1.c语言程序设计部分2.数据结构程序设计部分 2015年 1.c语言程序设计部分 1.从一组数据中选择最大的和最小的输出。 void print_maxandmin(double a[],int length) //在一组数据中选择最大的或者最小的输出…

EM算法学习

1.EM算法的介绍 可以发现&#xff1a;计算出θA和θB的值的前提是知道A、B币种的抛掷情况。 所以我们需要使用EM算法&#xff1a;求出每轮选择硬币种类的概率 2.EM算法执行过程&#xff1a; 第一步&#xff1a;首先初始化设置一组PA和PB证明的值。然后通过最大似然估计得到每…

2024软考网络工程师笔记 - 第3章.广域通信网

文章目录 广域网物理层特性1️⃣公共交换电话网 PSTN2️⃣本地回路3️⃣机械特性4️⃣电气特性 &#x1f551;流量与差错控制1️⃣流量与差错控制2️⃣流量控制——亭等协议3️⃣流控机制——滑动窗口协议4️⃣差错控制5️⃣差错控制——停等协议6️⃣差错控制——选择重发ARQ协…

MySQL【知识改变命运】08

数据库约束 1&#xff1a;约束的几个类型2&#xff1a;NOT NULL非空约束3&#xff1a;UNIQUE 唯⼀约束4&#xff1a;PRIMARY KEY 主键约束4.1:回顾 5&#xff1a;FOREIGN KEY 外键约束5.1&#xff1a;创建班级表(主表)&#xff0c;并初始化数据5.2&#xff1a;重构学⽣表(从表)…

【Golang】Go语言http编程底层逻辑实现原理与实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Docker 拉取镜像时配置可用镜像源(包含国内可用镜像源)

文章目录 写在前面一、Docker 官方源二、更换Docker 国内可用镜像源 &#xff08;推荐使用&#xff09;参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04&#xff0c;docker-27.3.1 一、Docker 官方源 打开 /etc/docker/daemon.json文件&#xff1a; sudo gedit …

STM32F4- SD卡和 FATFS文件系统

单片机系统常需大容量存储设备&#xff0c;如U盘、FLASH芯片、SD卡等。 其中&#xff0c;SD卡因容量大、支持SPI/SDIO驱动、尺寸多样&#xff0c;成为单片机系统的优选。 STM32F4开发板自带SD卡接口&#xff0c;使用SDIO接口驱动&#xff0c;支持高速数据传输。 1.1 SDIO 简介…

JavaWeb学习(1)

目录 一、什么是JavaWeb 二、静态web和动态web 三、Web服务器&#xff08;Tomcat&#xff09; 四、Http 4.1 是什么 4.2 两个时代 4.3 Http请求 4.4 Http响应 五、Maven 六、Servlet 七、HttpServletResponse 7.1 常见应用 7.1.1 向浏览器输出消息 7.1.2 下载文件 …

为您的人工智能数据提供类似 Git 的版本管理功能

您过去肯定有过版本控制代码。但是&#xff0c;您是否对数据进行了版本控制&#xff1f;您是否曾经想过与不同的团队协作处理大量数据&#xff0c;而无需提交大量数据&#xff1f;想象一下&#xff0c;使用类似 git 的命令来运行类似存储库的生态系统&#xff0c;在该生态系统中…

Unity实现自定义图集(三)

以下内容是根据Unity 2020.1.0f1版本进行编写的   1、实现编辑器模式下进游戏前Pack全部自定义图集 同Unity的图集一样,Unity的编辑器模式会在进游戏前把全部的SpriteAtlas都打一次图集,如图: 我们也实现这样的效果。 首先需要获取全部的图集路径。因为目前使用的是以.…

RISC-V笔记——RVWMO基本体

1. 前言 RISC-V使用的内存模型是RVWMO(RISC-V Weak Memory Ordering)&#xff0c;它是Release Consistency的扩展&#xff0c;因此&#xff0c;RVWMO的基本特性类似于RC模型。 2. RC模型 Release consistency(RC)的提出是基于一个观察&#xff1a;将所有同步操作用FENCE围在一…

全国职业技能大赛——信息安全管理与评估第一阶段BC、FW、WAF题目详细解析过程

💗需要职业技能大赛环境+WP,请联系我!🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 一个想当文人的黑客 ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【edusrc漏洞挖掘】 【VulnHub靶场复现】【面试分析】 🎉欢迎关注💗一起学习👍一起讨论⭐️一起…

【WPF】中ListBox的ListBox选项的选中状态在弹出MessageBox后失效的解决办法

1.问题描述 1.1 ListBox选项的样式 在WPF中&#xff0c;可以通过定义ListBoxItem的样式来改变ListBox选项的选中状态。这通常涉及到使用ControlTemplate和Trigger来指定当ListBoxItem处于不同状态时&#xff08;如被选中、鼠标悬停等&#xff09;的外观。ListBoxItem设置不同…

TikTok零播放的原因及解决方法

TikTok作为一个月活跃用户数已经超过15亿的社媒平台&#xff0c;巨大的流量不断吸引着用户加入&#xff0c;其中不乏需要推广获客的卖家。在运营推广工作中&#xff0c;视频播放量是重要的评估维度&#xff0c;如果出现零播放的情况&#xff0c;需要卖家找出原因并尽快解决。 一…

『Mysql集群』Mysql高可用集群之主从复制 (一)

Mysql主从复制模式 主从复制有一主一从、主主复制、一主多从、多主一从等多种模式. 我们可以根据它们的优缺点选择适合自身企业情况的主从复制模式进行搭建 . 一主一从 主主复制 (互为主从模式): 实现Mysql多活部署 一主多从: 提高整个集群的读能力 多主一从: 提高整个集群的…