转自:

1. https://www.yiboard.com/thread-782-1-1.html

2.https://mansfield-devine.com/speculatrix/2018/01/avr-basics-spi-on-the-atmega-part-1/

当AVR与其他器件进行数据交互时,我们需要选择采用哪种方式。这里可以使用UART、I2C等经典的串口方式,也可以选择串行外设接口(SPI)。我比较喜欢SPI总线方式。那么让我们来聊一聊这种总线形式。

关系

在SPI中的一个重要的概念就是主从关系。一个设备作为主机,负责产生时钟信号并启动每次通信。除了时钟之外,其他设备在很多方面都像主机一样操作,而且只有在被呼叫时才会回应。

一般情况下,SPI总线至少由四条线组成 - 也就是说,它需要每个器件的四个引脚。 他们是:

●    MOSI:主机输出,从机输入 - 数据从主机传输到从机。

●    MISO:主机输入,从机输出 - 用于从从机到主机的数据传输。

●    SCK:时钟线,有时也被标记为CLK。

●    SS:从机选择 - 有时也被标记为片选(CS);这根线激活从机并启动通信。

和其他总线不一样的是,SPI总线总是只有一根MOSI、一根MISO和一根SCK。但是该总线是设计用于连接多个设备。每个总线上只有一个主机设备(不同于提供多主设备模式的I2C)。但是你可以有多个从设备,每个都需要自己的SS线。

这被认为是SPI的弱势之一,尤其是当您尝试使用GPIO数目较少的微控制器时。它至少需要将四个引脚连接在一个从机设备上,每个附加的从设备需要另一个引脚。但是,这种总线方式非常简单,通讯速度可以很快。

专用硬件

谈到GPIO引脚,可以使用任何GPIO引脚来实现一种“软件模拟串行”方式的SPI。事实上,在使用移位寄存器等设备时,我已经做到了这一点。但是,您需要负责切换时钟引脚,以产生必要的脉冲,并将数据移入或移出数据引脚。这并不难,但像AVR微控制器这样的设备已经内置了硬件来为您做所有这些。

我使用ATMEGA328P进行实验,所以我将指出这一点,但所有这些都应该轻松转移到其他微控制器。我们来看看ATMEG328P的引脚分布。

<ignore_js_op>

ATmega_88-168-328_pinout.png (301.69 KB, 下载次数: 2)

下载附件  保存到相册

2018-1-25 10:52 上传

 

在右下角你会看到四个粉红色的标签,表明引脚16-19是我们的SPI引脚。当然,它们也是普通的GPIO,但是当启用SPI功能时,它们承担SPI的角色,我们稍后会看到。通过使用这些引脚分配的目的,你需要在代码中做更少的工作。

不同之处在于SS引脚。说实话,你用这个GPIO是非常随意的。即使启用SPI,您仍然必须将SS引脚设置为输出,并在适当的时刻将其切换为高电平或低电平。如果你想用另一个引脚,可以自己选择。如果你想要连接不止一个从设备,你必须使用其他的GPIO。

转移数据

在讨论如何使用SPI之前,让我们花点时间考虑它是如何工作的。

您可以将每个器件(主器件和从器件)的SPI部分视为一个移位寄存器,在每个时钟脉冲中,一次输入一位和输出一位。

当时钟滴答时,从主机的移位寄存器发送一位到从机上,其余位移位。从机的移位寄存器有足够的空间来接受这个位,因为在同一个时钟脉冲上,从机已经向主机发送了一位数据,并且也一起移动了。在八个时钟脉冲之后,两个器件已经交换了这些移位寄存器中的全部字节。

这就是SPI的秘密:每当主机发送数据时,无论数据是否有意义(通常不是),它都会返回。事实上,有很多时候,主机只是想刺激从机放弃一些数据,而这是通过发送任何东西来实现的。它可以是全0或全1,这并不重要 - 这只是让从机发送任何已经准备好的移位寄存器的一种方式。

启用S​​PI

像微控制器上的许多事情一样,SPI通过巧妙地使用寄存器来控制。和往常一样,在AVR中,宏(通过avr / io.h)定义了寄存器和其中的位,所以我们可以简单地使用这些名称来处理接口。

我们不会在这里详细介绍SPI,但是我们将看看能让您获得简单的SPI解决方案的关键要素。我们的重点在于使用AVR作为主设备。

SPCR - SPI控制寄存器

SPCR是建立SPI的关键寄存器。所有八位用于配置接口,它们是:

7
6
5
4
3
2
1
0
SPIE
SPE
DORD
MSTR
CPOL
CPHA
SPR1
SPR0

根据数据表,当ATMEGA328P上电时,SPCR设置为0。个人而言,我并不介意花费一个或两个时钟周期,在我的SPI设置例程开始时,写到:

  1. 1SPCR = 0;

复制代码

