24C08中文资料下载:
24cxx中文资料.pdf
(576.32 KB, 下载次数: 157)
1. I2C总线概念
I2C(InterIntegrated Circuit Bus)总线是一种双向二线制总线,是Philps公司推出的串行总线标准(为二线制)。总线上扩展的外围器件及外设接口通过总线寻址。它的结构简单,可靠性和抗干扰性能好。目前很多公司都推出了基于I2C总线的外围器件,例如我们学习板上的24c08芯片,就是一个带有I2C总线接口的E2PROM存储器,具有掉电记忆的功能,方便进行数据的长期保存。
2. I2C总线结构
I2C总线结构很简单,只有两条线,包括一条数据线(SDA)和一条串行时钟线(SCL)。具有I2C接口的器件可以通过这两根线接到总线上,进行相互之间的信息传递。连接到总线的器件具有不同的地址,CPU根据不同的地址进行识别,从而实现对硬件系统简单灵活的控制。
一个典型的I2C总线应用系统的组成结构如下图1所示(假设图中的微控制器、LCD驱动、E2PROM、ADC各器件都是具有I2C总线接口的器件):
我们知道单片机串行通讯的发送和接收一般都各用一条线TXD和RXD,而I2C总线的数据线既可以发送也可以接受,工作方式可以通过软件设置。所以,I2C总线结构的硬件结构非常简洁。当某器件向总线上发送信息时,它就是发送器,而当其从总线上接收信息时,又成为接收器。
3. I2C总线特点
组成系统结构简单,占用空间小。芯片管脚的数量少,无需片选信号,价格低,允许若干兼容器件共享总线,应用比较广泛,总线的长度可达7.6m,传送速度可达400kbps,标准速率为100kbps,支持多个组件,I2C上所有的设备的SDA,SCL引脚必须外加上拉电阻
4. I2C总线上的数据传送
下面我们看看I2C总线是如何进行数据传送的。我们知道,在一根数据线上传送数据时必须一位一位的进行,所以我们首先研究位传送。
1) 位传输
I2C总线每传送一位数据必须有一个时钟脉冲。被传送的数据在时钟SCL的高电平期间保持稳定,只有在SCL低电平期间才能够改变,示意图如下图1所示,在标准模式下,高低电平宽度必须不小于4.7us。
图1 位传输时序图
那么是不是所有I2C总线中的信号都必须符合上述的有效性呢?只有两个例外,就是开始和停止信号。
开始信号:当SCL为高电平时,SDA发生从高到低的跳变,出现开始信号以后,总线被认为“忙”。
停止信号:当SCL为高电平时,SDA发生从低到高的跳变,停止信号过后,总线被认为“空闲”。
开始和结束信号的时序图如下图所示:
2) 数据传输的字节格式
SDA传送数据是以字节为单位进行的。每个字节必须是8位,但是传输的字节数量不受限制,首先传送的是数据的最高位。每次传送一个字节完毕,必须接收到从机发出的一个应答位,才能开始下一个字节的传输。如果没有接受到应答位,主机则产生一个停止条件结束本次的传送。那么从机应该发出什么信号算是产生了应答呢?这个过程是这样的。当主器件传送一个字节后,在第9个SCL时钟内置高SDA线,而从器件的响应信号将SDA拉低,从而给出一个应答位。了解了I2C传输数据的格式,下面我们来研究双方传送的协议问题。
3) I2C数据传输协议
I2C总线的数据传输协议如下:
(1)、主器件发出开始信号
(2)、主器件发出第一个字节,用来选通相应的从器件。其中前7位为地址码,第8位为方向位(R/W)。方向位为“0”表示发送,方向位为“1”表示接受。
(3)、从机产生应答信号,进入下一个传送周期,如果从器件没有给出应答信号,此时主器件产生一个结束信号使得传送结束,传送数据无效。
(4)、接下来主、从器件正式进行数据的传送,这时在I2C总线上每次传送的数据字节数不限,但每一个字节必须为8位(传送的时候先送高位,再送低位)。当一个字节传送完毕时,再发送一个应答位(第9位),如上一条所述,这样每次传送一个字节都需要9个时钟脉冲。数据的传送过程如下图所示:
图2 I2C总线数据传输协议
4) 24c08芯片相关介绍
AT24c08是带有I2C总线接口的E2PROM存储器,具有掉电记忆的功能,并且可以象普通RAM一样用程序改写。它的容量是1024个字节,有A2、A1、A0三位地址,可见I2C总线上可以连接8片AT24c08,它的寻址字节是1010 A2A1A0 R/W。板上面24c08的电路连接如图所示:
图3 24C08的硬件接线图
我们对引脚的功能作一个简单的解释:
VCC,GND: 电源、地引脚
A2A1A0: 地址引脚
SCLK、SDA: 通信引脚
WP: 写保护引脚
从上面的电路连接知:A2A1A0=000,可见如果要对24c08进行写操作,寻址字节是1010 000 0;如果对24c08进行读操作,寻址字节是1010 000 1。用单片机的P3.4脚作为串行时钟线,用P3.5脚作串行数据线。
写过程:
(1)、主机首先发出开始信号
(2)、发出写24c08的寻址字节1010000 0,即0A0H
(3)、发数据写入24c08的地址,本例中为01H
(4)、往24c08中写入数据,这里是3个字节,分别为48h,0ebh,52h。
(5)、写完毕发出停止信号
读过程:
(1)、主机发出start信号
(2)、发写24c08的寻址字节1010000 0
(大家可能要问:我们是读数据,为什么要发写信号呢?这是因为你首先要送出一个信号,说明从24c08中的哪个地址读取数据。)
(3)、发要读取的数据在24c08中的地址,即01h
(4)、主机发start信号
(5)、发读24c08的寻址字节1010000 1
(5)、从24 C02中读取数据
(6)、读取完毕发出停止信号
5.实例演练
1) 实验目的
从地址0x00 开始连续写入16个数据(LED流水灯显示码),然后再从地址0x00 开始读出所写入的16个数据,由P0口的LED灯显示出来(先从右到左流,再从左到右流)。
2) 实验电路
3) 实验步骤
将JPLED P0跳线的跳线帽插好
不要插1602LCD 以免干扰P0口LED灯
4) 流程图
5) C语言源程序
通电后 数码管从00开始计数 每过1秒加1 直到99 计数。过程中你可以关闭电源,然后再开启电源,可以看到数值并没有从00开始计数,而是从你关闭电源前的数值开始,这证明我们通过24C08设计的断电记忆功能的计时器设计成功。按键K1键 可以使数值清零 清零后从00开始计数。
//24c08地址为0xa0
#include <reg52.h>
#define uchar unsigned char
unsigned char codetable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char sec=0; //定义计数值,每过1秒,sec加1
unsigned int count; //定时中断次数
bit write=0; //写24C08的标志;
sbit gewei=P2^7; //个位选通定义
sbit shiwei=P2^6; //十位选通定义
/////////24C08读写驱动程序////////////////////
sbit scl=P3^4; // 24c08 SCL
sbit sda=P3^5; // 24c08 SDA
sbit K5=P1^4; //清0按键
/***********************************************/
void delay() //delay 5us
{ ;; }
/**********************************************/
void delay1(uchar x)
{
uchar a,b;
for(a=x;a>0;a--)
for(b=100;b>0;b--);
}
/**********************************************/
void start() //开始信号
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
/************************************************/
void stop() //停止信号
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
/**************************************************/
void respons() //应答
{
uchar i;
scl=1;
delay();
while((sda==1)&&(i<250))i++;
scl=0;
delay();
}
/**************************************************/
void init_24c08() //初始化24C02
{
sda=1;
delay();
scl=1;
delay();
}
/************************************************/
void write_byte(uchar date)
{
uchari,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delay();
sda=CY;
delay();
scl=1;
delay();
// scl=0;
// delay();
}
scl=0;
delay();
sda=1;
delay();
}
/**********************************************/
uchar read_byte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
k=(k<<1)|sda;
scl=0;
delay();
}
return k;
}
/*****************************************************************/
void write_24c08(uchar address,uchar shuju) //给指定地址中写入数据
{
start();
write_byte(0xa0); // 最低位为0写,1读
respons();
write_byte(address);
respons();
write_byte(shuju);
respons();
stop();
}
/*****************************************************************/
uchar read_24c08(uchar address) //从24c08指定地址中读出数据
{
uchardate;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
returndate;
}
/////////////24C02读写驱动程序完/////////////////////
/***********************************************************/
void LEDshow() //LED显示函数
{
P0=table[sec/10];
shiwei=0;
delay1(40);
shiwei=1;
P0=table[sec%10];
gewei=0;
delay1(40);
gewei=1;
}
/***********************************************************/
void main(void)
{
TMOD=0x01;//定时器工作在方式1
ET0=1;
EA=1;
init_24c08();//初始化24C08
sec=read_24c08(2);//读出保存的数据赋于sec
TH0=(65536-50000)/256;//对TH0 TL0赋值
TL0=(65536-50000)%256;//使定时器0.05秒中断一次
TR0=1; //开始计时
while(1)
{
LEDshow();
if(write==1)//判断计时器是否计时一秒
{
write=0;//清零
write_24c08(2,sec);//在24c08的地址2中写入数据sec
}
if(K5==0){
delay1(10);
if(K5==0){
sec=0;
}
}
}
}
/**************************************************************/
void t0(void) interrupt 1 using 0 //定时中断服务函数
{
TH0=(65536-50000)/256;//对TH0 TL0赋值
TL0=(65536-50000)%256;//重装计数初值
count++;//每过50ms tcnt加一
if(count==20)//计满20次(1秒)时
{
count=0;//重新再计
sec++;
write=1;//1秒写一次24C08
if(sec==100)//定时100秒,在从零开始计时
{sec=0;}
}
}
6 拓展训练
1)用24C08与1602LCD设计电子密码锁
2)12864LCD显示24C08保存的开机画面。即运行时,单片机程序从24C08中读取该画面并显示在12864LCD液晶显示屏上。
|