设备与设备之间的通信往往都伴随着总线的使用,而用得比较多的就当属于SPI总线和I2C总线,而恰巧NodeMcu也支持这两种总线通信,所以本章的主要内容就是讲解ESP8266 SPI和I2C总线的使用。

1. SPI总线——SPI类库的使用

    SPI是串行外设接口(Serial Peripheral Interface)的缩写。是Motorola公司推出的一种同步串行接口技术,是一种高速的、全双工、同步的通信总线。通过它可以连接使用同样接口的外部设备。例如,ESP8266模组上,ESP8266EX芯片就是通过SPI接口与外接flash芯片连接的。
    SPI作为一种总线通信方式,可以通过SPI接口连接多个从设备,并通过片选控制来选择对某一设备进行连接使用。如下图所示:

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进行。

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部分:

知识扩展——标准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)。

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的优先级是最高的。在此,笔者不建议这么用。

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)。

ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信的更多相关文章

  1. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  2. ESP8266开发之旅 基础篇④ ESP8266与EEPROM

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  3. ESP8266开发之旅 基础篇① 走进ESP8266的世界

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  4. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  6. ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库

        在网络篇①中,博主主要讲解了Arduino上开发ESP8266的插件库 Arduino Core For ESP8266.但是,并没有讲到关于这个模块的工作模式,所以本篇讲着重讲解ESP826 ...

  7. ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  8. ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266烧录配置

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  9. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

随机推荐

  1. Redis专题(3):锁的基本概念到Redis分布式锁实现

    拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...

  2. springboot应用在tomcat中运行

    1.将打包方式改成war,因为如果是java -jar xx.jar方式运行,一定是jar包 <packaging>war</packaging> 2.添加tomcat的依赖, ...

  3. 200行代码实现Mini ASP.NET Core

    前言 在学习ASP.NET Core源码过程中,偶然看见蒋金楠老师的ASP.NET Core框架揭秘,不到200行代码实现了ASP.NET Core Mini框架,针对框架本质进行了讲解,受益匪浅,本 ...

  4. CF #579 (Div. 3) A.Circle of Students

    A. Circle of Students time limit per test2 seconds memory limit per test256 megabytes inputstandard ...

  5. windows核心编程 第5章job lab示例程序 解决小技巧

    看到windows核心编程 第5章的最后一节,发现job lab例子程序不能在我的系统(win8下)正常运行,总是提示“进程在一个作业里”         用process explorer程序查看 ...

  6. Angular 页面初始化动画

    用于进入组件前的加载动画 第一步:index.html 定义动画模板和样式 // 样式 <style type="text/css">.preloader { posi ...

  7. 不吹不黑,今天我们来聊一聊 Kubernetes 落地的三种方式

    作者 | 王国梁  Kubernetes 社区成员与项目维护者原文标题<Kubernetes 应用之道:让 Kubernetes落地的"三板斧">,首发于知乎专栏:进击 ...

  8. Python3 学习笔记之 类型/运算符

    类型/运算符: 类型: 整数 字符串 浮点数 布尔类型 类型转换: 检查类型: 算术操作符: 逻辑操作符: 优先级:

  9. java第1天:简介,入门程序,变量,常量

    1 java语言简介 美国的SUN公司开发的静态面向对象的编程语言,后来被甲骨文公司收购,现在也是全球范围内最受欢迎的编程语言. *** 2 计算机进制的相互转换 进制 英文代号 2进制 bin 8进 ...

  10. Android 横竖屏切换生命周期

    默认情况下,屏幕会旋转并且会重新走生命周期. 1. 屏幕不旋转   在AndroidManifest文件中的对应Activity中配置android:screenOrientation=”landsc ...