那我们来看看这些位的含义:

●    SPIE - SPI中断使能。将其设置为1时,只要另一个寄存器中的另一个位(SPSR中的SPIF精确)被置位,就会触发SPI中断。

●    SPE - SPI启用。这是至关重要的,因为它有效地打开SPI并使这些引脚承担SPI的角色。

●    DORD - 数据顺序。这控制数据是首先发送最高有效位(MSB - 即第7位)还是最低有效位(LSB,第0位)。在默认状态(0)是MSB,这就是我喜欢它。如果您以此方式滚动或者从属设备期望它,则将此设置为1为Little-Endian。

●    CPOL、CPHA - 时钟极性和时钟相位。这些需要更多的解释,我们马上就会谈到。

●    SPR1、SPR0 - SPI时钟频率。它们与SPSR寄存器中的SPI2X位一起使用来设置时钟速度,从而设置数据移动的速率。这是一个与处理器的振荡器时钟频率(Fosc)相关的预分频器。

相位和极性

时钟极性和相位的设置取决于从机的工作方式和期望值。有四种模式:

SPI模式
条件
前边沿
后边沿
0(0,0)
CPOL = 0,CPHA = 0
采样(上升沿)
设置(下降沿)
1(0,1)
CPOL = 0,CPHA = 1
设置(上升沿)
采样(下降沿)
2(1,0)
CPOL = 1,CPHA = 0
采样(下降沿)
设置(上升沿)
3(1,1)
CPOL = 1,CPHA = 1
设置(下降沿)
采样(上升沿)

您需要阅读从设备的数据表以了解其要求。例如,我最近搞砸了一个23LCV512的串行RAM芯片。其数据表说明如下:

The device is accessed via the SI pin, with data being clocked in on the rising edge of SCK.

数据在上升沿“锁存”(又称锁存或采样)意味着它必须是上表中的模式0或模式3。这取决于上升沿是被认为是“领先”还是“落后”。你怎么知道的?回到数据表。它应该显示时序图。这里是我们的RAM芯片的例子:

<ignore_js_op>

Serial_RAM_timing.png (254.14 KB, 下载次数: 2)

下载附件  保存到相册

2018-1-25 10:52 上传

 

在输入版本中的所有内容开始之前,看看SCK线路是如何变低的?当SCK变高时,'MSB'发生。所以这里的上升沿也是领先的,这意味着我们想要模式0,在很多圈子里也被称为0,0。

设置速度

设置SPCR中的SPR0和SPR1位以及SPSR中的SPI2X位可将时钟频率设置为用于运行微控制器(Fosc)的振荡器的特定频率的一小部分。所以,如果你像我一样在16MHz下运行你的处理器,并且设置一个预分频值(比如16),那么SPI总线将以1MHz运行。预分频值越大,SPI总线越慢。

你可能会认为你想尽可能快地走,但是你可能会遇到问题,特别是如果你的从机的电线很长。正如我在面包板上做了很多这样的事情,我倾向于使用第二个最慢的64位设置,推测我可以随时尝试提高速度。

SPI2X
SPR1
SPR0
SCK频率
0
0
0
Fosc / 4
0
0
1
Fosc / 16
0
1
0
Fosc / 64
0
1
1
Fosc / 128
1
0
0
Fosc / 2
1
0
1
Fosc / 8
1
1
0
Fosc / 32
1
1
1
Fosc / 64

SPSR - SPI状态寄存器

在这里我们只关心三个位,如果说实话,我主要关心的只有一个位。

7
6
5
4
3
2
1
0
SPIF
WCOL
-
-
-
-
-
SPI2X

●    SPIF - SPI中断标志。当数据传输和输入完成时自动设置。如果您已经使能了全局中断和SPCR中的SPIE位,则当该标志置位时将触发中断。处理该中断将自动清除该标志,就像读取SPI数据寄存器(SPDR)一样。所以大多数情况下,你只需要读取这个标志就可以了。

●    WCOL - 写入碰撞标志。

●    SPI2X - 时钟速度设置的一部分。

准备设置

在我们检查第三个寄存器之前,让我们来设置SPI。我将假定AVR将作为一个主机,我们不会搞乱中断,数据顺序将是MSB第一。我将要进行通讯的是串行RAM芯片,它的时钟极性(CPOL)为0,时钟相位(CPHA)为0。我将使用处理器速度的1/64作为总线的速度。

让我们配置SPCR的八位。我将逐一浏览所有八位数据 - 即使是我没有使用的数据 - 你可以看到:

  1. SPCR = 0;                 // just to be sure
  2. // SPCR |= (1 << SPIE);   // not using interrupts, so leaving this at 0
  3. SPCR |= (1 << SPE);       // enable SPI
  4. // SPCR |= (1 << DORD);   // we want to keep the default MSB first, so not using this
  5. SPCR |= (1 << MSTR);      // set master mode
  6. // SPCR |= (1 << CPOL);   // leaving this set to 0
  7. // SPCR |= (1 << CPHA);   // leaving this set to 0
  8. SPCR |= (1 << SPR1);      // using a prescaler setting of 64 (1,0) in this register
  9. // SPCR |= (1 << SPR0);

