零死角玩转stm32中级篇3-SPI总线

news2024/11/15 22:26:36

一.基础知识

1.什么是SPI

SPI(Serial Peripheral Interface,串行外设接口)是一种同步的串行通信协议,它被用于在微控制器、存储器芯片、传感器和其他外围设备之间传输数据。SPI通常由四个线组成:时钟线(SCK)、主设备输出/从设备输入(MOSI)、从设备输出/主设备输入(MISO)和片选线(SS)。SPI通信中,数据在时钟的边沿上进行传输,以实现高速、可靠的数据传输。SPI可以支持单主机和多从机的连接方式,并且具有简单、灵活和可扩展的特点。

(主从连接方式1:一个主机上有多个SS片选信号去连接从机,如下图)
在这里插入图片描述

(主从连接方式2:一个主机上只有一个片选信号可以通过daisy-chained(菊花链)进行连接,如下图)

在这里插入图片描述

备注:图片来源于https://www.circuitbasics.com/basics-of-the-spi-communication-protocol/。

2.SPI和IIC有什么不同

SPI和I2C(Inter-Integrated Circuit,即IIC)都是常见的串行通信协议,它们在一些方面有所不同:

  1. 总线结构:SPI是点对点的结构,每个设备占用一个片选线;而I2C是多主从结构,允许多个设备通过两根共享的线路进行通信。

  2. 传输速率:SPI的传输速率通常比I2C更快,SPI可以达到几百MHz的传输速率,而I2C通常只能达到几十kHz或几百kHz的传输速率。

  3. 电气特性:SPI时钟线和数据线的电平是由驱动器控制的,因此SPI的电气特性更容易控制和优化,而且SPI在长距离传输时噪声抗干扰能力更强;而I2C的时钟和数据线由开漏输出控制,需要加上外部上拉电阻,电气特性控制相对较难。

  4. 硬件资源:SPI传输需要占用多个GPIO,因此需要更多的硬件资源来实现;而I2C只需要两个GPIO,可以减少芯片上的硬件资源占用。

总之,SPI和I2C都有其适用的场景。SPI适用于高速、简单的点对点通信,而I2C适用于多设备的通信,因为I2C允许多个设备在同一个总线上进行通信。

3.SPI的优缺点

优点:

  • 没有启动和停止位,所以数据可以不间断地连续流
  • 没有像 I2C 这样复杂的从站寻址系统
  • 数据传输速率比 I2C 高(几乎是 I2C 的两倍)
  • 单独的MISO 和 MOSI 线路,这样数据可以同时发送和接收

缺点:

  • 使用四根线(I2C 和 UART 使用两根)
  • 没有确认数据已经成功接收(I2C 有这个)
  • 没有像 UART 中奇偶校验位那样的错误检查形式
  • 只允许一个master

4.SPI是怎么实现通信的

① 在SPI通信中,数据是通过一个主设备与一个或多个从设备进行的。通信的过程是主设备向从设备发送数据,并且同时接收从设备发回的数据。SPI总线由四个信号线构成,分别是:

  1. SCLK(Serial Clock):时钟线,用于同步主从设备之间的数据传输。

  2. MOSI(Master Out Slave In):主设备输出数据到从设备的信号线。

  3. MISO(Master In Slave Out):从设备输出数据到主设备的信号线。

  4. SS(Slave Select):从设备的选中信号线,用于让主设备控制从设备的选择。

② 简单来说,当主设备需要跟某个从设备通信时,它会先把该从设备的SS线拉低(低电平有效还是高电平有效要根据元件的数据手册来看),表示选中该从设备,然后主设备以时钟信号为基准,通过MOSI线发送数据,从设备则通过MISO线将响应数据发回主设备。通信结束后,主设备会将该从设备的SS线拉高,表示不再选中该从设备。
③ SPI通信的速度可以通过调整时钟频率来实现,而具体的通信协议和数据格式则需要根据具体的应用场景来确定。

5.SPI 数据传输的步骤

  • 主机(master)输出时钟信号

在这里插入图片描述

  • 主机(master)将对应从机(方式一)的片选信号切换到低电平,从而激活对应从机

