友情提示:380元/半年,儿童学编程,就上码丁实验室。
这一篇打算总结一些基本概念。之所以放到第7篇才讲这个内容有两点原因:1.前几篇内容中逐渐接触到一些关于通信的知识,那么到第7篇的时候也差不多需要汇总一下了;2.本人在做四轴无人机项目时发现在这些基本概念上有一些没讲清楚,同时这些不清楚的概念也会导致在软件编写时出现了一些弯路,所以感觉非常有必要把通信的概念梳理一下。为此本人也专门查阅了一些资料,整理了一下。
那么本篇会讲些什么内容呢?主要有:串行通信,并行通信,串口通信USART,SPI,I2C,波特率。还是按照本系列的宗旨,我会讲我觉得比较有用的方面,也就是在做Arduino嵌入式项目时你必须知道的内容,如果不知道或者没搞清楚有可能会导致项目出错。当然如果你想做一些很低层的嵌入式工作可能本篇的内容就不够深入了,但是如果你像我一样借助很多“库”文件来做项目那么本篇内容应该足够你应付实际问题了。

图1中显示的是前几篇提到的各种通信模式的关系。最上层分两大类:串行通信和并行通信;并行通信到目前为止还没有涉及到,涉及到的都属于串行通信。串行通信下面又分好多种不同的协议方式:SPI,I2C,USART等等,当然串行通信下面包含的不仅仅是图1中所示的这三种,有很多种协议方式,但是目前我们在本系列中接触到的是图1中这三种,在以后的学习中可能还会接触更多不同种类但是它们之间的区别无非也就是今天要讲的几个方面。下面一一对这些概念进行介绍:
串行通信—所谓串行通信就是一堆数据,被一个一个地传输,这时候看上去就像一个“串串”,所以叫串行通信,见图2。串行通信是一个大类,凡是数据被一个一个传输的都属于串行通信。像SPI,I2C,USART等等,它们都是将数据一个一个传输的,而区别仅仅在于一些细节上,但是从大的原理上讲他们都是属于串行通信。
并行通信—所谓并行通信是和串行通信想区别的,并行通信就是一次同时传输多位数据,这些数据就像肩并肩一样被传输出去。从图2中可以看到,并行通信一次可以传输多位数据,而串行通行一次这能传输一位数据。
所以从理论上讲,并行通信效率要高于串行通信。讲到这里我想到一个很有趣的例子,在我上小学的时候,有个小朋友经常被老师罚写字,比如老师会罚他一个字写100遍,当时他就投机取巧地将三支笔绑一起来写字,这样每写一次就会出三个字,这就是一种朴素的并行通信思想。不过虽然并行通信效率高,但是它出错率也高,因为要实现并行通信意味着需要多条通道同时运行,串行通信就不同了,由于串行通信一次只发送一位数据,所以它只需要一条通道。那么好,通道多了自然出错的概率就大了。这也很容易理解,试想一位交警,他需要同时管理8条马路,另外一位交警他只需要管理一条马路,你说哪个人出错的可能性大呢?当然是同时管8条马路的那位,所谓忙中出错,这条铁律不光对人有用,对机器也一样。

讲完了最顶层的区别,接下来我们单独看看串行通信下面这些协议之间的区别。

SPI—见图3,图中是SPI的引脚示意图。假如你在使用一块SPI通信模式的模块,这时候怎么和Arduino连接呢?其实在Arduino上Pin13,Pin12,Pin11,Pin10分别被设定为SCLK,MISO,MOSI,SS引脚。什么意思呢?意思就是这几个引脚在被用作普通的I/O接口时,也可以在SPI串行通信时被用作对应功能的引脚。SCLK是“时钟引脚”,MISO是“主机发送从机接收引脚”,MOSI是“主机接收从机发送引脚”,SS是“片选引脚”。这些引脚是什么意思呢?
SCLK时钟引脚:在串行通信中通常有一个主机从机的概念,SPI既然是串行通信的一种当然也有主从机的概念。主机一般是发送时钟信号的,从机是接收时钟信号的。这个时钟信号是干什么的呢?说白了就是协调主机,从机之间发送接收动作的。所以图3中所示SPI协议下,Arduino和模块之间不需要设定波特率,因为他们之间的协调通过时钟信号就可以完成。
MISO,MOSI:主机发送信息给从机时,信息是通过MOSI传送的;主机接收从机信息时,信息由MISO传送的。其实他俩的英文写法可能会更清晰,MISO即”master in slave out”,MOSI即”master out slave in”。
SS片选引脚:片选引脚就是“模块芯片选择引脚”。看名字就知道其意思,图3中画的是1对1通信,假如是1对多通信的话就需要SS片选引脚来选择我们想要对话的模块了。