复制代码

这样我们就准备好了。 在第2部分中,我们将开始使用SPI总线。

ATMEGA的SPI总线 - 第1部分的更多相关文章

  1. ATMEGA的SPI总线 - 第2部分

    参考: 1.https://www.yiboard.com/thread-783-1-1.html 2.https://mansfield-devine.com/speculatrix/2018/01 ...

  2. SPI总线

    一.概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控 ...

  3. MSP430单片机的两种SPI总线实现方式

    MSP430单片机上的SPI总线的实现方式分为两种:硬件实现和软件实现. 二者的抽象层次不同,硬件实现方式下程序员只需要完成总线协议的寄存器层,即一字节(char,8位二进制)数据,而软件实现方式下程 ...

  4. SPI总线协议及SPI时序图详解

    SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚 ...

  5. SPI总线(同步)

    一.SPI总线简介 串行外围设备接口SPI(serial peripheral interface)总线技术是Motorola公司推出的一种同步串行接口.SPI 用 于CPU与各种外围器件进行全双工. ...

  6. STM32学习笔记(八) SPI总线(操作外部flash)

    1. SPI总线简介 SPI全称串行外设接口,是一种高速,全双工,同步的外设总线:它工作在主从方式,常规需要至少4根线才能够正常工作.SPI作为基本的外设接口,在FLASH,EPPROM和一些数字通讯 ...

  7. SPI总线的特点、工作方式及常见错误解答

    1.SPI总线简介 SPI(serial peripheral interface,串行外围设备接口)总线技术是Motorola公司推出的一种同步串行接口.它用于CPU与各种外围器件进行全双工.同步串 ...

  8. SPI总线通信电路设计

    数据带宽=(总线频率×数据位宽)÷8 B表示带宽,F表示存储器时钟频率,D表示存储器数据总线位数,则带宽为: B(峰值带宽)=F(时钟频率MHz)×D(总线位数bit)/8 例如,PC-100的SDR ...

  9. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

随机推荐

  1. 由mv命令引发的对inode的思考

    一场机器迁移引起的思考 最近团队一台机器老化了,准备做全量迁移,一不小心,就把100多个G的/data目录放到了新机器的/data/data目录下,上愁了,怎么削减一层data目录呢?难倒像Windo ...

  2. 精华技巧,学会这几招可以假装是Python高手

    Python里面的技巧真的是太多了,菜鸟如何假装自己的是高手呢,下面教大家几招快速变成老司机的招数,尤其是在实战的项目中,用上这几招一定让你周围的同事刮目相看,哇这个代码有两把刷子. 很多人学习pyt ...

  3. 攻防世界——web新手练习区解题总结<3>(9-12题)

    第九题simple_php: 看题目说是php代码,那必定要用到php的知识,让我们先获取在线场景,得到如下网页 仔细看这个代码,意思大概是: 1.当a==0且a为真时输出flag1 2.当b为数字退 ...

  4. selenium上手

    功能自动化 前提 自动化的主要目的并不是为了找Bug,是为了证明功能可用 不只是所有的功能都可以自动化,如UI 并不是所有的项目都可以使用自动化,如selenium只能使用bs项目,小项目不适合使用自 ...

  5. Myabtis动态SQL,你真的会了吗?

    目录 前言 什么是动态SQL? 常用的标签 if choose.when.otherwise where foreach set sql include 总结 拓展一下 Mybatis中如何避免魔数? ...

  6. 2020年的UWP——通过Radio类控制Cellular(1)

    最近在做UWP的项目,在2020年相信这已经是相对小众的技术了,但是在学习的过程中,发现某软这么几年仍然添加了不少的API,开放了相当多的权限.所以打算总结一下最近的一些经验和收获,介绍一下2020年 ...

  7. css动画 loading

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 20190923-08Linux压缩和解压类 000 016

    gzip/gunzip 压缩 1.基本语法 gzip 文件 (功能描述:压缩文件,只能将文件压缩为*.gz文件) gunzip 文件.gz (功能描述:解压缩文件命令) 2.经验技巧 (1)只能压缩文 ...

  9. python appium app ui 自动化

    1.下载Android-SDK.夜神安卓模拟器.Appium.adb命令执行包并配置环境变量 2.打开夜神 3.打开Appium进行配置,配置如下 4.启动命令,到夜神bin目录下执行 adb con ...

  10. 反序列化之PHP

    反序列化漏洞 #PHP反序列化 原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果.在反序列化的过程中自动触发了某些魔术方法. ...