查看原文
其他

浅谈总线通信机制(通信基础+串口+I2C)

杨源鑫 嵌入式云IOT技术圈 2021-01-31

总线的应用非常广泛,在计算机领域来说。

(1)按系统总线传输信息的方式可以分为以下三种:

1、数据总线

2、地址总线

3、控制总线

(2)按照总线的使用范围又可以分为很多很多种:

比如串口通信,计算机外设通信,网络通信等等。

(3)按数据传送方式的方式可以分为以下两种:

1、串行传输总线

2、并行传输总线

     当然还有其它的分类,非常非常的多,所以在学习的过程中,把握主体,其它的都是从一个概念中衍生出来的。

那什么是总线呢?总线就是连接多个部件的信息传输线,是各个器件共享的传输介质。

     其实不管是什么通信,本质上其实只有串行和并行。

 


   当有很多个器件和连接到总线上时候,如果出现两个或者两个以上器件同时对总线发送信息的时候,这就势必会导致竞争关系,也就是到底谁先谁后的问题,这样会导致通信过程中信号与信号之间产生冲突,就比如说,追求一个女孩(总线),我(器件)也喜欢她,你(器件)也喜欢她,但按照常理,她只能选一个她喜欢的,信得过得男孩,谈到合适的时候就结婚对吧?这个时候假设她已经有喜欢的男孩了,那么她就有这个男孩相关的信息,这点类比成一个ID好吧,每个追求者都是一个ID,由总线去匹配这个ID,最后才能连接。所以正是考虑到这样的原因,就有这么一个规定,在某一个时刻,只允许有一个器件向总线发送信息,而多个器件可以同时从总线上接收相同的信息,这就更好解释了,就拿刚刚说的男女关系,我(器件)和你(器件)都追求这个女孩(总线),而现在这个女孩(总线)选择了我(器件),那么我(器件)和女孩(总线)之间就是恋爱关系(连接)了,当你或者更多的男孩(一个器件或者多个器件)要去追求女孩(总线)的时候,她(总线)会毫不犹豫的告诉你(器件):我有男朋友了,请你们离我远点!!!(总线发广播,告诉所有的器件,所有的器件就可以同时从总线上接收信息)。当然,他们也可以分手啊,这就不用我说了吧,自己联想,道理也是一样的。纯属个人的理解,我觉得这样适合我理解哈,如有说得不对的地方,请多多指教。

   总线实际上是由许多传输线或者通路组成的,每条线可以一位一位的传输,这些位可以在规定的时间里传输完成,也可以在一定的时间内,多位同时传输;这就是串行通信和并行通信。什么是串行?简单的理解吧,串行就是一条路,一次过一辆车或者过一个人。那什么又是并行?并行就是多条路,多辆车或者多个人同时过多条路,从效率上看,并行的效率肯定比串行高,这是肯定的,毫无疑问,有点常识的人都应该知道;打个比方,你去坐地铁,没有位置的时候,你是喜欢跟别人一起挤着还是喜欢站得宽敞点舒服点?正常人肯定希望宽敞点舒服点啦,就这么个道理。那么,从成本上来讲,比如设计同样长度的传输线,这个时候,并行传输肯定比串行传输的成本要高得多了,比如修一条1000米的路成本贵一点还是修多条1000米的路成本贵一点?并行传输在这时候耗费的资源远远比串行传输要多得多了,为什么?串行传输一条线(MCU用一个IO)就可以完成多个位的传输,只是耗费的时间长而已,这是劣势。并行传输需要使用多条线(MCU使用多个IO)发送多个位,但节省了相应的时间。所以一般情况下,并行通信适合近距离传输,通常小于30m,而串行通信比并行通信更适合远距离传输,可以从几米到上千公里。

       串行和并行通信的数据传送速率都与距离成反比。在短距离内,并行通信传输效率比串行通信传送的速率高很多,但随着大规模和超大规模集成电路发展,数字电路组成的逻辑驱动器件的价格相对来说价格便宜,但通信线路的费用越来越高,因此对远距离通信而言,采用串行通信的费用远远要比采用并行通信的费用要低得多。

       从数据的传输方式角度来说就是串行和并行这两种,相信大家也理解了。那么从数据的通信方向来说,就会分单工,半双工,全双工。从概念上来说:

       1、单工:在任何时刻都只能进行一个方向的通讯,即一个固定为发送设备,另一个固定为接收设备。

    2、半双工: 两个设备之间可以收发数据,但不能在同一时刻进行。

    3、全双工:在同一时刻,两个设备之间可以同时收发数据。

       概念一看对于不理解的人来说就难以理解,只是了解,但实际是怎么样的他可能不知道。那么举个简单的例子得了,这样大家很快就懂了。

    就拿道路与交通来做个类比吧。

    单工是什么?单工就类似一个只允许单方向运行的车道,在任何时刻,只允许一辆车向同一个方向走,不允许逆行。

 


        半双工是什么?半双工就类似一条道路,在有人过来的时候,你过不去,当这个人过来了,你可以过去。



        全双工是什么?全双工就类比成两条车道,同一时间,两方的车都可以走,互不干扰,互不影响。


             这样的例子够形象吧,相信一看就懂了,不用解释哈哈。

    传输过程中,根据数据传输的方式不同,可以分为同步和异步两种。

        (1)同步,从字面上来理解,就是同一个时间内双方都在同时做一件事情,比如去公园跳广场舞吧,肯定有个领头的对吧?然后就是跟着领头一起跳舞的一群人了,他们跳舞是根据一个音乐来跳的,把握好音乐的节奏,比划不同的动作出来,这样远远一看过去,很壮观对吧,这就需要音乐和人比划的动作进行相互协调,这样才能同步。这在通信中,通常就相当于时钟线和数据线;也就是说,在时钟线启动到结束,数据线都要跟着时钟的频率进行传输。

        (2)异步,相对于同步来说了,异步双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位,在开始位和停止位之间就是数据了。

     所以,从结果来看,同步传输的信息基本都是直接同步过来数据,而异步因为包含各种各样的开始位,停止位,甚至还有数据校验位等等,所以同步传输的明显效率要比异步要高得多得多。

     在嵌入式领域中,使用串行异步通信的协议还是挺多的。比如我们接下来要说到的串口,串口协议就是异步通信的协议。

     那么,什么又是协议?把话挑明白点说,就是双方约定好一定的规则来做,不然我们去办理一些业务的时候,一般业务员都要你签一个协议,那个协议就是约束你和业务本身的一个规则。当然,在计算机通信中,也不例外的。

