22:SPI一:简单的使用

SPI简单的使用

  • 1、什么是SPI
  • 2、数据通信
    • 2.1:5个重要参数
    • 2.2:4种传输模式
  • 3、程序模拟SPI通信时序
  • 3、片上外设SPI通信时序

1、什么是SPI

SPI是一种同步的,全双工,支持总线挂载多设备的通信协议。它特别适用于高效,快速的传输。

在这里插入图片描述
如上图所示:单片机作为主机,其他模块作为从机。通过SPI总线进行数据通信,而SPI总线如上图结构。SPI由4条线组成:MOSI,MISO,SCK,NSS。

MOSI:主机输出从机输入(主机发送从机接收,发送数据时高位先行),在进行数据传输时,主机的MOSI和所有从机的MOSI连接在一起。
MISO:主机输入从机输出(主机接收从机发送),在进行数据传输时,主机的MISO和所有从机的MISO连接在一起。
SCK:串行时钟线,每个时钟周期发送/接收一个位数据。
NSS:从机选择线,主机和所有从机的NSS连接在一起,低电平有效,主机需要和那一个从机通信就向那个从机的NSS发送低电平即可。

接线如下图所示:

在这里插入图片描述

2、数据通信

在这里插入图片描述
假如主机需要向从机1发送0110 0100的一个字节的数据:
①则主机的NSS1引脚输出一个低电平,其他的NSS引脚输出为高电平。
②主机向数据发送移位寄存器里面写入数据0110 0100。
③然后在SCK的作用下,每来一个脉冲,寄存器的最高位就发送到从机的接收寄存器最高位里面,依次发送8次,那么一个字节就发生完成。
而主机发送数据时,也会接收到从机发送来的数据,这是一个双向的过程。至于接收到的是数据的是什么内容,我们只管主机发送数据即可。而主机需要读取从机的数据时,则需要向从机发送数据,至于发送的数据是是什么内容,我们只管主机读取数据即可
⑤数据发送完成后,主机的NSS1发送一个高电平,用于结束。
在这里插入图片描述

2.1:5个重要参数

①波特率:即SCK时钟的快慢,每一个时钟周期传输一个比特位,波特率越大,传输速率越快。而选择多大的波特率取决于从机允许最大值/设备所承受的极限/电路所承受的极限。
②比特位传输顺序:可以设置一个字节的高位先行,也可以设置为低位先行。例如需要传输数据0110 0100,我们让高位先行,则写入数据寄存器为:0110 0100。我们让低位先行,则写入数据寄存器为:0010 0110。
③数据为的长度:8bit/16bit,一般情况下我们就选择8bit进行传输。
④时钟的极性与边沿
时钟极性为低电压:时钟空闲时为低电平,进行数据传输时才产生脉冲。

在这里插入图片描述

时钟极性为高电压:时钟空闲时为高电平,进行数据传输时才产生脉冲。

在这里插入图片描述时钟的边沿

在这里插入图片描述

⑤时钟相位:数据的传输分为了2个阶段,分别为发送阶段和采集阶段,发送阶段时发送设备向传输线上发送比特位,采集阶段时接收设备采集传输线上的比特位。而时钟的相位分为第1边沿采集和第2边沿采集。

在这里插入图片描述

2.2:4种传输模式

在这里插入图片描述
由上图所示:若为第1边沿进行采集,那么采集的第1个比特位在NSS发送低电平的一瞬间,MOSI引脚就会把比特位瞬间传输到传输线上。

3、程序模拟SPI通信时序

①MySPI.c文件的代码如下:

/*使用代码程序模拟SPI模式0的传输方式*/
#include "stm32f10x.h"                 /** PA4引脚选择从机*/
void MySPI_NSS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}/** PA5引脚模拟时钟信号*/
void MySPI_SCK(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);		
}/** PA7引脚主机发送从机接收*/
void MySPI_Write(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}/** PA6引脚主机接收从机发送*/
uint8_t MySPI_Receive(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}/** 对引脚的初始化,PA4为从机选择引脚,PA5时钟信号引脚,PA6为数据接收引脚* PA7为数据发送引脚。所以PA4,PA5,PA7配置为通用推挽输出,PA6配置为上拉输入*/
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);					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);					/*设置时钟极性为低电压*/MySPI_NSS(1);				//NSS高电平,还没有选择从机MySPI_SCK(0);				//SCK极性为低电平
}/** 起始信号*/
void MySPI_Start(void)
{MySPI_NSS(0);				//拉低NSS,开始时序
}/** 停止信号*/
void MySPI_Stop(void)
{MySPI_NSS(1);				//拉高SS,终止时序
}/** 发送数据和读取数据函数*/
uint8_t MySPI_SengRec_Byte(uint8_t SendByte)
{uint8_t i, Byte = 0x00;//定义接收的数据,并赋初值0x00,for (i = 0; i < 8; i ++)//循环8次,依次交换每一位数据{MySPI_Write(ByteSend & (0x80 >> i));//给传输线上写入数据	MySPI_SCK(1);//拉高SCK,上升沿从机读取数据if (MySPI_Receive() == 1)//读取MISO数据,并存储到Byte变量{Byte |= (0x80 >> i);}											MySPI_SCK(0);//拉低SCK,为下一位数据放入传输线做准备}return Byte;//返回接收到的一个字节数据
}

②主函数程序代码如下:

#include "stm32f10x.h"
#include "MyI2C.h"       int main(void)
{uint8_t Data;MySPI_Init();//SPI的初始化MySPI_Start();Data = MySPI_SengRec_Byte(0xAA);//向从机方式数据0xAA,并接收从机发来的数据保存在Data变量中MySPI_Stop();while(1){}
}

3、片上外设SPI通信时序

在这里插入图片描述
如上图所示:stm32f10c8t6只有2个SPI外设,其中SPI1的外设引脚为PA4~PA7。

相关标准库编程接口如下
在这里插入图片描述
①MySPI.c文件的代码如下:

#include "stm32f10x.h"                  // Device header/** PA4引脚选择从机*/
void MySPI_NSS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);//设置NSS引脚的电平
}/** 对引脚的初始化,PA4为从机选择引脚,PA5时钟信号引脚,PA6为数据接收引脚* PA7为数据发送引脚。所以PA4配置为通用推挽输出,PA5,PA7配置为复用推挽输出,PA6配置为上拉输入*/
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;        //将PA4引脚初始化为推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;  //将PA5和PA7引脚初始化为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           //将PA6引脚初始化为上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					/*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模式0SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式,暂时用不到,给默认值7SPI_Init(SPI1, &SPI_InitStructure);						//将结构体变量交给SPI_Init,配置SPI1SPI_Cmd(SPI1, ENABLE);									//使能SPI1,开始运行MySPI_NSS(1);											//SS默认高电平
}/** 起始信号*/
void MySPI_Start(void)
{MySPI_NSS(0);				//拉低NSS,开始时序
}/** 停止信号*/
void MySPI_Stop(void)
{MySPI_NSS(1);				//拉高SS,终止时序
}/** 发送数据和读取数据函数*/
uint8_t MySPI_SengRec_Byte(uint8_t SendByte)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空,写入数据自动清除SPI_I2S_SendData(SPI1, SendByte);								//写入数据到发送数据寄存器,开始产生时序while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空,读取数据自动清除return SPI_I2S_ReceiveData(SPI1);								//读取接收到的数据并返回
}

②主函数程序代码如下:

#include "stm32f10x.h"
#include "MyI2C.h"       int main(void)
{uint8_t Data;MySPI_Init();//SPI的初始化MySPI_Start();Data = MySPI_SengRec_Byte(0xAA);//向从机方式数据0xAA,并接收从机发来的数据保存在Data变量中MySPI_Stop();while(1){}
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

激光粉尘传感器:筑牢粮仓安全防线,有效应对粮食粉尘爆炸高危风险

随着我国农业的持续发展和粮食产量的稳步提升&#xff0c;2023年全国粮食总产量达到了13908.2亿斤&#xff0c;这一丰硕成果不仅保障了国家的粮食安全&#xff0c;也对粮食的储备、加工、运输等环节提出了更高的要求。然而&#xff0c;在粮食产业链的各个环节中&#xff0c;粮食…

11_Python函数基本概念和示例

函数 函数是组织代码、提高代码复用性的基本工具。一个函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段。函数类型&#xff1a;内置函数、自定义函数 定义函数 在 Python 中&#xff0c;使用 def 关键字来定义一个函数。 函数可以有参数&#xff0c;也可以…

虚拟背景扣像SDK解决方案,电影级抠像技术

美摄科技&#xff0c;作为影像技术领域的领航者&#xff0c;凭借其革命性的虚拟背景抠像SDK解决方案&#xff0c;正以前所未有的方式&#xff0c;重新定义电影级背景抠像技术&#xff0c;让直播与视频制作迈入全新境界。 电影级抠像技术&#xff0c;重塑视觉盛宴 美摄科技的虚…

Appium环境搭建及元素定位

Appium是一个开源测试自动化框架&#xff0c;可用于原生&#xff0c;混合和移动Web应用程序测试。它使用WebDriver 协议驱动iOS&#xff0c;Android和Windows应用程序。 01 环境搭建步骤 Appium环境安装&#xff1a; 第一步安装 appium 桌面版客户端 Appium-1.12.1.dmg(MAC…

比亚迪高歌猛进背后,高端市场攻坚与出海风险并存

比亚迪高速扩张的繁荣表象之下&#xff0c;仍遭遇高端市场挑战&#xff0c;全球化征程面临可持续性考验。 转载&#xff1a;科技新知 原创 作者丨颜曌 编辑丨蕨影 比亚迪的发展史&#xff0c;堪称我国新能源汽车品牌的缩影。如今在全球新能源市场越来越有影响力的比亚迪&…

自动化测试需要学什么【附学习路线和学习教程】

随着自动化测试行业的薪酬越来越高&#xff0c;平均月薪早在很多年前就已破万&#xff0c;也有越来越多的人愿意投身测试行业&#xff0c;成为一名测试工程师&#xff0c;这些人当中也有相当多的一部分是测试行业的小白&#xff0c;并不知道自动化测试需要学习哪些内容 在放上…

第二届Apache Flink极客挑战赛冠军比赛攻略_SkyPeaceLL队

关联比赛: 第二届 Apache Flink极客挑战赛 赛题介绍 指定的数据集一、病例行动数据集 病例历史行动数据集&#xff08;训练集1&#xff09; 1M确诊病例数据 &#xff08;测试集1&#xff09; 500实时病例行动数据集&#xff08;测试集2&#xff09; 1000二、天猫精灵行为数据…

【服务集成】最新版 | 阿里云OSS对象存储服务使用教程(包含OSS工具类优化、自定义阿里云OSS服务starter)

文章目录 一、阿里云OSS对象存储服务介绍二、服务开通与使用准备1、准备工作2、开通OSS云服务&#xff08;新用户免费使用三个月&#xff09;3、创建存储空间bucket4、创建并保存Accesskey5、配置访问凭证AK & SK&#xff08;系统环境变量&#xff09; 三、阿里云OSS使用步…

codemirror 代码在线编辑器基本使用

CodeMirror 是一个强大的基于浏览器的文本编辑器组件&#xff0c;主要用于网页中创建可编辑的源代码区域&#xff0c;特别适用于编写和展示程序代码。它支持多种编程语言的语法高亮、代码折叠、自动补全、查找替换等多种高级编辑特性。 npm install vue-codemirror --save 或者…

张恒汝的个人简介:招生宣传用

张恒汝&#xff0c;男&#xff0c;九三学社社员&#xff0c;博士&#xff0c;教授&#xff0c;硕士生导师&#xff0c;机器学习研究中心副主任&#xff0c;四川省学术和技术带头人后备人选&#xff0c;中国科协科技人才奖项评审专家&#xff0c;四川省网络安全与信息化技术专家…

HarmonyOS开发实战( Beta5.0)使用GTest测试C++案例

鸿蒙HarmonyOS开发往期必看&#xff1a; HarmonyOS NEXT应用开发性能实践总结 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; 介绍 本示例主要介绍如何在HarmonyOS NEXT应用中使用GTest测试…

基于Java的学生档案管理系统的设计与实现

基于springbootvue实现的学生档案管理系统 &#xff08;源码L文ppt&#xff09;4-065 第4章 系统设计 4.1 总体功能设计 学生档案管理系统的总体功能设计包括学生信息管理、课程管理、教师信息管理、成绩管理和系统配置管理。系统将提供用户友好的界面&#xff0c;支…

Cpp类和对象(上)(3)

文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言…

天池Fashion AI 比赛失败经历分享

关联比赛: FashionAI全球挑战赛—服饰关键点定位 昨天是天池Fashion AI初赛Deadline&#xff0c; 成绩出来复赛都没能进&#xff0c;虽然结果很遗憾&#xff0c;但在比赛的过程中也接触到了不少的新东西&#xff0c;希望能在这里把我尝试过的方法都分享出来。作为对自己的总结…

EPLAN中如何切换编辑区的背景颜色为黑色?

EPLAN中如何切换编辑区的背景颜色为黑色&#xff1f; 如下图所示&#xff0c;打开EPLAN软件&#xff0c;打开或新建一个项目&#xff0c; 如下图所示&#xff0c;点击选项----设置&#xff0c; 在弹出的窗口中找到用户----图形的编辑------2D&#xff0c;在右侧找到颜色设置---…

便携式气象监测站的工作原理

型号&#xff1a;TH-BQX9】便携式气象环境监测站是一种集数据采集、处理、传输于一体的便携式设备&#xff0c;主要用于实时、准确地监测环境中的多种气象要素。便携式气象环境监测站通常能够监测多种气象参数&#xff0c;包括但不限于温度、湿度、风速、风向、气压、降雨量、太…

Java虚拟机 - 实战篇

一、内存调优 1. 什么是内存泄漏 &#xff08;1&#xff09;内存溢出和内存泄漏 2. 监控Java内存的常用工具 &#xff08;1&#xff09;Top命令 &#xff08;2&#xff09;VisualVM &#xff08;3&#xff09;Arthas &#xff08;4&#xff09;Prometheus Grafana &#xff…

【C++STL简介】——我与C++的不解之缘(八)

前言 学过了C的模版&#xff0c;接下来学习C中的STL&#xff08;标准模版库&#xff09;&#xff0c;先来了解一下STL是啥 一、什么是STL STL&#xff08;standard template libaray 标准模版库&#xff09;&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的…

cmake的下载与安装

介绍&#xff1a; CMake是一个跨平台的安装&#xff08;编译&#xff09;工具&#xff0c;可以用简单的语句来描述所有平台的安装(编译过程)。 能够输出各种各样的makefile或者project文件&#xff0c;能测试编译器所支持的C特性,类似UNIX下的automake。 CMake 的组态档取名为…

[Java]SpringBoot能力进阶

配置优先级 SpringBoot中支持三种格式的配置文件 优先级: application.properties文件 > application.yml文件 > application.yaml文件 SpringBoot除了通过配置文件配置属性, 还支持Java系统属性和命令行参数的方式 进行属性配置 1.在IDEA中配置java系统属性和命令行参…