I2C—图4中是I2C协议的示意图。我们前面讲过SPI,I2C都属于串行通信,那么他们的区别又是什么呢?对比图3和图4就可以知道:1.SPI有两条数据线MOSI和MISO,I2C只有一条数据线SDA;2.SPI有片选引脚,I2C没有片选引脚。
先说数据线的差别:从图4中可见,Arduino的4号引脚可被用作I2C模式下的SDA引脚,就是数据传输引脚,它相当于图3中SPI模式下的MOSI和MISO两者的结合。所以这意味着I2C发送和接收只能同时做一样,即半双工,因为它只有一根线,同一时间要嘛发送要嘛接收;而SPI可以同时进行发送和接收动作,这就是全双工,因为SPI有两根线,一根发送一根接收。
接着说片选引脚:SPI中我们说到片选引脚是用来选择要通信的模块用的,那么I2C没有片选引脚是不是意味着I2C协议没办法做到1对多通信呢?当然不是的。I2C也可以做到1对多通信,只不过I2C在选择模块时也是通过SDA引脚实现的。具体做法是:当SDA数据引脚开始传送数据的时候,它会先传送一个片选信号,即需要通信的模块的编号,然后才开始传送数据;打个不恰当的比方,假设现在有1个主机10歌从机,假如主机要给3号从机发送数据,那么主机的SDA会先发送一个数据3,这时候所有从机都会收到这个信号,但是除了3号从机以外其他从机在接到这个数据后会保持静默状态,而3号从机会发出一个确认信号给主机,这时候主机和3号从机就建立了通信状态,接下来主机就开始传送后续的数据给3号从机了。这就是I2C与SPI在片选引脚上的区别。
上面时I2C与SPI不同之处,而I2C和SPI相同之处在于它们都有时钟信号,这就意味着它们都不需要设置波特率。

USART—,USART又叫串口通信,图5所示就是USART的引脚连接方式。其实在前面第4篇文章中我们讲到过这个连接方式图(第4篇中图5),可看到USART即没有时钟引脚,也没有片选引脚,所以这就决定了USART协议的两大特点:1.由于没有时钟信号所以USART需要另外的方法来协调主机和从机之间的动作,即“设定波特率”;2.由于没有片选引脚,USART只能单点对单点通信,不能1对多或者多对1。下面分别讲讲这两大特点:
波特率:波特率往往会和另一个概念“比特率”混淆,不过通常情况下两者数量上一致。在Arduino上通常不需要区分两者区别,为了简单起见我就简单地下个定义:在Arduino上,波特率就是比特率,即每秒发送的bit数量。
USART的点对点通信:Arduino UNO只有一套串口通信接口,即一个TX一个RX,所以如果采用USART协议,Arduino UNO同时只能和一个外设进行通信。不过有两点要说明:首先,Arduino是一个系列,它还有高端版本的版子可供选用,而这些高端版子拥有不止一套的USART串口,比如Arduino Mega,所以Arduino Mega 可以同时与多个设备通信。其次,Arduino UNO的的串口通信分为硬串口和软串口两种,什么意思呢?硬串口就是默认的Pin0为RX,Pin1为TX;不过你也可以自己定义哪一个Pin作为TX,哪一个Pin作为RX,这就是软串口。软串口的定义方法见图6。可见软串口的使用也需要通过“库”文件,不过这个库文件“Software.h”是Arduino自带的,不需要从网上下载,直接打命令就可以。图6中的例子就是将Pin2作为RX,Pin3作为TX。

上面就是对SPI,I2C,USART的介绍。总结一下本文:
1. SPI,I2C有时钟引脚,不需要设置波特率,属于同步串行通信;
2. USART没有时钟引脚,需要设置波特率,属于异步串行通信;
3. SPI和I2C可以实现1对1,1对多的通信;USART只能是1对1的通信。