那串口通信又是怎么约定的呢?首先肯定得有电路连接图对吧:

     MCU要和PC机相连,中间多了一个MAX232芯片,它是用来干嘛的呢?其实就是用于电平转换用的,就是以下电平做转换,才能相互进行通信。

 



   通常,串口通信由一个起始位,多个数据位,一般是8位,或者8位以下,从一个字节的低位开始传输,传输完毕后传输停止位,这就是一个基本的串口协议,当然这个协议中也可以安插一些空闲位,还有奇偶校验位。我们可以很形象的用一幅图来表示:


         那串口也不能随便发,假设我是主机,我发得很快,从机却接收得很慢,那会造成什么样的影响?每秒传输多少数据?那么这里就出现了波特率这个概念。波特率是什么东西?简单的说,波特率就是每秒传输的位数,单位是fps/s

     常用的波特率有115200、9600、4800等等。

     比如,现在我使用波特率为115200,请问1s钟传输多少KB的数据?

     答:115200 / 8bit / 1024 = 14KB 

     所以串口传输的速度其实是很慢很慢的,一秒钟才14KB,真的很慢了。

     光说不练假把戏,没有经过验证的东西不能就说它一定是对的,即使是书本的知识。

     

[cpp] view plain copy

  1. /** 

  2.   * @brief  Ö÷º¯Êý 

  3.   * @param  ÎÞ 

  4.   * @retval ÎÞ 

  5.   */  

  6. int main(void)  

  7. {     

  8.   int i ;  

  9.   unsigned char ch = 'a' ;  

  10.   USART_Config();  //配置串口 波特率:115200   8bit数据  0个校验位  1个停止位  

  11.   while(1)  

  12.     {     

  13.         //发送一个字节      

  14.           Usart_SendByte(DEBUG_USARTx,ch);  

  15.           for(i = 0 ; i < 50000 ; i++) ;  

  16.     }     

  17. }  



     下面我使用Saleae Logic 1,1,15来分析一帧串口协议,使用STM32开发板作为实验,向PC发送一个字节的数据,然后用逻辑分析仪连上Rx口,即可得到以下数据:


上面的图片有一个地方写错了,手抖打少了一个0,解析出来得,1000 0110.

我们只是截取了其中一帧数据进行分析,由于这个程序是无线循环,所以实际上从逻辑分析仪得到的结果是这样的:

