14244|17

190

帖子

0

TA的资源

五彩晶圆(初级)

楼主
 

第12/15原创:事无巨细,IIC总线协议与AT24C02 [复制链接]

事无巨细,IIC协议与EEPROM 24C02

在前面的一系列文章中,我们从最简单的开发环境开始到上一节的片外DAC的使用为止,算是AVR单片机中比较简单但是绝对是比较全面的内容了。如果你能够独立掌握了前面的这些内容,我们现在可以开始进入CEPARK AVR开发板上最后的三个最难的内容:存储芯片AT24C02的IIC总线协议,时钟芯片DS1302的SPI总线协议,还有温度传感器DS18B20的单总线协议。
今天我们来讲存储芯片AT24C02的IIC总线协议。(也称I^2 C总线协议)
IIC的概念:
IIC,英文全称为Inter-Integrated Circuit,即内置集成电路。所以IIC总线协议,就是指内置集成电路总线协议。我理解为集成电路直接用以数据传输的线路。
IIC的发展:
IIC总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
IIC的特点:
IIC总线最主要的优点是其简单性和有效性。由于接口直接在组件之上而且只有两根信号线,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。I2C总线的另一个优点是,它支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
IIC总线操作方法:
IIC总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。笔者分别配合时序图来说明:
1、开始信号与结束信号:

开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。
一定要注意时序的精准性!这两个信号成功的关键是:
① 在SDA的整个变化期间,SCL是一直保持稳定的高电平的。SCL监视SDA的整个变化而不只是开始信号中的负跳变或者结束信号的正跳变。
② 要注意到IIC总线的传输速度为Kbps级,而AVR单片机工作频率为Mbps级,所以必不可少的要用us级延时函数_delay_us()将单片机速度降下来配合IIC时序。
2、应答信号

首先要知道器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。如上应答信号时序,SCL线为主机(微控制器)控制,DATA IN表示从机接受数据情况,DATA OUT表示从机发送数据情况。如图可见,在START信号之后,从器件在8个时钟脉冲的控制下接受数据,在此期间从机并未发出任何信号!而在第9个时钟期间,从机将SDA线拉低表示应答。
所以,应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。
关于SDA上的数据变化

如上图所见,当SCL为高电平时要求DATA STABLE即数据稳定,而在SCL低电平时才可以DATA CHANGE即数据改变。所以IIC总线协议要求只有在SCL为低电平是SDA上的数据才可以改变。因为若SCL处于高电平期间,SDA上的电平无论发生上升沿还是下降沿,都会被识别为一次开始或结束信号。
4、字节传输时序

上时序是一个个完整的IIC字节写周期,有左往右,起始信号之后:
如果是写字节,前8个时钟周期中的SCL上升沿将数据写入数据接收方,接着在第九个周期数据接收方发出应答信号;
而如果是读字节,前8个时钟周期中的SCL上升沿将数据从数据发送方读出到SDA线上,并且数据接收方在第九个周期选择发送怎样的应答信息到SDA线上;
如果使用中断方式的IIC,要把上图中的英文字看明白。
CEPARK AVR开发板上集成了Two-wire Serial EEPROM 24C02,全面兼容IIC协议,具有256X8 bit存储空间,也就是2k位(注意是2K位不是2K字节)。我们来看看CEPARK AVR 开发板的AT24C02模块原理图:

看上图,
A0、A1、A2三个引脚为AT24C02的硬件地址线,根据引脚上的电平决定当前器件的硬件地址。
WP为AT24C02的写保护引脚,当该引脚为高电平时,器件只读不写。
SCL、SDA分别为器件的IIC协议接口。
注意到SCL和SDA分别接了两个10K上拉电阻,我想重点讲讲这两个上拉的作用。
我们有上面的几个时序可以看到,IIC传输的基本模式是“起始信号——数据传输——应答——结束”,那么要在我们的AVR Mega16上应用,毫无疑问,连接SDA的IO口要适当的在输出口和输入口两个状态间改变。这样就显得比较繁琐。然而我们可以巧妙地利用IO口的原理和这两个上拉电阻。听我说来:
首先,AVR单片机的IO口具有三态输出,高电平,低电平,高阻态。无论你水平多低,至少肯定知道前面两个。什么是高阻态呢?就是电阻无限大,你可以想象IO内部连接了一个无限大的电阻,对外表现近似开路;
其次,我们还知道器件的IO口一般都具有线与的关系,即有“0”得“0”;
好了,知道以上两条就够了。SCL和SDA两条线,具体说来一共就是五种操作:SCL拉高、SCL置低、SDA输出高、SDA输出低、还有SDA设置为输入口,来看程序怎么做:
PORTx=0x00;//先把PORTx寄存器永远配置为0,不再改变
DDRx=0xff;//IO设置为输出口,则IO输出低电平
DDRx=0x00;//IO设置为输入口,而此时IO输出高电平
前面两句应该很容易理解,但是第三句为什么将IO设置为输入口会使IO输出高电平呢?
其实此处的“将IO设置为输入口”,并不是指我们真的将要读取数据,刚才说明的“首先…..”道出了缘由:当IO设置为PORTx=0;DDRx=0;时,IO口对外呈现高阻态,近似开路。所以外部电路其实是通过10K的上拉电阻接在了5V电源上,把IO“拉”成了高电平。所以我们若要IO输出高电平,即将其设置为高阻态就可以了。
当IO用确切做输入口的时候,上拉确实是把IO拉成了高电平,会不会影响数据读取呢?看到上面强调的“即有’0’得’0’”,明白了么?电路被电源拉成了高电平,但是线路上最终的电平状态还是取决于IIC器件发出的数据“是否有0”。所以外部上拉并不会影响IO做输入状态用。
所以我们只需要用三句程序,就可以借助外部上拉完成IIC的五个操作。即(SCL拉高、SCL置低、SDA输出高、SDA输出低、还有SDA设置为输入口)
AT24C02的读写时序完全遵循标准的IIC读写时序,但是我们接下来还要了解AT24C02的器件操作方法:

上图为AT24C系列的地址寄存器,AT24C02具有2K bit,所以看到第一行。我们看到写地址寄存器的数据,最高位MSB永远是1,高四位为固定值,接下来A2,A1,A0就是前面说到的器件硬件地址,如果你写(A2,A1,A0)=(0,0,0)就对应到器件此三个引脚都接到地的那个器件。
最低位LSB是读写命令位,如果为1则表示“将要对这个器件进行‘读’操作”,反之为“写”。

这个是AT24C02的字节写时序,很清晰,由左到右(我写中文):
“起始信号——指定器件(写)——从器件应答——再写存储器内部空间地址——从器件应答——写数据到指定器件指定存储地址——从器件应答——结束信号”
注意:
MSB指最高位,LSB指最低位,上图看出数据传输都是从最高位开始;
R/W表示低电平为“写”(Write)高电平为读“Read”;
AT24C02的存储空间是2K bit,即256个字节。所以存储器寻址空间为0~255(0x00~0xff),上图的星号所以表示不需要第九位数据来寻址(但是更大容量器件就需要);

上图是AT24C02随机地址读时序,就是任意指定一个地址位置读出数据:
“起始信号——器件地址(写)——应答——指定存储空间地址——应答——起始信号——器件地址(读)——应答——读出数据——不需要应答——结束信号”
同样:
我们看到,随机读时序还是以写器件的硬件地址和存储空间地址为前提;
注意后一个器件地址,末位为“读”命令;
读出的数据仍然是高位MSB开始
读取完之后,数据读取方(也就是AVR单片机)并不需要产生应答信号
上述就是笔者的程序用到的两个时序,实现了“对AT24C02的任意地址写,并再从任意地址读”的功能。本来,存储器嘛,不是读就是写咯。以下附上详细注释的源程序:
main.rar (1.37 KB, 下载次数: 315)
最后是程序注意事项:
笔者大部分地方都用了10us的延时来配合IIC的时序;
要十分注意每次IIC时序之后的SCL和SDA线的状态,最好SCL保持低电平,以免产生不必要的起始和结束信号;
主机读取应答信号时,要将IO置为输入状态,要注意DDRx的延迟效应;
要注意任意两次完整的读写之间一定要有至少10ms的延时;(我就是卡在这点上,因为根本无资料可查,当时是靠感觉才加了20ms的延迟,没想到真的是这个原因)
写在最后:其实AVR单片机是自带了IIC接口的,叫TWI。并且IDE提供了调用函数,某种程度上来说用起来也许更为方便。但是此处仍然用IO口模拟IICj接口的方法,是觉得这样更能够掌握到IIC的底层协议,更有助于对IIC协议的理解。仁者见仁吧!
希望能给有需要的朋友一点帮助

最新回复

这个系列很不错呢  详情 回复 发表于 2013-3-25 07:48

赞赏

1

查看全部赞赏

点赞(1) 关注(1)
 

回复
举报

6366

帖子

4917

TA的资源

版主

沙发
 
继续努力啊,这个系列很不错呢,期待着
 
 
 

回复

5

帖子

0

TA的资源

一粒金砂(初级)

板凳
 

感谢分享,,

写得很不错,不过实现起来还是不简单啊,,,
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

4
 

请教高手

