STM32-SPI通信协议

串行外设接口SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线。
        在某些芯片上,SPI接口可以配置为支持SPI协议或者支持I2S音频协议。 SPI接口默认工作在SPI方式,可以通过软件把功能从SPI模式切换到I2S模式,具体需参考操作手册
        串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方式通信。此接口可以被配置成主模式,并为外部从设备提供通信时钟(SCK)。接口还能以多主配置方式工作。
它可用于多种用途,包括使用一条双向数据线的双线单工同步传输,还可使用CRC校验的可靠通信。
        I2S也是一种3引脚的同步串行接口通讯协议。它支持四种音频标准,包括飞利浦I2S标准, MSB和LSB对齐标准,以及PCM标准。它在半双工通讯中,可以工作在主和从2种模式下。当它作为主设备时,通过接口向外部的从设备提供时钟信号。

SPI特点

  1. 四根通信线:SCK、MOSI、MISO、SS
  2. 支持全双工同步传输
  3. 支持总线挂载多设备(一主多从)
  4. 支持多主机模型,主或从操作
  5. 支持DMA
  6. 可配置8位/16位数据帧
  7. 时钟频率:f(PCLK)/(2, 4, 8, 16, 32, 64, 128, 256)
  8. 兼容I2S协议等

电路连接

  • 所有SPI设备的SCK、MOSI、MISO、分别连接在一起。
  • 主机另外引出多条SS控制线,分别接到各从机的SS引脚,需要找谁通信就置谁的SS为低电平,同一时间主机只能选择一个从机。
  • 输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入。
  • 所有设备需要共地。

 SPI移位示意图

 SPI时序

起始条件:SS从高电平切换到地点哦

终止条件:SS从低电平切换到高电平

SPI模式

SPI有四种模式通过CPOL时钟极性和CPHA时钟相位来定义

  • CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
  • CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时

  • CPHA=0,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。在第2个边沿发送数据
  • CPHA=1,在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。在第1个边沿发送数据

 软件SPI设置时序单元

数据采样==移入数据

模式0

模式1

模式2
模式3

软件SPI代码

以模式0为例,只需对相位和极性修改即可得到其他模式


//SPI写SS引脚电平
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);//根据BitValue,设置SS引脚的电平
}

//SPI写SCK引脚电平
void MySPI_W_SCK(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);//根据BitValue,设置SCK引脚的电平
}

//SPI写MOSI引脚电平
void MySPI_W_MOSI(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);		
    //根据BitValue,设置MOSI引脚的电平,BitValue要实现非0即1的特性
}

//SPI读MISO引脚电平
uint8_t MySPI_R_MISO(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);			//读取MISO电平并返回
}

//SPI初始化
void MySPI_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//将PA4、PA5和PA7引脚初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
	
	/*设置默认电平*/
	MySPI_W_SS(1);											//SS默认高电平
	MySPI_W_SCK(0);											//SCK默认低电平
}



//SPI起始
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS,开始时序
}

//SPI终止
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS,终止时序
}

//SPI交换传输一个字节,使用SPI模式0
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	uint8_t i, ByteReceive = 0x00;		            
    //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到

	
	for (i = 0; i < 8; i ++)						//循环8次,依次交换每一位数据
	{
		MySPI_W_MOSI(ByteSend & (0x80 >> i));		//使用掩码的方式取出ByteSend的指定一位数据并写入到MOSI线
		MySPI_W_SCK(1);								//拉高SCK,上升沿移出数据
		if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}	//读取MISO数据,并存储到Byte变量
																//当MISO为1时,置变量指定位为1,当MISO为0时,不做处理,指定位为默认的初值0
		MySPI_W_SCK(0);								//拉低SCK,下降沿移入数据
	}
	
	return ByteReceive;								//返回接收到的一个字节数据

//	for(i=0;i<8;i++)
//	{
//		MySPI_W_MOSI(ByteSend & 0x80);
//		ByteSend<<=1;
//		MySPI_W_SCK(1);
//		if(MySPI_R_MISO()==1){ByteSend|=0x01;}
//		MySPI_W_SCK(0);
//	}
//	 return ByteSend;
}

硬件SPI

SPI采用高位先行的模式

SPI框图

数据寄存器DR分为TDR和RDR

1.当需要发送数据时,第一个数据写入TDR,当移位寄存器没有数据进行移位时,TDR数据会立刻转入移位寄存器开始移位。

转入时刻会置状态寄存器的TXE位1,表示发送寄存器空,当检查TXE为1后,下一个数据便可写入TDR等候。