因此,我们来总结一下上面写的内容的关键部分。

       数据通信的种类有:串行通信、并行通信。不管是什么类型的通信,再怎么复杂的,也是在这两种上面衍生出来的。

       数据通信的传输方向又有:单工、半双工、全双工。它们之间各有什么样的特点,我举了车辆过道的实例,通俗易懂的跟大家讲明白了。

      数据通信的方式还可以分为:同步、异步。什么是同步?什么是异步?相信大家现在已经有个概念了吧?同步就是根据一定的时钟周期,做一定的事情,这里我举了广场舞的例子,那异步又是什么呢?异步就是随时都可以,但怎么来区分开始,动作和结束呢?这就需要一帧数据里面安插开始传输位、数据内容、结束位以作区分,然后还需要一定的传输频率,这样才能将数据发送出去。

  而串口协议又是什么东西呢?串口协议就是一种串行异步通信协议。有协议还不行,得有硬件接口嘛,具体是什么就不说了。然后双方都约定好,比如通信双方都设置波特率115200,一次发8bit数据,0个校验位,1个停止位。接下来就开始发数据,这时候就按照协议的规范,发送端开始发送一个起始位,通常是0,然后开始传输8bit数据,如果需要校验,那么就传输校验位,最后再传输1bit的停止位,这样一帧数据就发完了。

  接下来,我们来说说I2C协议I2C协议是什么鬼?I2C(Inter-Integrated Circuit)的英文缩写,是Philips公司开发的一个通信协议,只有两根线是用来通信的。简单的来说,如下图:

   

   我先来说下上面这幅图具体是什么含义,然后接下来再来说说I2C是怎么操作数据的。I2C总线就是通过SDA总线(数据)、SCL总线(时钟)来传输数据的,那为什么I2C总线上还要接两个上拉电阻呢?根据I2C规格设计上手册上了解到,由于I2C接口设计大多采用的是集电极开路或者是开漏输出的接口,当总线为空闲的时候,两根线均为高电平,由于I2C的SDA和SCL都具有线与功能,什么是线与?线与就是有0为0,同1为1,这是数字电路逻辑相关的了。也就是说只要有一个节点对总线(SCL或者SDA)发送了低电平,那么这整根线就会呈现为低电平,你想想,协议都说了,空闲要高电平,你突然给它来个低电平,这不逗死人嘛?这还叫协议?这明显就是乱搞嘛,是不是?所以既然是协议,那I2C就肯定会有约束条件嘛,这个上拉电阻的其中一个作用就在这里了,给硬件电路的IO口提供一个确定的电平信号。

  说到这里,可能有人要问了,我是写代码的,硬件我不太熟悉或者根本就不懂啊?他们可能会提出这样的问题:什么是集电极开路输出?什么是开漏输出?什么是上拉电阻?上拉电阻取值要取什么值,这个电阻取大取小对I2C通信的时候有什么影响,应该取什么值最合适?既然有上拉电阻,那是不是有下拉电阻?为什么我看有些I2C的外设接在MCU的IO口里,也没有看见接上拉电阻啊,那为什么通信也正常?

