在说驱动之前,咱们可以先来了解下通信的基本原理:
数据通信的种类有:串行通信、并行通信。不管是什么类型的通信,再怎么复杂的,也是在这两种上面衍生出来的。
数据通信的传输方向又有:单工、半双工、全双工。它们之间各有什么样的特点,我举了车辆过道的实例,通俗易懂的跟大家讲明白了。
数据通信的方式还可以分为:同步、异步。什么是同步?什么是异步?相信大家现在已经有个概念了吧?同步就是根据一定的时钟周期,做一定的事情,这里我举了广场舞的例子,那异步又是什么呢?异步就是随时都可以,但怎么来区分开始,动作和结束呢?这就需要一帧数据里面安插开始传输位、数据内容、结束位以作区分,然后还需要一定的传输频率,这样才能将数据发送出去。
而串口协议又是什么东西呢?串口协议就是一种串行异步通信协议。有协议还不行,得有硬件接口嘛,具体是什么就不说了。然后双方都约定好,比如通信双方都设置波特率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)是利用控制输入回路的电场效应来控制输出回路电流的一种半导体器件,并以此命名。
因此为什么I2C总线外要接两个上拉电阻的原因就在于此。这时候疑问就来了,为什么有些MCU不需要加上拉电阻也可以正常驱动I2C总线呢?
答:有些MCU内部带了弱上拉电阻,这样也可以与I2C总线实现线与的功能,这样可以保证I2C在空闲的时候都为高电平。但考虑到驱动能力的问题,毕竟由芯片输出的驱动能力有限,所以在外部接上拉电阻可以增加驱动能力。
至于电阻的大小取什么值,可以参考博客末尾的文章。
关于协议部分,常用的参考以下博客即可,写得通俗易懂,也很好理解,以下这篇文章考虑的只是主-从模式,而多主机模式在这篇文章中并没有涉及,建议还是看I2C官方的User Spec来了解,毕竟官方的是最标准的。
http://blog.csdn.net/w89436838/article/details/38660631
一网友写的一个51单片机的程序,非常好理解,截取过来:
完整PPT: