Chinaunix首页 | 论坛 | 博客
  • 博客访问: 726353
  • 博文数量: 104
  • 博客积分: 4320
  • 博客等级: 上校
  • 技术积分: 1948
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-30 14:42
文章分类

全部博文(104)

文章存档

2012年(4)

2011年(65)

2010年(35)

分类: LINUX

2011-04-02 11:57:26

I2C总线是Philips公司最先推出的一种双向数据传输总线,其仅使用两根连线便可以实现全双工同步数据传送。在I2C总线中,一条为串行数据线(SDA),另一条为一条串行时钟线(SCL)。I2C总线占用引脚少,接口协议简单。目前多数公司均推出了I2C总线接口的各种器件,如存储器、A/D、D/A、键盘、LCD等,大大方便了用户的选择。
本章主要介绍了I2C总线的工作原理、寻址方式以及数据操作,并重点介绍了数据传输协议以及相应的C51子函数。最后通过具体的实例,介绍如何使用在没有I2C总线接口的单片机上读写具有I2C总线接口的E2PROM存储器。

1  I2C总线概述

I2C总线采用两线制,由数据线SDA和时钟线SCL构成。I2C总线对数据通信进行了严格的定义。

1.1  I2C总线工作原理

典型的I2C总线系统结构,如图所示。I2C总线上可以挂接多个器件,其中每个器件必须都支持I2C总线通信协议。

1.2  I2C总线器件的寻址方式
由于所有器件都通过SCL和SDA连接在I2C总线上,因此,主器件在进行数据传输前需要通过寻址,选择需要通信的从器件。I2C总线上所有外围器件都需要有唯一的7位地址,由器件地址和引脚地址两部分组成。
器件地址是I2C器件固有的地址编码,器件出厂时就已经给定,不可更改。
引脚地址是由I2C总线外围器件的地址引脚(A2,A1,A0)决定,根据其在电路中接电源正极、接地或悬空的不同,形成不同的地址代码。
1.3  I2C总线数据操作
在I2C总线上,数据是伴随着时钟脉冲,一位一位地传送的,数据位由低到高传送,每位数据占一个时钟脉冲。I2C总线上的在时钟线SCL高电平期间,数据线SDA的状态就表示要传送的数据,高电平为数据1,低电平为数据0。在数据传送时,SDA上数据的改变在时钟线为低电平时完成,而SCL为高电平时,SDA必须保持稳定,否则SDA上的变化会被当作起始或终止信号而致使数据传输停止。
1.写数据格式
2.读数据格式

2  I2C总线接口EEPROM存储器
目前,市场上I2C总线接口器件有多种,例如A/D转换器、D/A转换器、时钟芯片和存储器等。这里以典型的I2C总线接口的存储器为例进行介绍。
I2C总线接口EEPROM存储器是一种采用I2C总线接口的串行总线存储器,这类存储器具有体积小、引脚少、功耗低、工作电压范围宽等特点。目前,Atmel、MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存储器。在单片机系统中使用较多的EEPROM存储器是24系列串行EEPROM。其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展方便、读写简单等优点。

3  C51模拟 I2C总线协议
在实际应用中,往往遇到所使用的单片机没有I2C总线接口,例如典型的 51系列单片机。为了让此类单片机用于操作I2C总线器件的能力,往往需要在程序模拟I2C总线数据传输协议。
这里以典型的51系列单片机为例,假设其外接6MHz的晶振,采用P1.0作为时钟线SCL,P1.1作为数据线SDA。在C51语言的程序中,首先需要声明SCL和SDA所使用的引脚。其声明如下所示:
sbit SCL=P1^0;
sbit SDA=P1^1;

3.1  延时子函数
这里给出一个典型的延时子函数。当单片机的工作频率比较高的时候,为了保证I2C总线的传输速率满足100kHz或者400kHz的限制,可以进行适当的延时处理。用户可以根据需要使用。延时子函数的程序示例如下:
void Delays(unsigned int number)            //延时子程序
{
unsigned char temp;
for(;number!=0;number--)    //循环
{
for(temp=0;temp<100;temp++)        //空循环
{
}
}
}

3.2  起始信号子函数
起始信号子函数用于开始I2C总线通信。其中,起始信号是在时钟线SCL为高电平期间,数据线SDA上高电平向低电平变化的下降沿信号。起始信号出现以后,才可以进行后续的I2C总线寻址或数据传输等。起始信号的时序,如图所示。在程序中,可以直接为SDA和SCL赋值来实现起始信号的时序。起始信号子函数示例如下:
void StartI2C()                            //起始信号子程序
{
 SDA=1;
 Delays(1);                            //延时,用于满足传输速率要求
 SCL=1;
 Delays(1);
 SDA=0;
 Delays(1);
 SCL=0;
 Delays(1);
}

3.3  终止信号子函数
终止信号子函数用于终止I2C总线通信。其中,终止信号是在时钟线SCL为高电平期间,数据线SDA上低电平到高电平变化的上升沿信号。终止信号一出现,所有I2C总线操作都结束,并释放总线控制权。终止信号的时序,如图所示。在程序中,可以直接为SDA和SCL赋值来实现终止信号的时序。终止信号子函数示例如下:

3.4  应答信号子函数
应答信号子函数用于表明I2C总线数据传输的结束。I2C总线数据传送时,一个字节数据传送完毕后都必须由主器件产生应答信号。主器件在第9个时钟位上释放数据总线SDA,使其处于高电平状态,此时从器件输出低电平拉低数据总线SDA为应答信号。应答信号的时序,如图所示。在程序中,可以直接为SDA和SCL赋值来实现应答信号的时序。应答信号子函数示例如下:
void AckI2C()                                //发送应答位子程序
{
 SDA=0;
 Delays(1);
 SCL=1;
 Delays(1);
 SCL=0;
 Delays(1);
 SDA=1;
 Delays(1);
}

3.5  非应答信号子函数
非应答信号子函数用于数据传输出现异常而无法完成时。在一个字节数据传送完毕后,在第9个时钟位上从器件输出高电平为非应答信号。非应答信号的产生有两种情况。
当从器件正在进行其他处理而无法接收总线上的数据时,从器件不产生应答,此时从器件释放总线,将数据线SDA置为高电平。这样,主器件可产生一个停止信号来终止总线数据传输。
当主器件接收来自从器件的数据时,接收到最后一个数据字节后,必须给从器件发送一个非应答信号,使从器件释放数据总线。这样,主器件才可以发送停止信号,从而终止数据传送。

3.6  应答位检查子函数
应答位检查子函数用于主器件检测接收的是否为正常的应答信号,以便于判断数据接收是否正常。程序中定义了ErrorBit作为应答检查位,用于数据线SDA上的应答位检查结果,最后通过return语句返回该值。应答位检查子函数示例如下:
bit TestAckI2C()                            //应答位检查子程序
{
 bit ErrorBit;
 SDA=1;
 Delays(1);
 SCL=1;
 Delays(1);
 ErrorBit=SDA;                                //读入SDA上的应答状态
 Delays(1);
 SCL=0;
 Delays(1);
 return(ErrorBit);                            //返回应答状态,0为应答信号,1为非应答信号
}

3.7  单字节写子函数
单字节写子函数用于向从器件写入单个字节的数据。程序中,可以通过for循环语句,逐位将数据发送到I2C数据总线上。该函数在使用之前,必须先使用起始信号子函数启动I2C总线数据传输。单字节写子函数的流程图,如图16.7所示。单字节写子函数示例如下:
bit Write8BitI2C(unsigned char input)            // input为待发送的数据
{
 unsigned char temp;
 for(temp=8;temp!=0;temp--)                    //循环移位,逐位发送数据
 {
  SDA=(bit)(input&0x80);                        //取数据的最高位
  Delays(1);
  SCL=1;
  Delays(1);
  SCL=0;
  Delays(1);
  input=input<<1;                            //左移一位
 }
 return 1;
}

3.8  单字节读子函数
单字节读子函数用于从I2C数据总线读入单个字节的数据。程序中,可以通过for循环语句,逐位将数据读入。该函数在使用之前,同样需要先使用起始信号子函数启动I2C总线数据传输。单字节读子函数的流程图,如图所示。单字节读子函数示例如下:

3.9  多字节写子函数
多字节写子函数用于主器件发送多个字节的数据。首先发送起始位,接着是寻址字节,然后是数据的所要存入单元的首地址,外围器件此时产生正确的应答后,主器件便将开始多个字节的数据传输。多字节写子函数的流程图,如图所示。多字节写子函数示例如下:

3.10  多字节读子函数
多字节读子函数用于主器件从SDA线上读取多个字节的数据。在读多个字节的操作中,除了发送寻址字节外,还要发送器件的子地址。因此,在读多个字节操作前,要进行一个字节的写操作,然后重新开始读操作,将从器件内的字节数据读出。多字节写读函数的流程图,如图16.10所示。多字节写读函数示例如下:
4  C51读写EEPROM实例
I2C总线接口器件以体积小,占用引脚少,接口简单,读写操作方便等优点而得到广泛的应用。目前Philips、Atmel、Maxim以及其他集成电路制造商推出了很多基于I2C总线的单片机和外围器件,如24系列E2PROM、串行实时时钟芯片DS1302、USB2.0芯片CY7C68013A等。
这里以普通的51系列单片机为例,通过实例介绍如何使用C51模拟I2C总线接口来读写I2C总线的EEPROM存储器。
4.1  电路设计
这里给出单片机AT89S51读写I2C总线接口的AT24C08存储器的电路原理图图,该电路图中所使用的元器件的参数及数量,如表所示。
4.2  程序设计
这里采用C51语言在Keil μVison3集成开发环境中编写程序。
本程序的功能是利用单片机的P1.0、P1.1作为I2C串行总线的SCL、SDA接口,向AT24C08写入10个字节的数据,然后再将写入的数据读出,并比较读写的数据是否完全一致。如果数据的读写一致,则点亮LED,表示写入正确;否则熄灭LED报警。
4.3  仿真分析
为了加深对I2C串行总线协议的理解,可以在Keil μVison3集成开发环境中对整个程序进行仿真。通过信号仿真,可以查看I2C总线中起始信号、终止信号以及数据读写的时序。具体操作步骤如下:
5  小结
本章首先介绍了I2C串行总线的工作原理、寻址方式以及总线数据的读写操作等,并对常用的I2C串行总线接口的EEPROM存储器进行了介绍。接着,本章详细介绍了I2C串行总线的协议,以及采用C51语言模拟读写I2C串行总线的子函数。最后通过一个具体的实例,讲解了51系列单片机读写I2C总线外围器件的电路设计以及程序设计。I2C串行总线具有接口简单、引脚少、体积小等优点,在实际电路设计中经常使用。
阅读(4273) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

gongxijie2014-01-16 11:46:51

你这个没写完啊,模拟之后和一般硬件实现的I2C性能对比如何呢,一般都会有性能的降低,有多大差距呢?