下面咱们就来说说这些问题该怎么来解答,那什么问题好解释,我们先从硬件电路开始下手,一步一步的分析上面的这些问题。

   我们先来看一个简单的电路:



   想象一下,如果现在把B点上面那一部分去掉了,变成下面这样:


   学习数字电路后我们知道,电路的输出状态有三种:

   1、高电平  2、低电平  3、高阻态

   如图(5),这种无法确定电路状态到底是高电平还是低电平,就是高阻态。

   什么是高阻态?

   答:电路分析时高阻态可做开路理解。你可以把它看作输出(输入)电阻非常大。它的极限状态可以认为悬空(开路)。也就是说理论上高阻态不是悬空,它是对地或对电源电阻极大的状态。而实际应用上与引脚的悬空几乎是一样的。 

   所以,我们可以认为,B点在开关断开的时候,相当于悬空引脚,没有办法确定它的状态,而一般情况下,为了给它确定一个电平,通常就会给IO口加一个上拉电阻,也就是图(4)看到的情况,也就是当按键没按下的时候,B点为高电平,MCU读取B点也为高电平。而当按键按下的时候,则情况相反,这就是上拉电阻的其中一个作用------确定电路的状态。那么下拉电阻也同样是这么一个功能,该怎么分析,就不用我说了,道理是一样的。

   那么,最前面我们在分析I2C为什么要接上拉电阻的问题,其中一个原因是因为集电极开路输出和漏极开路输出,先来搞明白第一个问题,什么是集电极开路输出?

   什么是集电极开路输出?集电极是什么指的什么东西?

   答:集电极是三极管的其中一个电极,这里我们形象的把它画出来:



   那么怎么解决这么不能确定c点到底输出多少的问题呢?上拉电阻闪亮登场!!!!确定电路状态,这无疑就是个宝贝,关键时刻可以用到了,我们来看看怎么改变它。

   

   由此可见,当集电极开路的时候,比如就上面说的,当三极管处于截止状态的时候。也就相当于bc之间没有形成通路的时候,那么c点的电平无法确定,也就是说,将一个无法确定电平的线路接在I2C总线的SDA和SCL上,当I2C为空闲的时候,能保证SDA和SCL输出高电平吗?不能?那不能的话,假设输出低电平,由于I2C总线的线与关系,那不就相当于违背了I2C协议所说的条件了吗?所以这就是上拉电阻存在的必要性了。集电极开路也被称为OC开路,OC,就是Open Collector的英文缩写。

   那么讲到这里,有人可能就要问了,那现在我输入1时,最终就要输出1,不要反向,我现在输入0的时候,我就要输出0,不要被反向,那如何来实现呢?

   很简单,我们接两个反向器不就得了?来看看怎么接:



  但通常在MCU中,不会这么接,但最终的效果是一样的,原理还是有所区别。于是经过改造就有了如图(10)所示的电路,由两只三极管共同控制,当电平不同的时候,总有一只三极管是导通的,当我把上拉电阻换成开关的时候,这个电路就称为推挽输出电路。



   那么什么又是漏极输出呢?漏极又是什么东西?漏极是场效应管中的一个极:如图(11)所示,场效应晶体管(Field Effect Transistor缩写(FET))简称场效应管。主要有两种类型(junction FET—JFET)和金属 - 氧化物半导体场效应管(metal-oxide semiconductor FET,简称MOS-FET)。由多数载流子参与导电,也称为单极型晶体管。它属于电压控制型半导体器件。具有输入电阻高(107~1015Ω)、噪声小、功耗低、动态范围大、易于集成、没有二次击穿现象、安全工作区域宽等优点,现已成为双极型晶体管和功率晶体管的强大竞争者。

   场效应管(FET)是利用控制输入回路的电场效应来控制输出回路电流的一种半导体器件,并以此命名。


   漏极开路(OD)输出,跟集电极开路输出是十分类似的。将上面的三极管换成场效应管即可。这样集电极就变成了漏极,OC就变成了OD,原理分析是一样的。对于漏极开路(OD)来说,必须在漏极输出端接上拉电阻,否则只能输出低电平。



   因此为什么I2C总线外要接两个上拉电阻的原因就在于此。这时候疑问就来了,为什么有些MCU不需要加上拉电阻也可以正常驱动I2C总线呢?

   答:有些MCU内部带了弱上拉电阻,这样也可以与I2C总线实现线与的功能,这样可以保证I2C在空闲的时候都为高电平。但考虑到驱动能力的问题,毕竟由芯片输出的驱动能力有限,所以在外部接上拉电阻可以增加驱动能力。

至于电阻的大小取什么值,可以参考博客末尾的文章。

       关于协议部分,常用的参考以下博客即可,写得通俗易懂,也很好理解,以下这篇文章考虑的只是主-从模式,而多主机模式在这篇文章中并没有涉及,建议还是看I2C官方的User Spec来了解,毕竟官方的是最标准的。

       http://blog.csdn.net/w89436838/article/details/38660631

  接下来看一个分析协议的实例:以下是使用LA逻辑分析仪从一个I2C接口的设备抓取的时序图:


一网友写的一个51单片机的程序,非常好理解,截取过来:




本文参考文献:

1、I2C原理和上拉下拉电阻的介绍

https://wenku.baidu.com/view/64a4bc3431b765ce04081407.html

2、什么是高阻态

https://baike.baidu.com/item/%E9%AB%98%E9%98%BB%E6%80%81/7062370?fr=aladdin

3、集电极开路输出、开漏输出、推挽输出

http://forum.eepw.com.cn/thread/242225/1

4、场效应管

https://baike.baidu.com/item/%E5%9C%BA%E6%95%88%E5%BA%94%E7%AE%A1/151400?fr=aladdin

5、关于I2C上拉电阻取值的计算方法

http://blog.csdn.net/zyboy2000/article/details/5789005

6、I2C总线协议详解:

http://blog.csdn.net/w89436838/article/details/38660631






    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存