2.移位寄存器检测到有数据也会自动产生时钟将数据移出,在移出的过程中MISO的数据也会移入。

3.一旦数据移出完成,数据移入也完成了,这是移位寄存器就会将数据整体转出到RDR,

这时会置状态寄存器RXNE为1,表示接收寄存器非空。当检测到RXNE为1就需在下一个数据到来之前将数据读出来,不然数据会被覆盖。

SPI时序框图
连续传输

模式三

非连续传输 

硬件SPI代码
 
#include "stm32f10x.h"                  // Device header

//SPI写SS引脚电平,SS仍由软件模拟
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);//根据BitValue,设置SS引脚的电平
}

//SPI初始化
void MySPI_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);	//开启SPI1的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA4引脚初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);				//将PA5和PA7引脚初始化为复用推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
	
	/*SPI初始化*/
	SPI_InitTypeDef SPI_InitStructure;						//定义结构体变量
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;			//模式,选择为SPI主模式
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;	//方向,选择2线全双工
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据宽度,选择为8位
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		//先行位,选择高位先行
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;	//波特率分频,选择128分频
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;				//SPI极性,选择低极性
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;			//SPI相位,选择第一个时钟边沿采样,极性和相位决定选择SPI模式0
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制
	SPI_InitStructure.SPI_CRCPolynomial = 7;			//CRC多项式,暂时用不到,给默认值7
	SPI_Init(SPI1, &SPI_InitStructure);				//将结构体变量交给SPI_Init,配置SPI1
	
	/*SPI使能*/
	SPI_Cmd(SPI1, ENABLE);									//使能SPI1,开始运行
	
	/*设置默认电平*/
	MySPI_W_SS(1);											//SS默认高电平
}

//SPI起始
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS,开始时序
}

//SPI终止
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS,终止时序
}

//SPI交换传输一个字节,使用SPI模式0
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
	
	SPI_I2S_SendData(SPI1, ByteSend);				//写入数据到发送数据寄存器,开始产生时序
	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);//等待接收数据寄存器非空
	
	return SPI_I2S_ReceiveData(SPI1);							//读取接收到的数据并返回
}

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

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

相关文章

【计算机网络】HTTPS 协议原理

https 一、HTTPS 是什么二、加密1. 加密概念2. 加密的原因3. 常见的加密方式&#xff08;1&#xff09;对称加密&#xff08;2&#xff09;非对称加密 三、数据摘要(数据指纹)四、HTTPS 的工作原理探究1. 只使用对称加密2. 只使用非对称加密3. 双方都使用非对称加密4. 非对称加…

java 实现图片新增水印(动态计算水印背景 + 水印文字),附带文字乱码解决方案

文章目录 概要实现流程代码如下小结 概要 图片增加水印背景以及水印文字&#xff0c;根据文字内容是否换行&#xff0c;以及文字行高大小自适应计算背景大小 结果图如下&#xff1a; 实现流程 定义图片来源&#xff0c;以及读取字体来源(防止中文乱码)计算文字所需高度 与…

云上攻防-云原生篇KubernetesK8s安全APIKubelet未授权访问容器执行

知识点 1、云原生-K8s安全-名词架构&各攻击点 2、云原生-K8s安全-Kubelet未授权访问 3、云原生-K8s安全-API Server未授权访问 章节点&#xff1a; 云场景攻防&#xff1a;公有云&#xff0c;私有云&#xff0c;混合云&#xff0c;虚拟化集群&#xff0c;云桌面等 云厂商…

PyInstaller 打包 Python 应用程序一键双击运行

PyInstaller 打包 Python 应用程序一键双击运行 作为一个词语&#xff0c;“活着”在语言里充满了力量&#xff0c;它的力量不是来自于喊叫&#xff0c;也不是来自于进攻&#xff0c;而是忍受&#xff0c;去忍受生命赋予我们的责任&#xff0c;去忍受现实给予我们的幸福和苦难、…

独立游戏《星尘异变》UE5 C++程序开发日志2——创建并编写一个C++类

在本篇日志中&#xff0c;我们将要用一个C类来实现一个游戏内的物品&#xff0c;同时介绍UCLASS、USTRUCT、UPROPERTY的使用 一、创建一个C类 我们在UE5的"内容侧滑菜单"中&#xff0c;在右侧空白中右键选择"新建C类"&#xff0c;然后可以选择一个想要的…

基础二分学习笔记