在这里插入图片描述

  • 主机(master)通过MOSI线向从设备一次一位地向从机发送数据,从设备读取接收到的数据

在这里插入图片描述

  • 如果从设备有相应的回应,从设备通过MISO线向主设备一次一位地向主机发送数据,主设备读取接收到的数据

在这里插入图片描述

6.SPI菊花链

在SPI菊花链方式中,各个从机的MISO(Master In Slave Out)输入都连接到前一个从机的MOSI(Master Out Slave In)输出上,一直到链的最后一个从机(如下图所示)。主机通过片选信号来选择与其通讯的从机,只有被选中的从机的MISO输出的数据才会被主机的MOSI输入。

在这里插入图片描述
备注:图片来源于https://zhuanlan.zhihu.com/p/290620901

具体的连接图如下:

在这里插入图片描述

SPI菊花链方式通信的基本步骤:

  • 主机发送片选信号(CS)来选择要与之通讯的从机。

  • 在所选从机的MISO输入处放置数据,同时主机在MOSI输出口发送相应的数据。

  • 当所选从机选定数据并将其内容从MISO输出时,主机也会将其内容从它的MISO输入口中读取,完整的数据交换完成。

  • 当主机需要与另一个从机通讯时,它会将片选信号切换到下一个从机上,然后重复上述步骤。

  • 当通讯完成时,主机可以停止发送片选信号。

需要注意的是,在SPI菊花链方式中,所有从机的MISO都连接在同一条线上。在未选中的情况下,从机将忽略主机发出的数据。因此,在设计SPI系统时需要确保未选中的从机在通讯期间处于高阻状态,以避免因为信号冲突而产生干扰。

  • 上文说所的未选中

① SPI菊花链中,所有从机都与同一条MISO线相连,但是在不同时间内只会有一个从机处于被选中状态,其他从机都处于未选中状态。这是通过从机的片选信号(CS)来实现的。当主机选择与某个从机通信时,它会向该从机的CS引脚发送低电平信号,从而告诉该从机它正在被选中。其他未被选中的从机,它们未选中时CS引脚通常为高电平状态,并且未选中的从机的MISO输出需要设置为高阻状态。
② 因此,在SPI菊花链方式中,需要确保未被选中的从机在通讯期间处于高阻状态,以避免干扰。最好的做法是在主机与某个从机通信之前,先将所有其他未选中的从机的片选信号拉高,保证它们的MISO输出都处于高阻状态。这样可以减少通信期间出现干扰的可能性。

  • 什么是高阻态

① 高阻状态是指一个电路中的输入端或输出端等待输入或输出信号时,它处于一种电气状态,该状态被称作高阻态或三态,简称"Z"态。处于高阻态的信号线会表现出一种很高的电阻,阻止其他电路对其进行电流或电压的驱动,这样可以保证电路的安全和稳定性。
② 在数字电路中,高阻态被广泛应用于多路复用器、锁存器和开关等电路中。例如,在多路复用器中,当选择器控制线不代表选中任何一个输入端口时,所有的输入端口都处于高阻状态,以避免输入端口之间的干扰。在锁存器中,当时钟信号处于非稳定状态时,输入端口处于高阻态,以避免输出端脱离预期状态。在开关中,当输出端口未被激活时,它处于高阻状态,以防止从该端口流出意外的电流引起不必要的能量损耗。

在这里插入图片描述

7.通过SPI实现数据的读和写

通过SPI协议进行数据的读写操作和其他通信协议(UART,IIC)一样也会有相应的数据格式,下面给出是93C46存储器的SPI数据读写的格式(具体的读写的数据各式可以通过数据手册进行获取)。

在这里插入图片描述

和异步不同的是,数据的发送会受到时钟线的控制,如下,就是当SS(片选线)为高电平时,进行数据的读写操作,从机采样数据由极性和相位决定,极性决定时钟SCK空闲时是高电平还是低电平,相位决定在第一个跳边沿还是第二个跳边沿进行数据采集,下图就是极性为低电平,相位为第一个跳边沿(低->高)进行数据采集,采集MOSI上的数据,从机采集到了1 01 0000001 0000 1111的数据,再进行解析,数据解析的结果表示将进行写数据,向000 0001地址写入数据0000 1111。

