C51单片机之AT24C02实验.docx
《C51单片机之AT24C02实验.docx》由会员分享,可在线阅读,更多相关《C51单片机之AT24C02实验.docx(23页珍藏版)》请在冰豆网上搜索。
C51单片机之AT24C02实验
实验十基于MCS-51单片机的存储器AT24C02读写实验
一、支撑课程目标
目标1:
掌握微机和单片机的基本原理、编程技术、中断技术、系统扩展、定时器、串行接口和其他输入/输出接口技术,并且了解典型的单片机应用系统的设计思想和实现方法。
目标2:
初步具备自行拟定实验步骤、检查和故障排除、分析和综合实验结果以及撰写实验报告的能力。
目标3:
综合应用单片机原理及接口等知识、软硬件设计与仿真平台来对电子信息系统中的复杂工程问题进行独立分析、并设计和调试相应微机和单片机的应用系统。
目标4:
掌握MCS-51单片机/STM32F103单片机系统仿真工具和仿真流程,了解常用实验仪器、设备的基本工作原理,了解其正确使用方法,具备利用电子仪器设备和专业仿真软件对复杂工程问题进行分析和设计的能力。
二、实验类型:
验证型()、设计型(√)、研究创新型()
三、预期学生学习的成果
1、理解典型的串行同步通讯协议。
2、理解IIC串行同步通讯协议及对应时序。
3、理解AT24C02铁电存储器内部结构及存取工作原理。
4、掌握AT24C02接口电路及时序编程存取。
5、掌握模块化编程方法。
四、实验原理
1、IIC总线特点
、可最大限度地简化结构,二线制的IIC串行总线使得各电路单元之间只需最简单的2线连接,而且总线接口都已集成在器件中,不需另加总线接口电路,这样减少电路板面积,提高了可靠性,降低了成本。
、可实现电路系统的模块化、标准化设计。
在IIC总线上各单元电路相互之间没有其它连线,常用的单元电路基本上与系统电路无关,故极易形成用户自己的标准化、模块化设计。
、IIC总线各节点具有独立的电气特性,各节点单元电路能在相互不受影响的情况下,甚至在系统供电情况下接入或撤出,且系统可方便地对某一节点电路进行故障诊断与跟踪,有极好的可维护性。
、IIC总线系统构成具有最大的灵活性、系统改型设计、或对已加工好的电路板需扩展功能时,对原有设计及电路板系统影响最小,同时标准IIC总线模块的组合开发大大地缩短了新品的开发周期。
2、IIC总线协议
IIC总线通过2根线——串行数据(SDA)和串行时钟(SCL)线连接到总线上的任何一个器件,每个器件都应有一个唯一的地址,而且都可以作为一个发送器或接收器。
器件在执行数据传输时也可以被看作是主机或从机。
发送器:
本次传送中发送数据(不包括地址和命令)到总线的器件。
接收器:
本次传送中从总线接收数据(不包括地址和命令)的器件。
主机:
初始化发送、产生时钟信号和终止发送的器件,它可以是发送器或接收器,主机通常是微控制器。
从机:
被主机寻址的器件,它可以是发送器或接收器。
IIC总线是一个多主机的总线,也即可以连接多于一个能控制总线的器件到总线。
当2个以上能控制总线的器件同时发动传输时,只能有一个器件能真正控制总线而成为主机,并使报文并不被破坏,这个过程叫做仲裁。
与此同时,能使多个能控制总线的器件产生时钟信号的同步。
SDA和SCL都是双向线路,连接到总线的器件的输出级必须是漏极开路或集电极开路,都通过一个电流源或上拉电阻连接到正的电源电压,这样才能够实现“线与”功能。
当总线空闲时,这2条线路都是高电平。
在标准模式下,数据传输的速度为0~100Kbit/s。
(1)、位传输
IIC总线上每传输一个数据位必须产生一个时钟脉冲。
、数据的有效性
SDA线上的数据必须在时钟线SCL的高电平周期保持稳定,数据线的电平状态只有在SCL线的时钟信号是低电平时才能改变,如图1所示。
在标准模式下,高低电平宽度必须不小于4.7纳秒。
图1IIC总线位传输
、起始和停止条件
在IIC总线中,唯一违反上述数据有效性的起始(S)和停止(P)条件,如图2,起始条件(重复起始条件):
SCL线是高电平时,SDA线从高电平向低电平切换。
停止条件:
SCL线是高电平时,SDA线由低电平向高电平切换。
起始和停止条件一般由主机产生。
起始条件作为一次传送的开始,在起始条件后总线被认为处于忙的状态。
停止条件作为一次传送的结束,在停止条件的某段时间后,总线被认为再次处于空闲状态。
重复起始条件既作为上次传送的结束,也作为下次传送的开始。
图2起始和终止时序
(2)、数据传输
、字节格式
发送到SDA线上的每个字节必须为8位。
每次传输可以发送的字节数量不受限制。
每个字节后必须跟一个应答位。
首先传输的是数据的最高位(MSB),见图3所示。
图3IIC总线的数据传输
、应答
相应的应答时钟脉冲由从机产生。
在应答的时钟脉冲期间,发送器释放SDA线(高)。
在应答的时钟脉冲期间,接收器必须将SDA线拉低,使她在这个时钟脉冲的高电平期间保持稳定的低电平。
如图3中时钟信号SCL的第9位。
一般说来,被寻址匹配的从机或可继续接收下一字节的接收器将产生一个应答。
若作为发送器的主机在发送完一个字节后,没有收到应答位(或收到一个非应答位),或作为接收器的主机没有发送应答位(或发送一个非应答位),那么主机必须产生一个停止条件或重复起始条件来结束本次传输。
若从机—接收器不能接收更多的数据字节,将不产生这个应答位:
主机—接收器在接收完最后一个字节后不产生应答,通知从机—发送器数据结束。
3、AT24C02介绍
AT24C02是美国Atmel公司的低功耗CMOS型E2PROM,内含256*8位存储空间,具有工作电压宽(2.5V~5.5V),擦写次数多(大于10000次),写入速度快(小于10ms),抗干扰能力强,数据不易丢失,体积小等特点。
并且它是采用IIC总线式进行数据读写的串行操作,只占用很少的资源和I/O线。
AT24C02有一个16字节页写缓冲器,该器件通过IIC总线接口进行操作,还有一个专门的写保护功能。
AT24C02的引脚如图4,各引脚功能如下:
SCL:
串行时钟输入管脚,用于产生器件所有数据发送或接收的时钟。
SDA:
双向串行数据/地址管脚,用于器件所有数据的发送或接收。
A0、A1、A2:
器件地址输入端。
这些输入脚用于多个器件级联时设置器件地址,当这些脚悬空时默认值为0。
使用AT24C02最大可级联8个器件,如果只有一个24C02被总线寻址,这三个地址输入脚A0、A1、A2可悬空或连接到VSS。
WP:
写保护。
如果WP管脚连接到Vcc,所有的内容都被写保护,只能读。
当WP管脚连接到Vss或悬空,允许器件进行正常的读/写操作。
VSS:
电源地(GND)。
VCC:
电源电压(5V)。
五、实验内容及步骤
(一)实验内容
1、AT24C02存取实验:
将特定字符串写入AT24C02存储器,并读出来显示在串口驱动的数码管上。
2、编写程序,连接导线,下载程序代码,调试完成AT24C02的写入和读取、数码管显示实验。
(二)实验步骤
、AT24C02存取实验:
将特定字符串写入AT24C02存储器,并读出来显示在串口驱动的数码管上,原理图见下。
图6AT24C02实验原理图
实验步骤:
1、实验连线
1)串行存储器(E²PROM)区SDA_02连接P3.1,SCL_02连接P3.0;
2)串行键盘显示接口区的SDA_04连接P3.1,SCL_04连接P3.0;
3)串行键盘显示接口区BIT连数码管显示区的BIT,DU(seg0-seg7)连到数码管显示区的DU(a-h),P1.0接单脉冲单元的SP(也可以接固定脉冲的1HZ)。
2、调试运行程序工程中的24C02.hex。
3、查看运行结果
致。
NCBIT0-KBIT4右边上观察数码管上显示的内容与写入的内容是否一致,每按一次单脉冲按键数字变化一次,顺序显示为24C02o55~24C02o5C,见图7。
六、实验结果
(1)AT24C02程序以及实验结果
●Keil
●实验箱
“24C02o55”
“24C02o5C”
七、实验分析
AT24C02的存储容量为2Kbit,内容分成32页,每页8Byte,共256Byte,操作时有两种寻址方式:
芯片寻址和片内子地址寻址。
(1)芯片寻址:
AT24C02的芯片地址为1010,其地址控制字格式为1010A2A1A0R/W。
其中A2,A1,A0可编程地址选择位。
A2,A1,A0引脚接高、低电平后得到确定的三位编码,与1010形成7位编码,即为该器件的地址码。
R/W为芯片读写控制位,该位为0,表示芯片进行写操作。
(2)片内子地址寻址:
芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。
IIC总线各节点具有独立的电气特性,各节点单元电路能在相互不受影响的情况下,甚至在系统供电情况下接入或撤出。
IIC总线上可以挂多个器件,而每个器件都有唯一的地址,这样可以标识通信目标。
数据的通信的方式采用主从方式,主机负责主动联系从机,而从机则被动回应数据。
向AT24C02写数据步骤:
第1步:
发送开始信号,IIC启动;
第2步:
发送器件地址,其中读写标志位为写;
第3步:
IIC应答信号;
第4步:
发送器件内部存储地址;
第5步:
IIC应答信号;
第6步:
向器件中写入数据;
第7步:
IIC应答信号;
第8步:
发送停止信号,IIC停止
数据遵循“起始、寻址、指定页写首地址、连续写入一页数据、停止”的过程。
为了实现连续存数据每发送一个字节数据之后AT24C02芯片都会产生一个从机应答并将字节地址低位自动加1,高位保持不变烧入程序后,烧入程序后,观察数码管上显示的内容与写入的内容是否一致,每按一次单脉冲按键数字变化一次,顺序显示为24C02o55~24C02o5C。
可以改变main函数的temp的初始数据,使得数码显示器同步改变。
代码
#include
#include
#include
#defineucharunsignedchar/*宏定义*/
#defineuintunsignedint
#define_Nop()_nop_()/*定义空指令*/
/*常,变量定义区*/
#defineEEROM020x0a0
#defineZLG72900x70
/*端口位定义*/
sbitSDA=P3^1;/*模拟I2C数据传送位*/
sbitSCL=P3^0;/*模拟I2C时钟控制位*/
sbitp1_0=P1^0;/*状态标志*/
bitack;/*应答标志位*/
voiddelay(unsignedchari);
voidDISP(void);
voidStart_I2c(void);
voidStop_I2c(void);
voidSendByte(ucharc);
unsignedcharRcvByte(void);
voidAck_I2c(bita);
bitISendStr(ucharsla,ucharsuba,uchar*s,ucharno);
bitIRcvStr(ucharsla,ucharsuba,uchar*s,ucharno);
unsignedcharSLA,SUBA,NUMBYTE,MTD[16],MRD[16],i,j,//SLA器件从地址,SUBA器件子地址
temp,buffer[8];
voidmain(void)
{
temp=0x51;//初始数据
for(i=0;i<8;i++)
{
MTD[i]=temp;//写入发送缓冲
temp++;
}
SLA=EEROM02;
SUBA=0x00;
NUMBYTE=0x08;
ISendStr(SLA,SUBA,MTD,NUMBYTE);//写入8个数据
delay(10);
temp=0x5d;//再写入8个
for(i=8;i<16;i++)
{
MTD[i]=temp;
temp++;
}
SLA=EEROM02;
SUBA=0x08;
NUMBYTE=0x08;
ISendStr(SLA,SUBA,MTD,NUMBYTE);
delay(10);
SLA=EEROM02;
SUBA=0x00;
NUMBYTE=0x08;
IRcvStr(SLA,SUBA,MRD,NUMBYTE);//读入数据
delay(10);
SLA=EEROM02;
SUBA=0x08;
NUMBYTE=0x08;
IRcvStr(SLA,SUBA,MRD+8,NUMBYTE);
delay(10);
buffer[2]=0x15;
buffer[3]=0x02;
buffer[4]=0x00;
buffer[5]=0x0c;
buffer[6]=0x04;
buffer[7]=0x02;//24C02-XX
j=0;
for(i=0x10;i>0;i--)
{
buffer[0]=*(MRD+j)&0x0f;
buffer[1]=(*(MRD+j)>>4)&0x0f;
j++;
DISP();
delay(10);
while(p1_0==1){;}
while(p1_0==0){;}
}
}
//******显示子程序******ZLG7290*******************
voidDISP(void)
{unsignedchari,j,Data[2];
Data[0]=0x60;
Data[1]=buffer[i];
j=0x60;
for(i=0;i<8;i++)
{
Data[0]=j;
Data[1]=buffer[i];
j++;
SLA=ZLG7290;
SUBA=0x07;
NUMBYTE=0x02;
ISendStr(SLA,SUBA,Data,NUMBYTE);
}
}
/*******************************************************************
起动总线函数
函数原型:
voidStart_I2c();
功能:
启动I2C总线,即发送I2C起始条件.
********************************************************************/
voidStart_I2c(void)
{
SDA=1;/*发送起始条件的数据信号*/
_Nop();
SCL=1;
_Nop();/*起始条件建立时间大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0;/*发送起始信号*/
_Nop();/*起始条件锁定时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0;/*钳住I2C总线,准备发送或接收数据*/
_Nop();
_Nop();
}
/*******************************************************************
结束总线函数
函数原型:
voidStop_I2c();
功能:
结束I2C总线,即发送I2C结束条件.
********************************************************************/
voidStop_I2c(void)
{
SDA=0;/*发送结束条件的数据信号*/
_Nop();/*发送结束条件的时钟信号*/
SCL=1;/*结束条件建立时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1;/*发送I2C总线结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
字节数据传送函数
函数原型:
voidSendByte(ucharc);
功能:
将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0假)
发送数据正常,ack=1;ack=0表示被控器无应答或损坏。
********************************************************************/
voidSendByte(ucharc)
{
ucharBitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++)/*要传送的数据长度为8位*/
{
if((c<elseSDA=0;
_Nop();
SCL=1;/*置时钟线为高,通知被控器开始接收数据位*/
_Nop();
_Nop();/*保证时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1;/*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
elseack=1;/*判断是否接收到应答信号*/
SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字节数据传送函数
函数原型:
ucharRcvByte();
功能:
用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
ucharRcvByte()
{
ucharretc;
ucharBitCnt;
retc=0;
SDA=1;/*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0;/*置时钟线为低,准备接收数据位*/
_Nop();
_Nop();/*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=1;/*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1;/*读数据位,接收的数据位放入retc中*/
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
应答子函数
原型:
voidAck_I2c(bita);
功能:
主控器进行应答信号,(可以是应答或非应答信号)
********************************************************************/
voidAck_I2c(bita)
{
if(a==0)SDA=0;/*在此发出应答或非应答信号*/
elseSDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();/*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;/*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();
}
/*******************************************************************
向有子地址器件发送多字节数据函数
函数原型:
bitISendStr(ucharsla,ucharsuba,ucahr*s,ucharno);
功能:
从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意:
使用前必须已结束总线。
********************************************************************/
bitISendStr(ucharsla,ucharsuba,uchar*s,ucharno)
{
uchari;
Start_I2c();/*启动总线*/
SendByte(sla);/*发送器件地址*/
if(ack==0)return(0);
SendByte(suba);/*发送器件子地址*/
if(ack==0)return(0);
for(i=0;i{
SendByte(*s);/*发送数据*/
if(ack==0)return(0);
s++;
}
Stop_I2c();/*结束总线*/
return
(1);
}
/*******************************************************************
向有子地址器件读取多字节数据函数
函数原型:
bitISendStr(ucharsla,ucharsuba,ucahr*s,ucharno);
功能:
从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否则操作有误。
注意:
使用前必须已结束总线。
********************************************************************/
bitIRcvStr(ucharsla,ucharsuba,uchar*s,ucharno)
{
uchari;
Start_I2c();/*启动总线*/
SendByte(sla);/*发送器件地址*/
if(ack==0)return(0);
SendByte(suba);