模板 : 个人倾向第一种 ; 整数二分 : 最大化查找 : 可行区域在左侧 : 查找最后一个<q的数的下标 : int find(int q){// 查找最后一个 < q 的下标 int l 0 , r n 1 ;while(l 1 < r){int mid l r >> 1 ;if(a[mid]<q) l mid ;else r mid ;}return…

【设计模式 01】单例模式

单例模式&#xff0c;是一种创建型设计模式&#xff0c;他的核心思想是保证一个类只有一个实例&#xff08;即&#xff0c;在整个应用程序中&#xff0c;只存在该类的一个实例对象&#xff0c;而不是创建多个相同类型的对象&#xff09;&#xff0c;并提供一个全局访问点来访问…

深入了解 JavaScript 混淆加密和环境检测

JavaScript混淆加密是一种通过修改代码结构和命名约定来增加代码的复杂性&#xff0c;使其难以被理解和逆向工程的技术。在这篇文章中&#xff0c;我们将深入探讨JS混淆加密的一些逻辑&#xff0c;并介绍如何通过环境检测来提高代码的安全性。我们将使用案例代码演示这些概念。…

微信小程序开发学习笔记《18》uni-app框架-网络请求与轮播图

微信小程序开发学习笔记《18》uni-app框架-网络请求 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、下载网络请求包 这个包是以前黑马程序员老师写的一个包&#xff0c;跟着课程学习&#x…

LSTM 长短期记忆递归神经网络

1、神经网络简介 1.1 神经网络起源 人工神经网络&#xff08;Aritificial Neural Networks, ANN&#xff09;是一种仿生的网络结构&#xff0c;起源于对人类大脑的研究。人工神经网络&#xff08;Aritificial Neural Networks&#xff09;也常被简称为神经网络&#xff08;Ne…

考研复试指南

1. 记住&#xff0c;复试的本质不是考试&#xff0c;而是一场自我展示。 考研复试并非简单的知识考察&#xff0c;更是一场展示自我能力和潜力的机会。除了学科知识&#xff0c;考官更关注你的综合素质、学术兴趣和未来发展规划。因此&#xff0c;要保持自信&#xff0c;用更全…

重读 Java 设计模式: 探索经典之道与 Spring 框架的设计

写在开头 记得大学刚毕业那会儿&#xff0c;想学点东西&#xff0c;于是拿出了《Head First 设计模式》这本书&#xff0c;就开始了阅读&#xff0c;我曾对这些模式感到晦涩难懂。然而&#xff0c;随着工作岁月的增长&#xff0c;我逐渐领悟到设计模式的价值&#xff0c;尤其是…

使用 Haproxy 搭建Web群集

Haproxy是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多&#xff0c;如LVS 和Nginx。相比较而言&#xff0c;LVS.牲能最好&#xff0e;但是搭建相对复杂:Nginx的upstream模块支持群集功能&#xff0e;但是对群集节点健康检查功能不强&#xff0c;性能没有…

jupyter 一键快捷启动方法研究

1.效果 首先打开dat 文件&#xff0c;同意赋予管理员 输入序号1 成功启动 2.Bat代码 %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&e…

【网站项目】123网上书城系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Matlab 多项式插值(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于对曲线拟合有些兴趣,这里就找了一些资料从最基本的方法来看一下曲线拟合的效果: 二、实现代码 % **********

后端开发技术面试指南

工作10多年&#xff0c;每年都会帮组里面试一些新同学校招社招的都有&#xff0c;下面我就从一个面试官的视角来给大家拆解一下如何淡然应对后端开发技术面试。 1.一面多为电话面试 (1)问七问八 ①简历要注重内容&#xff0c;形式上不丑没有错别字即可。之前收到过一个工作5…

代码随想录算法训练营第七天

● 自己看到题目的第一想法 第454题.四数相加II 方法&#xff1a; 方法一&#xff1a; 暴力法 思路&#xff1a; 注意&#xff1a; 代码&#xff1a; class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<i…

SpringBlade CVE-2022-27360 export-user SQL 注入漏洞分析

漏洞描述 SpringBlade是一个基于Spring Cloud和Spring Boot的开发框架&#xff0c;旨在简化和加速微服务架构的开发过程。它提供了一系列开箱即用的功能和组件&#xff0c;帮助开发人员快速构建高效可靠的微服务应用。该产品/api/blade-user/export-user接口存在SQL注入。 漏…

探索Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式

目录 前言一、 单机模式二、 伪分布式模式三、 完全分布式模式&#xff08;重点&#xff09;3.1 准备工作3.2 配置集群3.2.1 配置core-site.xml 文件3.2.2 配置hdfs-site.xml 文件3.2.3 配置yarn-site.xml 文件3.2.4 配置mapred-site.xml 文件 3.3 启动集群3.3.1 配置workers3.…