在这里插入图片描述

① SPI数据采样是由SPI总线信号的时钟极性和相位来决定的。通常情况下,SPI信号是由主设备(如微控制器)发出的,从设备(如传感器或存储器)则根据时钟信号进行响应。使用SPI时,必须确保主设备与从设备使用相同的时钟极性和相位,以确保数据采样的正确性。
② SPI采样方式有四种:mode0、mode1、mode2和mode3。下面分别介绍各种采样方式的时钟极性和相位:

  1. mode0:时钟极性为0,时钟相位为0。时钟极性为0表示空闲时时钟处于低电平,采样时时钟沿上升。时钟相位为0表示数据采样在时钟的上升沿进行,数据产生在下降沿。mode0是最常用的采样方式。

  2. mode1:时钟极性为0,时钟相位为1。时钟相位为1表示数据采样在时钟的下降沿进行,数据产生在上升沿。

  3. mode2:时钟极性为1,时钟相位为0。时钟极性为1表示空闲时时钟处于高电平,采样时时钟沿下降。时钟相位为0表示数据采样在时钟的下降沿进行,数据产生在上升沿。

  4. mode3:时钟极性为1,时钟相位为1。时钟相位为1表示数据采样在时钟的上升沿进行,数据产生在下降沿。

上面的解析可能不容易进行理解,大致意思就是SPI由极性和相位决定,极性和相位有二种取值即0和1,这样一共就由4种采集方式(00 01 10 11),其中当极性为0时表示时钟空闲状态为低电平(第一个跳变为上升沿),为1表示时钟空闲状态为高电平(第一个跳变为下降沿);而相位为0表示在第一个跳边沿进行数据采集,为1时表示在第二个跳边沿进行数据采集。下图中的图1的CPOL表示极性;图2CPHA表示相位;这二张图片来源于https://www.cnblogs.com/gmpy/p/12461461.html。

(图1)
在这里插入图片描述

(图2)
在这里插入图片描述

具体的四种采样方式如下图所示:

在这里插入图片描述

至于数据的读取,主机先通过MOSI向从机发送读取的操作指令(1 10 地址),然后就可以通过MISO,从从机上面采集到对应的数据。

在这里插入图片描述
在这里插入图片描述

备注上图的图片和表格来源于:https://www.bilibili.com/video/BV1F54y1M7e7/

二.STM32F103C8T6芯片SPI协议案例代码

以下是一个基于STM32F103C8T6单片机的SPI协议案例代码,仅供参考(来源于ChartGPT):




#include "stm32f10x.h"

#define SPI_SCK_PIN  GPIO_Pin_5                //SPI时钟引脚
#define SPI_MISO_PIN GPIO_Pin_6                //SPI数据接收引脚
#define SPI_MOSI_PIN GPIO_Pin_7                //SPI数据发送引脚
#define SPI_CS_PIN   GPIO_Pin_4                //SPI片选引脚

void SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);  //使能SPI1外设时钟

    //配置SPI1对应的GPIO口
    GPIO_InitStructure.GPIO_Pin   = SPI_SCK_PIN | SPI_MOSI_PIN | SPI_CS_PIN;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = SPI_MISO_PIN;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //配置SPI1参数
    SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL              = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial     = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);  //使能SPI1外设
}

void SPI_SendByte(SPI_TypeDef* SPIx, uint8_t byte)
{
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET) ;  //等待发送缓冲区为空
    SPI_I2S_SendData(SPIx, byte);                                     //将数据写入发送缓冲区
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET) ; //等待接收缓冲区非空
    SPI_I2S_ReceiveData(SPIx);                                        //读取接收缓冲区数据,清除标志位
}

uint8_t SPI_ReceiveByte(SPI_TypeDef* SPIx)
{
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET) ;  //等待发送缓冲区为空
    SPI_I2S_SendData(SPIx, 0xFF);                                     //发送一个空数据,触发SPI通信
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET) ; //等待接收缓冲区非空
    return SPI_I2S_ReceiveData(SPIx);                                 //读取接收缓冲区数据
}

