Arduino爱好者

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15944|回复: 18

第4章 SPI通信和I2C通信

[复制链接]
发表于 2018-11-6 08:59 | 显示全部楼层 |阅读模式
本帖最后由 单片机菜鸟 于 2019-11-28 09:19 编辑

[md]![image]()
## 第4章 SPI通信和I2C通信
    设备与设备之间的通信往往都伴随着总线的使用,而用得比较多的就当属于SPI总线和I2C总线,而恰巧NodeMcu也支持这两种总线通信,所以本章的主要内容就是讲解ESP8266 SPI和I2C总线的使用。  
### 4.1 SPI总线——SPI类库的使用
    SPI是串行外设接口(Serial Peripheral Interface)的缩写。是Motorola公司推出的一种同步串行接口技术,是一种高速的、全双工、同步的通信总线。通过它可以连接使用同样接口的外部设备。例如,ESP8266模组上,ESP8266EX芯片就是通过SPI接口与外接flash芯片连接的。  
    SPI作为一种总线通信方式,可以通过SPI接口连接多个从设备,并通过片选控制来选择对某一设备进行连接使用。如下图所示:
![image]()
#### 4.1.1 SPI总线概述  
    SPI的通信原理很简单,它是全双工主从通信方式,这种模式下通常有一个主设备和一个或者多个从设备(注意,同一时刻,只有一个主设备和一个从设备进行通信),需要至少4根线,特殊情况下(单向传输时)3根线也可以。  
    SPI的器件工作在SPI规定下的两种基本模式,即SPI主模式和SPI从模式。在一个SPI设备中,通常有如下表的几个引脚:

引脚名称 | 引脚说明
---|---
MISO(Master In Slave Out) | 主设备数据输入,从设备数据输出
MOSI(Master Out Slave In) | 主设备数据输出,从设备数据输入
SCK(Serial Clock) | 用于通信同步的时钟信号,该时钟信号由主机产生
SS(Slave Select)或CS(Chip Select) | 从设备片选使能信号,由主设备控制

    主设备负责启动通信,负责输出时钟信号以及选择通信的从设备。当有多个从设备的时候,因为每个从设备上都有一个CS引脚接入到主设备中,当我们主设备和某个从设备通信时将需要将从设备的CS引脚电平设置为低电平或者高电平(根据实际情况而定)。数据的收发通过MISO和MOSI进行。
#### 4.1.2 NodeMcu SPI  
    在上一章中,笔者提供的NodeMcu引脚映射图,其实已经标注了SPI,读者可以查阅第2章。  
    NodeMcu的SPI(注意与HSPI区分)引脚(SD0-SD3、CLK、CMD)专门用于与ESP-12E的外接flash芯片进行Quad-SPI通信,因此不能用于SPI应用。基于ESP8266的NodeMcu具有HSPI,具有4个可用于SPI通信的引脚(GPIO12-GPIO15)。通过这个SPI接口,我们可以将任何支持SPI的设备与NodeMcu连接起来,并与其进行通信。下图显示NodeMcu的SPI部分:
![image]()  
##### 知识扩展——标准SPI、Dual SPI和Quad-SPI  
    **1.标准SPI**  
    标准SPI通常就叫做SPI,它是一种串行外设接口规范,有4根引脚信号:clk、cs、mosi、miso;  
    **2.Dual SPI**  
    它只是针对SPI Flash而言,不是针对所有SPI外设。对于SPI Flash,全双工并不常用,因此扩展了mosi和miso的用法,让它们工作在半双工,用以加倍数据传输。也就是对于Dual SPI Flash,可以发送一个命令字节进入dual mode,这样mosi变成SIO0(serial io 0),mosi变成SIO1(serial io 1),这样一个时钟周期内就能传输2个bit数据,加倍了数据传输;  
    **3.Quad SPI**  
    与Dual SPI类似,也是针对SPI Flash,Quad SPI Flash增加了两根I/O线(SIO2,SIO3),目的是一个时钟内传输4个bit。所以可以理解为:在传输速度上,Quad SPI=2Dual SPI=4SPI。
