一.概述
24系列I2C串行总线EEPROM芯片应用非常广泛,在51单片机控制系统中如影随形。24系列EEPROM可重复擦写100万次,数据可以掉电保存100年不变,有1K位、2K位、4K位、8K位等存储容量的系列产品,24C01就是其中的1K位容量的产品。
I2C串行总线是Philips公司推出的一种双向二线制通信总线,由一条数据线和一条时钟线组成,主要应用于芯片之间的通信。支持I2C总线接口的芯片非常多,所以学习单片机一定要掌握I2C总线协议。51单片机本身并不带I2C总线接口,要想访问I2C接口芯片,只有通过软件模拟实现。51单片机IO口操作简单,软件模拟I2C总线轻而易取。
二.电路设计
在WSF-51DB开发板上,利用AT89S52单片机的P0.3、P0.4、P0.5来驱动AT24C01,P0口的上拉排阻为4.7K欧姆。需要注意的是AT24C01的SDA管脚是漏极开路,所以一定要在这个管脚上接一个上拉电阻,阻值在2K-10K欧姆范围内选择,传输速率越高,阻值应当越小。
三.软件设计
/*****************************************************************
*程序名称:24C01驱动
*程序功能:写人8个数据,再读出来,放在P2口显示。
*开发工具:WSF-51DB开发板
* MCU型号:AT89S52-24PU
*时钟频率:12MHZ
*****************************************************************/
#include<reg52.h>
unsigned char code dat[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//写入24C01的数据
sbit wp=P0^3;//写保护
sbit scl=P0^4;//时钟线
sbit sda=P0^5;//数据线
//延时15us函数:
void Delayus()
{
unsigned char i;
for(i=5;i>0;i--);
}
//延时1ms函数:
void Delayms(unsigned int t)
{
unsigned int x,y;
for(x=t;x>0;x--)
for(y=120;y>0;y--);
}
//起始信号函数:
void Start(void)
{
sda=1;//时序要就很严格
scl=1;
Delayus();
sda=0;
scl=0;
}
//停止信号函数:
void Stop(void)
{
scl=0;//时序要就很严格
sda=0;
Delayus();
scl=1;
sda=1;
}
//应答信号函数:
void ACK(void)
{
sda=1;//先释放总线
scl=1;//启动应答时钟(第九个脉冲)
Delayus();//器件发出应答信号(sda被拉低)
scl=0;
Delayus();//等待应答脉冲变高后结束应答
}
//写字节函数:
void Write24c01Byte(unsigned char wbyte)
{
unsigned char i;
for(i=0;i<8;i++)
{
sda=(wbyte&0x80)?1:0;//从高到低逐位写数据,
Delayus();
scl=1;
Delayus();
scl=0;
Delayus();
wbyte<<=1;
}
}
//读数据函数:
unsigned char Read24c01Byte(void)
{
unsigned char i,rbyte;
for(i=0;i<8;i++)
{
rbyte<<=1;
scl=1;
Delayus();
if(sda==1) rbyte|=0x01;//逐位读取数据
else rbyte&=(~0x01);
scl=0;
Delayus();
}
return rbyte;
}
//字节模式写数据函数:
void Write24c01ByteData(unsigned char waddr, unsigned char wdata)
{
Start();
Write24c01Byte(0xa0);//器件地址1010000+写(0)
ACK();
Write24c01Byte(waddr);//写地址
ACK();
Write24c01Byte(wdata);//写数据
ACK();
Stop();
Delayms(1);//写延时,最大5毫秒
}
//页模式写数据函数:
void Write24c01PageData(unsigned char saddr,unsigned char *pd,unsigned char num)
//saddr---页起始地址;pd---指针;nun---字节个数,不能大于一页的字节数
{
unsigned char i;
Start();
Write24c01Byte(0xa0);//器件地址1010000+写(0)
ACK();
Write24c01Byte(saddr);//写页起始地址,24C01一页8个字节,共16页
ACK();
for(i=0;i<num;i++)//在一页范围内连续写多个字节
{
Write24c01Byte(*pd++);//写数据
ACK();
}
Stop();
}
//读数据函数:
unsigned char Read24c01Data(unsigned char raddr)
{
unsigned char rdat;
Start();
Write24c01Byte(0xa0);//器件地址+写(0)
ACK();
Write24c01Byte(raddr);//写数据存放地址
ACK();
Start();
Write24c01Byte(0xa1);//器件地址1010000+读(1)
ACK();
rdat=Read24c01Byte();
Stop();
return rdat;
}
//主函数:
int main(void)
{
unsigned char i;
wp=0;//写使能
//for(i=0;i<8;i++)
// Write24c01ByteData(i,datacode);//字节模式从0地址开始写入8个数据
Write24c01PageData(0,dat,8);//页模式从0地址开始写入8个数据
while(1)
{
for(i=0;i<8;i++)
{
P2=Read24c01Data(i);//从0地址开始读出数据,点亮P2口的8个LED
Delayms(500);
}
}
return 0;
}