int main(void)
{
    uint8_t tx_data = 0x55;
    uint8_t rx_data;

    SPI_Init();  //初始化SPI1

    GPIO_ResetBits(GPIOA, SPI_CS_PIN);  //拉低SPI片选引脚,开始SPI通信
    SPI_SendByte(SPI1, tx_data);        //发送数据
    rx_data = SPI_ReceiveByte(SPI1);    //接收数据
    GPIO_SetBits(GPIOA, SPI_CS_PIN);    //拉高SPI片选引脚,结束SPI通信

    while (1)
    {
        //此处可添加其他代码
    }
}

以上代码实现了STM32F103C8T6单片机的SPI通信,并利用SPI1对应的GPIO口进行了初始化配置。在主函数中,通过拉低片选引脚、发送数据、接收数据、拉高片选引脚的方式实现了SPI通信。用户可以根据实际需求,在SPI_SendByte和SPI_ReceiveByte函数中修改数据的长度和数据位数等参数。

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

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

相关文章

对git的简单总结

Git的基本使用 配置用户名和邮箱常见的操作查看仓库的状态远端仓库整体流程分支本地分支命令远端分支命令 这几天在做毕业设计,需要用到git,所以简单总结一下git的基本使用。 配置用户名和邮箱 git config --global user.name "Your Name" g…

【Vue】Vue-cli,创建项目设置自定义默认配置

Vue2.0,Vue-cli项目配置 步骤一,打开文件夹,导航栏输入cmd,打开命令行窗口步骤二,输入命令步骤三,选择第三个自定义新建项目步骤四,选择需要的项目模块,空格选择完,回车步…

Semaphore详解

Semaphore的基本使用场景是限制一定数量的线程能够去执行. 举个简单的例子: 一个单向隧道能同时容纳10个小汽车或5个卡车通过(1个卡车等效与2个小汽车), 而隧道入口记录着当前已经在隧道内的汽车等效比重. 比如1个小汽车和1个卡车, 则隧道入口显示3. 若隧道入口显示10表示已经…

《string的模拟实现》

本文主要介绍库里面string类的模拟实现 文章目录 前言一、string的构造函数①无参的构造函数②带参的构造函数③修改构造函数 二、析构函数三、拷贝构造四、赋值重载五、返回size 、capacity和empty六、[]的运算符重载七、迭代器① 正向迭代器。② 正向const迭代器 八、string比…

PointPillars点云编码器代码运行过程中的问题及解决

PointPillars:点云编码器,编码特征可以与任何标准的 2D 卷积检测架构一起使用。任务是目标检测。来自CVPR2019 论文地址:https://arxiv.org/pdf/1812.05784.pdf 代码地址:GitHub - nutonomy/second.pytorch: PointPillars for KITTI object…

【LeetCode】297. 二叉树的序列化与反序列化

1.问题 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。 请设计一个算法来实现二叉树的序列化与反序列…

Css如何优雅的实现抽奖转盘

如图,抽奖转盘,可以拆分为几部分: 1.底部大圆; 2.中间小圆; 3.扇形区; 4.扇形内部奖品区; 5.抽奖按钮; 6.点击抽奖按钮时旋转动效及逻辑; 这其中,扇形区&am…

集成灶/小家电语音提示芯片方案-WTN6040-8S唯创知音自主研发

集成灶一直是厨房中常用设备之一,而现代技术的不断发展,为集成灶的升级提供了更多的可能性。深圳唯创知音为了让家用电器更加便民,专门为集成灶开发了一款语音IC方案——WTN6040语音芯片方案,这款芯片可以满足集成灶对语音提示功能…

独家专访丨TheStage.ai :当 AI 邂逅 Web3

随着2022年末ChatGPT走红,AI再次成为人们关注的焦点。上一次AI掀起舆论热潮,还是2016年AlphaGo以4:1战胜世界顶级围棋棋手李世石。 但与上次不同的是,这次AI更强大了。在接受强化训练后,AI可以对用户的需求创造新内容。 面对AI的快…

