EEPROM
IIC串行总线的组成及工作原理
I2C总线的数据传送
- 数据位的有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
- 起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
-
数据传送格式
字节传送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
数据帧格式
在总线的一次数据传送过程中,可以有以下几种组合方式:
主机向从机发送数据,数据传送方向在整个传送过程中不变:
主机在第一个字节后,立即从从机读数据:
在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。
-
总线的寻址
I2C总线协议有明确的规定:采用7位的寻址字节(寻址字节是起始信号后的第一个字节)。
寻址字节的位定义
主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主机寻址,根据R/T位将自己确定为发送器或接收器。
从机的地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机的7位寻址位有4位是固定位,3位是可编程位,这时仅能寻址8个同样的器件,即可以有8个同样的器件接入到该I2C总线系统中。
典型信号模拟
串行E2PROM的扩展
写入过程
单片机进行写操作时,首先发送该器件的7位地址码和写方向位“0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为相应,单片机收到应答后就可以传送数据了。传送数据时,单片机首先发送一个字节的被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各数据字节,但每发送一个字节后都要等待应答。当要写入的数据传送完后,单片机应发出终止信号以结束写入操作。写入n个字节的数据格式 :
读出过程
单片机先发送该器件的7位地址码和写方向位“0”(“伪写”),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为回应。然后,再发一个字节的要读出器件的存储区的首地址,收到应答后,单片机要重复一次起始信号并发出器件地址和读方向位(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,单片机都要回复应答信号。当最后一个字节数据读完后,单片机应返回以“非应答”(高电平),并发出终止信号以结束读出操作。
AT24CXX存储器工作原理
实验代码
i2c.h
#ifndef _I2C_H
#define _I2C_H
#include "reg52.h"
sbit SCL=P2^1;
sbit SDA=P2^0;
void At24c02Write(unsigned char addr, unsigned char dat);
unsigned char At24c02Read(unsigned char addr);
#endif
i2c.c
#include "i2c.h"
void Delay10us(void)
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void I2cStart()
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();
SDA=0;
Delay10us();
SCL=0;
Delay10us();
}
void I2cStop()
{
SDA=0;
Delay10us();
SCL=1;
Delay10us();
SDA=1;
Delay10us();
}
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a;
unsigned char t=1;
unsigned char b=1;
for(a=0;a<8;a++)
{
SDA=dat>>7;
dat<<=1;
Delay10us();
SCL=1;
Delay10us();
SCL=0;
Delay10us();
}
SDA=1;
Delay10us();
SCL=1;
Delay10us();
while(SDA)
{
b++;
if(b>200)
{
SCL=0;
Delay10us();
t=0;
return b;
}
}
SCL=0;
Delay10us();
return t;
}
unsigned char I2cReadByte()
{
unsigned char a=0,dat=0;
SDA=1;
Delay10us();
for(a=0;a<8;a++)
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
return dat;
}
void At24c02Write(unsigned char addr, unsigned char dat)
{
I2cStart();
I2cSendByte(0xA0);
I2cSendByte(addr);
I2cSendByte(dat);
I2cStop();
}
unsigned char At24c02Read(unsigned char addr)
{
unsigned char num;
I2cStart();
I2cSendByte(0xA0);
I2cSendByte(addr);
I2cStart();
I2cSendByte(0xA1);
num=I2cReadByte();
I2cStop();
return num;
}
main.c
#include "reg52.h"
#include "i2c.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
u8 num=0;
u8 disp[4];
void delay(u16 i)
{
while(i--);
}
void datapros()
{
disp[0]=smgduan[num/1000];
disp[1]=smgduan[num/100%10];
disp[2]=smgduan[num/10%100%10];
disp[3]=smgduan[num%1000%100%10];
}
void Keypros()
{
if(k1==0)
{
delay(1000);
if(k1==0)
{
At24c02Write(1,num);
}
while(!k1);
}
if(k2==0)
{
delay(1000);
if(k2==0)
{
num=At24c02Read(1);
}
while(!k2);
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
num++;
if(num>255)
{
num=0;
}
}
while(!k3);
}
if(k4==0)
{
delay(1000);
if(k4==0)
{
num=0;
}
while(!k4);
}
}
void DigDisplay()
{
u8 i;
for(i=0;i<4;i++)
{
switch(i)
{
case(0):
LSA=0;LSB=0;LSC=0;break;
case(1):
LSA=1;LSB=0;LSC=0;break;
case(2):
LSA=0;LSB=1;LSC=0;break;
case(3):
LSA=1;LSB=1;LSC=0;break;
}
P0=disp[3-i];
delay(100);
P0=0x00;
}
}
void main(){
while(1)
{
Keypros();
datapros();
DigDisplay();
}
}