转自:转载请注明出处:HateMath的网上田园 )http://blog.vckbase.com/hatemath/archive/2005/11/18/15031.aspx
写的非常感性,万分感谢,在此保留!
1. I2 C总线是什么?
I2 C (Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2 C总线产生于在80年代.
以上是官方说法,其实说白了就是那么两条线,可以用来按照规定的格式传输数据.
2.我为什么要用I2 C总线?
传送数据的总线形式很多,为什么要用I2C总线?
上面提到, I2 C总线是一种”两线式串行总线”.这里,关键是"两线式".很显然,具有两条信号线的总线在电气连接上简洁方便,占用的空间小. 减少了电路板的空间和芯片管脚的数量,降低了互联成本。
这两条线,就是传说中的时钟信号线(SCL)和数据信号线(SDA).
3.SCL 和 SDA
对于使用I2 C总线传输的器件来说,它可能和外界有一些连接,比如电源VCC和接地GND以及这个器件的地址线A2/A1/A0等等.这其中,最值得注意的两根线就是SCL 和 SDA,它们是器件和外界通信的接口.
SCL(Serial CLock): 串行时钟信号线,用来给SDA上的数据传输提供时序.
SDA(Serial DAta): 串行数据信号线,所有的数据都在这条线上传输.
有人说,对于SCL和SDA我还是不大明白,听我打个比方你立刻就明白了.好比广播操比赛,如果每个人都是各自做各自的,那将是一团乱糟糟 的景象,可是如果有人在前面喊:” 1234…2234”,那么大家的动作就很整齐,整个队形看上去也像个样子.这里,” 1234…2234”就是节拍信号SCL,大家的动作就是SDA了.
相信大家一定明白了.下面让我们看一个实物图,增加一点感性认识.
图一 认识SCL和SDL
看到图中的四根红线了吗?中间两根分别就是SCL和SDA.边上的两根,自然是电源线了.
4. I2C总线中的信号.
在了解I2 C总线的工作原理之前,必须了解总线中的几种信号.就如同我们要想用英语写作,必须先学单词一样.值得庆幸的是, I2 C总线的”单词”是很少的.
I2 C总线在传送数据过程中共有三种类型信号,分别是:开始信号(START)、结束信号(STOP)和应答信号(ACK)。它们的作用,有点像TCP/IP通讯中的握手信号.
开始信号 :SCL为高电平期间,SDA由高电平(H)向低电平(L)跳变,表示数据传送开始.
结束信号 :SCL为高电平期间,SDA由低电平向高电平跳变,表示数据传送结束.
应答信号 :接收数据的器件在正确接收到一系列数据(一般是8bit)后的下一个时钟脉冲期间(就是SCL为高电平期间),拉低SDA(即使SDA变为低电平),表示收到.
三种信号如下图所示:
图二 在数据传输的任意时刻截取的I2C总线信号片断
注意:
1.SDA上有效数据(温度,指令等等)的传输只在SCL为高电平H时进行.显然,SCL为H时,SDA的数据应该保持稳定.
2.在SCL为H时,如果SDA的电平发生变化,只可能引起两种信号: 从上图中可以看出,当SDA由H变为L时,总线上出现”开始”信号,当SDA由L变为H时,总线上出现”停止”信号.
3.由2,我们可以得到一个明显但是重要推论: 在传输有效数据时,SDA的电平变化只能在SCL为L的时候进行.否则,总线上将会出现开始或者停止信号,打乱器件的操作时序(基于I2 C传输的器件对时序要求非常严格),使读取或写入操作失败. 明白这一点对接下来的编写代码相当重要.当然,明白了这一点后,接下来的编写代码也变的相当简单.
5.总线通讯的原理
这里所谓通讯,无非是按照时序进行数据交换罢了.比如现在想从温度传感器AD7416中读取温度值,应该怎么办呢?
通过查AD7416的DataSheet(说明书),我们可以获得如下信息:
READING DATA FROM THE AD7416/AD7417/AD7418
……
Reading data from the temperature value, is a two-byte operation, as shown in Figure 11.
你也许会说,这图看起来有点复杂.是的,我选了这个DataSheet中最复杂的时序图.并不是本人BT,等我把这个复杂的图讲简单后,你会发现I2C通信格式不过如此嘛.
上图中,让我们先看看有熟悉得地方没有?有的,注意我手工标记的5个数字.其中,1 是开始信号,5是结束信号,2.3是应答信号,4么,暂时不用管它.
由上面的图我们可以看出,它的工作时序是这个样子:
1.控制器C(多半是微处理器)发出开始信号1
2.C紧接着在总线上发出寻址信号(里面包含器件D的地址),因为总线上可能有多个器件.
3.C收到D的响应,表示:你要找的器件在这.
4.D发送温度数据的高8位
5.C开始一位一位的接收D发出的温度数据,然后保存.
6.收到8位数据后,C发送一个响应信号,告诉D,收到了。
7.D发送温度数据的低8位。
8.收到并保存低8位数据后,C在紧随的下一个周期拉高SDA(就是4所标记的那个)。
9.C发出结束信号。
就是这样子了,不要问我为什么过程这么繁杂,DataSheet里就是这么规定的。有意见的话,问AD公司去吧 ^_^。
6.举个用KeilC实现开始信号的例子
上面已经把关键的地方和值得注意的事项讲完了.至于其中的开始、结束等信号,用微控制器很容易实现的。比如产生开始信号:
设备:
控制器: AT89C51
传感器: AD7416
接线:
AT89C51的P3.4 <------> AD7416的SCL
AT89C51的P3.5 <------> AD7416的SDA
//////////////////////////////////////////////////////////////////////
// Start()
// send start signal, tell AD7416 to start
void Start()
{
SCL = 0; //先让SCL 为低电平
Delay(); // 延时几个微秒,让信号线有足够的时间变化为我们设置的电平.
SDA = 1; //在SCL为L的时候,改变SDA的状态
Delay();
SCL = 1; // SCL 为H
Delay();
SDA = 0; //此处实现SDA由高到低的跳变,开始信号就此产生
Delay();
}
//////////////////////////////////////////////////////////////////////
//delay some time
void Delay()
{
_nop_();
_nop_();
}
这么简单就完了?
当然不是,不过上面给出的一个完整的Start()函数 告诉大家如何用代码控制开始信号的产生.把这个搞清楚后,接下来的停止信号、应答信号以及发送和接收有效数据信号都大同小异.
这是一个最简单的从AD7416中读取温度值的代码.我昨天测了,室内温度12度(如下图)
下载KeilC51写的完整代码:
http://blog.vckbase.com/Files/HateMath/AD7416.rar
(全文结束)