关于API数据接口的使用说明

API(Application Programming Interface)是一种让不同软件之间进行数据交换和通信的技术,使用API可以减少开发者的工作量,提高软件应用的效率和可靠性。本文将介绍API数据接口的使用方式和注意事项。 使用API数据接口的方式&…

Python一行代码实现文件共享【内网穿透公网访问】

目录 1. 前言 2. 视频教程 3. 本地文件服务器搭建 3.1 python的安装和设置 3.2 cpolar的安装和注册 4. 本地文件服务器的发布 4.1 Cpolar云端设置 4.2 Cpolar本地设置 5. 公网访问测试 6. 结语 转载自内网穿透工具的文章:Python一行代码实现文件共享【内网…

PPOCRV3文本识别模型精度损失问题解决

PPOCRV3文本识别模型精度损失问题解决 1. 得到可用的ncnn模型2. 先看问题3. 快速解决4. 问题分析5. 最终效果6. 结语 1. 得到可用的ncnn模型 paddleocr文本识别模型(ch_PPOCRv3_rec_infer)转ncnn模型,我参考了这位大神的博客,基本包括了我遇到的所有问题…

操作系统八股文知识点汇总

1. 程序编译过程 gcc HelloWorld.c -E -o HelloWorld.i 预处理:加入头文件,替换宏。gcc HelloWorld.c -S -c -o HelloWorld.s 编译:包含预处理,将 C 程序转换成汇编程序。gcc HelloWorld.c -c -o HelloWorld.o 汇编:包…

在linux下搭建clash服务

下载clash并配置 clash安装包 一般下载名称中带clash-linux-amd64的包 下载完用gunzip解压,解压后重命名或者链接到系统环境变量目录都行 下载配置信息 wget -O config.yaml [订阅链接] wget -O Country.mmdb https://www.sub-speeder.com/client-download/Coun…

深元边缘计算盒子在社区的应用,提高社区的安全性和生活质量

近年来,随着人工智能技术的不断发展和普及,越来越多的社区开始应用边缘计算盒子AI视觉分析技术,以提高社区的安全性和管理效率。本文将介绍边缘计算盒子AI视觉分析技术在社区中的应用及其优势。 一、边缘计算盒子AI视觉在社区中的应用 1.安防…

uniapp中实现自定义导航栏

整个小程序默认配置存在系统内置导航和tabbar,项目中需求存在自定义的导航。 uniapp中vue封装组件(顶部导航、底部tabbar),按照vue的相关语法使用。 在page.json文件中修改配置: 自定义导航组件: 给自定义…

PLM听过很多遍,却依旧不知道是什么?看完这篇你就懂

上周参加展会,很多客户在现场了解到e企拆图解决方案后,向我们咨询了很多问题,发现有几个名词经常被提及,比如PLM、PDM、BOM等。随着技术的爆炸发展,新的名词概念也与日俱增,对于这些名词,可能我…

工贸企业重大事故隐患判定标准,自2023年5月15日起施行

应急管理部发布了《工贸企业重大事故隐患判定标准》(自2023年5月15日起施行),适用于判定冶金、有色、建材、机械、轻工、纺织、烟草、商贸等工贸企业重大事故隐患。新修改的安全生产法对建立健全重大事故隐患治理督办制度、督促生产经营单位消…

关于ffmpeg的使用过程中遇到的点(php)

有段日子没更新,最近使用ffmepg,这里记录一下 我这边就直说一下我工作中遇到的注意事项和使用方法,就不太详细说了 首先是安装的问题,windwos的话比较简单,官网下载安装文件,解压之后。设置环境变量 系统…

【react全家桶学习】react中组件定义及state属性(超详/必看)

函数式组件定义及特点 定义&#xff08;核心就是一个函数&#xff0c;返回虚拟dom&#xff09;&#xff1a; import React from reactexport default function index() {return <div>index</div> }特点&#xff1a; 1、适用于【简单组件】的定义2、是一个函数&a…