能请教一些关于IIC的问题吗,加我QQ373636014,谢谢了。
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

5
 
写得非常好,详细,值得学习!!!!
 
个人签名我的博客
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

6
 
如果是写字节,前8个时钟周期中的SCL上升沿将数据写入数据接收方
 请问LZ是怎么知道上升沿有效的,我看了DATASHEET好多遍 没发现是哪里有说这个 只看见说一个脉冲有效
 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

7
 
应该是上升沿写下降沿读才对,之前看的周立功的中文没有说明  还是看英文 SERIAL CLOCK (SCL): The SCL input is used to positive edge clock data into each
EEPROM device and negative edge clock data out of each device

赞赏

1

查看全部赞赏

 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

8
 
关于AT24C02的操作,虽然很多网上的代码也能驱动,但是觉得在时钟的理解上存在很多误区。比如LZ把数据的读认为是上升沿, 是因为输出的数据在上升沿期间是稳定的 .事实上for(){CLK=0,temp=sda;clk=1}能够读出数据  是因为在for循环的外面前一句的是clk=1; 而sda的数据是clk下降沿后产生的 即clk=1;clk=0;temp=sda;
 
 
 

回复

6366

帖子

4917

TA的资源

版主

9
 

原帖由 拿得起铁 于 2010-7-29 09:24 发表 关于AT24C02的操作,虽然很多网上的代码也能驱动,但是觉得在时钟的理解上存在很多误区。比如LZ把数据的读认为是上升沿, 是因为输出的数据在上升沿期间是稳定的 .事实上for(){CLK=0,temp=sda;clk=1}能够读出数据  是 ...

 

个人理解:在scl为低电平期间,SDA上的数据是不稳定的,要读数据,需要等SDA上的数据稳定后才能正确读出

 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

10
 

回复 9楼 tiankai001 的帖子

根据datasheet,在下一个下跳沿来临之前输出的都是这个数据  在两个下跳沿之间输出的数据是稳定的  而两个下跳沿之间的上升沿对数据没有影响,所一在上升沿读也没关系.我现在在SCL下跳沿后(也就是SCL为低时候)就读数据的 没有错.  当然具体编程是把SCL拉高后再读,还是象我这样下降沿后不等scl拉高读好 我也不清楚哪个好.   还请有经验的前辈指点下.但是很多人对AT24C02的CLK时序还有误解是肯定的.有些人不管上升沿下降沿只管一个时钟读取数据,写出的代码也驱动了.   
 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

11
 
另外AT24C02对读写的时序描述的不是很清楚感觉,时钟芯片DS1302除了没有应答信号,读写也是一个上升一个下降 跟AT24C02差不多.但是讲的很清楚
 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(初级)

12
 

回复 9楼 tiankai001 的帖子

严格按照LZ的想法写程序肯定是要出错的,在SCL=0;SDA=1;SCL=1;这样会缺一个跳变沿 只是LZ的写字节函数也并没有按照自己的想法严格的写,而是多了一个跳变沿,如下
void AT24C02_Byte_Write(uchar date)
{
        uchar n=0;
        for(n=0;n<8;n++)
        {
                if(date&0x80)                //从最高位开始写入
                        Set_SDA_high;
                else
                        Set_SDA_low;
                Set_SCL_high;                 //SCL上升沿写入数据
                delay10us;
                Set_SCL_low;                  //释放时钟线,为下一次上升沿做准备
                date<<=1;                     
                delay10us;
        }
        Set_SDA_high;                        //写完一个字节后,准备等待应答,把SDA置为输入口
        delay10us;              
        Set_SCL_high;                        //上升沿将应答读出在SDA线上
        delay10us;
        while(Read_SDA);                     //永久等待应答,直到有应答方可退出
        Set_SCL_low;                         //释放时钟线
        delay10us;
}

本来写入数据应该是SCL=0;SDA=TEMP;SCL=1才对(在上跳时锁住)    大家可一试试把while(Read_SDA); 放到前面一些for循环之后,也能跳出来,因为此时其实已经到了应答的周期了

LZ很久没来了 这为前辈貌似是论坛的明星,如果有空希望帮忙研究下 严格画时序图    应正下我的想法
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(高级)

13
 
写得非常好,详细,值得学习!!!!
 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(高级)

14
 
算是有点解惑了
 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(高级)

15
 
很有用
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

16
 
受益匪浅,高手很多,新手膜拜!
 
 
 

回复

27

帖子

0

TA的资源

一粒金砂(中级)

17
 

真的很不多

已经看到第12课了,写的挺详细的,楼主用心良苦
 
 
 

回复

22

帖子

0

TA的资源

一粒金砂(初级)

18
 
这个系列很不错呢
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表