所以对于SPI Flash,有标准spi flash,dual spi , quad spi 三种类型,分别对应3-wire, 4-wire, 6-wire,在相同clock下,线数越多,传输速率越高。  
    **温馨提示**  
    读者可以自行了解一下NodeMcu的flash是什么标准。说不定烧录代码失败就是因为这个原因(Flash模式是QIO或者DIO)。  
#### 4.1.3 ESP8266 SPI类库成员函数  
    Arduino Core For ESP8266的SPI类库定义在SPI.h头文件中。该类库只提供了作为SPI主设备的API,其成员函数如下:  
    **1.begin()**  
    该功能用于初始化SPI通信。  
    语法:SPI.begin()   
    参数:无;  
    返回值: 无;  
    **2.end()**  
    该功能用于关闭SPI通信。  
    语法:SPI.end()  
    参数:无;  
    返回值: 无;  
    **3.setBitOrder()**   
    设置数据传输顺序。  
    语法:SPI.setBitOrder(order)  
    参数:  
        order,传输顺序,取值为:  
        ~ LSBFIRST,低位在前;  
        ~ MSBFIRST,高位在前。  
    返回值: 无;  
    **4.setClockDivider()**  
    设置通信时钟。时钟信号由主机产生,从机不用配置。但主机的SPI时钟频率应该在从机允许的处理速度范围内。  
    语法:SPI.setClockDivider(divider)  
    参数:  
        divider,SPI通信的时钟是由系统时钟分频得到的。可使用的分频配置为:  
        ~ SPI_CLOCK_DIV2,2分频;  
        ~ SPI_CLOCK_DIV4,4分频(默认配置);  
        ~ SPI_CLOCK_DIV8,8分频;  
        ~ SPI_CLOCK_DIV16,16分频;  
        ~ SPI_CLOCK_DIV32,32分频;  
        ~ SPI_CLOC K_DIV64,64分频;  
        ~ SPI_CLOCK_DIV128,128分频;  
    返回值: 无;  
    **5.setDataMode()**  
    该功能用于设置数据模式。  
    语法:SPI.setDataMode(mode)  
    参数:  
        mode,可配置的模式,包括:  
        ~ SPI_MODE0;  
        ~ SPI_MODE1;  
        ~ SPI_MODE2;  
        ~ SPI_MODE3;  
    返回值: 无;  
    注意点:   
    SPI四种模式中,SPI的相位(CPHA)和极性(CPOL)分别可以为0或者1,对应的4种组合构成了4种模式:  
    ~ SPI_MODE0:CPOL=0,CPHA=0;   
    ~ SPI_MODE1:CPOL=0,CPHA=1;   
    ~ SPI_MODE2:CPOL=1,CPHA=0;   
    ~ SPI_MODE3:CPOL=1,CPHA=1;   
    时钟极性CPOL:即SPI空闲时,时钟信号SCLK的电平(1是空闲时高电平,0是空闲时低电平)。  
    时钟相位CPHA:即SPI在SCLK第几个边沿开始采样(0是第一个边沿开始,1是第二个边沿开始)。  
    **6.transfer()**  
    该功能用于传输1B的数据,参数为发送的数据,返回值为接收到的数据。SPI是全双工通信,因此每发送1B的数据,也会接收到1B的数据。  
    语法:SPI.transfer(val)  
    参数:  
        val,要发送的字节数据。  
    返回值: 从机返回的1B数据;  
    **7.transfer16()**  
    该功能用于传输2B的数据,参数为发送的数据,返回值为接收到的数据。  
    语法:SPI.transfer16(val)  
    参数:  
        val,要发送的16位(uint16_t)数据。  
    返回值: 从机返回的2B数据;  
    注意点: 发送的uint16_t数据,其实底层也是分开两个字节分别发送两次,接收到的2B数据,也会重新组装成uint16_t数据;  
    **8.transferBuf()**  
    该功能用于传输一个缓冲区数据,参数为发送的缓冲区buf。  
    语法:SPI.transfer(buf,count)  
    参数:  
        buf,要发送的缓冲区(uint8_t*)数据。  
        count,缓冲区的大小。
    返回值: 无;  
    注意点: 虽然没有返回值,但是从从机传输回来的数据会替换掉buf缓冲区的数据,所以调用完整个方法之后,buf里面的数据就是从机返回的数据;  
    **9.pins()**  
    该功能用于切换SPI引脚映射,需要在SPI.begin()之前调用SPI.pins(6,7,8,0)。  
    语法:SPI.pins(sck, miso, mosi, ss)  
    参数:  
        sck,时钟引脚,固定为6;  
        miso,主设备输入,从设备输出引脚,固定为7;  
        mosi,主设备输出,从设备输入,固定为8;  
        ss,使能信号引脚,固定为0。
    返回值: 无;  
    注意点: 通常情况下,ESP8266的SPI对应引脚为MOSI-GPIO13,MISO-GPIO12,SCLK-GPIO14,SS-GPIO15。如果在调用SPI.begin()之前调用SPI.pins(6,7,8,0),那么引脚映射就会变成MOSI-SD1,MISO-SD0,SCLK-CLK,HWCS-GPIO0。可以看出它们和ESP8266模块的外接Flash共享了SPI引脚。这个时候SPI的SS控制位就不是由我们的代码来控制,而是由系统硬件本身来调配,因为它必须确保外接Flash的优先级是最高的。在此,笔者不建议这么用。
#### 4.1.4 SPI寄存器  
    所有的SPI设置都由Arduino SPI控制寄存器(SPCR)来决定。这个寄存器就是微控制器内存的一个字节,它是可读写的。寄存器提供的服务通常有3类:控制、数据和状态。  
    **控制寄存器(SPCR)**  
    编码设置控制多种微控制器的功能。通常控制寄存器中的一个位影响某个特定的设置(学过单片机系统的读者应该比较了解这个,比如中断允许控制寄存器IE、中断优先级控制寄存器IP、定时器/计数器控制寄存器TCON等)。  
    **数据寄存器(SPDR)**  
    存储数据的寄存器,比如串行口锁存器SBUF,仅仅hold住了一个字节。比如,SPI数据寄存器hold住了要发往MOSI线的一个字节,或者这个数据是要从MISO线传入的。  
    **状态寄存器(SPSR)**  
    根据多种微控制器的条件改变其状态。比如,SPI状态寄存器(SPSR)的第七位被设置为1表示有数据从SPI传入或传出。  
    在这里,我们主要讲解一下SPI控制寄存器(SPCR),一共有8位,每一个都控制了一种特定的SPI设置。  

位数 | 名字 | 描述
---|---|---
7 | SPIE | 置为1时,表示enable SPI的中断。
6 | SPE | 置为1时,表示enable SPI。
5 | DORD | 发送数据时,设置为1表示最低有效位,0表示最高有效位。
4 | MSTR | 设置为1表示Arduino为master模式,0为slave模式。
3 | CPOL | 即SPI空闲时,时钟信号SCLK的电平(1是空闲时高电平,0是空闲时低电平)。
2 | CPHA | 即SPI在SCLK第几个边沿开始采样(0是第一个边沿开始,1是第二个边沿开始)。
1 | SPR1 | 设置SPI的速度,和SPR0组合
0 | SPR0 | 设置SPI的速度,和SPR1组合,00是最快的(4MHz),11是最慢的(250KHz)。[/md]
 楼主| 发表于 2018-11-8 13:19 | 显示全部楼层
更新第4章部分内容
发表于 2018-11-8 17:55 | 显示全部楼层
k已读,慢慢理解,。
发表于 2018-11-10 01:09 | 显示全部楼层
已收藏 慢慢理解
发表于 2018-11-20 18:05 | 显示全部楼层
感谢,大牛啊。能加您微信或q吗?
 楼主| 发表于 2018-11-20 18:08 | 显示全部楼层
bitwxd 发表于 2018-11-20 18:05
感谢,大牛啊。能加您微信或q吗?

有qq群的 以往的链接
发表于 2019-1-17 18:21 | 显示全部楼层
这是什么书的内容吗?
 楼主| 发表于 2019-1-17 18:40 | 显示全部楼层
zhaxiaorui 发表于 2019-1-17 18:21
这是什么书的内容吗?

不是什么书 我自己写的
发表于 2019-2-19 08:34 | 显示全部楼层
已收藏 慢慢理解
发表于 2019-2-22 18:03 | 显示全部楼层
楼主,ss 片选的规则是什么?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino爱好者

GMT+8, 2022-12-3 03:42 , Processed in 0.070365 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表