I2C存储器实验.docx
《I2C存储器实验.docx》由会员分享,可在线阅读,更多相关《I2C存储器实验.docx(30页珍藏版)》请在冰点文库上搜索。
![I2C存储器实验.docx](https://file1.bingdoc.com/fileroot1/2023-5/8/2a91ee0f-1221-4f07-9304-87088e3430ad/2a91ee0f-1221-4f07-9304-87088e3430ad1.gif)
I2C存储器实验
微机原理与接口技术实验报告
实验名称:
I2C存储器实验
班级:
姓名:
学号:
实验日期:
成绩:
I2C存储器实验
实验目的
1、了解I2C总线的工作原理
2、掌握I2C总线驱动程序的设计和调试方法
3、掌握I2C总线存储器的读写方法
实验仪器
单片机开发板、万利仿真机、稳压电源、计算机
实验原理
1、I2C总线常识
I2C总线采用一个双线式漏极开路接口,可在一根总线上支持多个器件和主控器。
所连接的器件只会把总线拉至低电平,而决不会将其驱动至高电平。
总线在外部通过一个电流源或上拉电阻器连接至一个正电源电压。
当总线空闲时,两条线路均为高电平。
在标准模式中,I2C总线上的数据传输速率高达100kbit/s,而在快速模式中则高达400kbit/s。
I2C总线上的每个器件均由一个存储于该器件中的唯一地址来识别,并可被用作一个发送器或接收器(视其功能而定)。
除了发送器和接收器之外,在执行数据传输时,还可把器件视作主控器或受控器。
主控器是负责启动总线上的数据传输并生成时钟信号以允许执行该传输的器件。
同时,任何被寻址的器件均被视作受控器。
CAT24WC01/02/04/08/16是一个1K/2K/4K/8K/16K位串行CMOSEEPROM,内部含有128/256/512/1024/2048个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗,CAT24WC01有一个8字节页写缓冲器,CAT24WC02/04/08/16有一个16字节页写缓冲器,该器件通过I2C总线接口进行操作,有一个专门的写保护功能,并且器件能与400KHzI2C总线兼容。
引脚名称和功能如图4-64所示。
图4-6424系例I2C存储器引脚说明
通过器件地址输入端A0、A1和A2可以实现将最多8个24WC01和24WC02器件4个24WC04器件,2个24WC08器件和1个24WC16器件连接到总线上。
2、I2C总线协议
(1)只有在总线空闲时才允许启动数据传送。
(2)在数据传送过程中,当时钟线为高电平时,数据线必须保持稳定状态,不允许有跳变。
时钟线为高电平时,数据线的任何电平变化将被看作总线的起始或停止信号。
(3)起始信号
时钟线保持高电平期间,数据线电平从高到低的跳变作为I2C总线的起始信号。
(4)停止信号
时钟线保持高电平期间,数据线电平从低到高的跳变作为I2C总线的停止信号。
I2C总线时序:
图4-65I2C总线时序图
I2C总线启动停止信号波形:
SCL为高电平,SDA降沿为启动信号;SCL为高电平,SDA上升沿为停止信号。
图4-66I2C总线启动停止信号
I2C总线写周期波形:
SCL正脉冲锁存数据,或SCL为高电平数据有效。
SCL高电平期间SDA数据应保持不变。
图4-67I2C总线写时序波形
I2C总线应答信号波形:
I2C总线数据传送时,每成功地传送一个字节数据后,接收器都必须产生一个应答信号。
应答的器件在第9个时钟周期时将SDA线拉低,表示其已收到一个8位数据。
图4-68I2C总线读时序
3、24C系列存储器读写操作
(1)24系列常用存储器器件地址安排
图4-6924系例存储器器件地址安排
(2)字节写操作
在字节写模式下,主器件发送起始命令和从器件地址信息(R/W位置零)给从器件,在从器件产生应答信号后,主器件发送CAT24WC01/02/04/08/16的1字节地址(存储容量大的存储器字节地址两字节),主器件在收到从器件的另一个应答信号后,再发送数据到被寻址的存储单元。
CAT24WC01/02/04/08/16再次应答,并在主器件产生停止信号后,开始内部数据的擦写,在内部擦写过程中从器件不再应答主器件的任何请求(10ms)。
如图4-70所示。
图4-70字节写操作数据帧结构
(3)页写操作(提高写入速度)
根据页缓冲区的大小,页写的字节数不能超过缓冲区大小。
如果在发送停止信号之前主器件发送超过缓冲区大小,地址计数器将自动翻转,先前写入的数据被覆盖。
如图4-71所示。
图4-71页写操作数据帧结构
(4)当前地址读操作
当读取一个字节数据后,存储器内部地址计数器加1。
当读到最后一字节时,计数器将翻转到0且继续输出数据。
CAT24WC01/02/04/08/16接收到从器件地址信号后(R/W位置1),它首先发送一个应答信号,然后发送一个8位字节数据。
主器件产生一个非应答信号(这里是主器件发送的非应答信号),再产生一个停止信号。
如图4-72所示。
图4-72当前地址读操作数据帧结构
(5)任意地址读操作、连续读操作
图4-73任意地址读、连续读操作数据帧结构
4、I2C总线存储读写程序设计
I2C总线存储器读写程序分为两层:
硬件接口程序和存储器读写程序。
其中硬件接口程序有:
总线启动、停止、发数据、收数据、发响应、发非响应、读从器件响应状态等。
存储器读写程序有:
单字节写数据、页写数据、当前地址读数据、任意地址读数据、连续读数据等。
参考上面的时序图设计硬件接口相关子程序。
图4-74I2C总线接口程序流程图
图4-75I2C总线数据读写流程图
存储器读写程序设计。
这里以单字节读、写程序为例说明,其它子程序由读者自行设计。
图4-76I2C存储器单字节读写流程图
实验内容
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
#definedata1000
sbitLEDDIN=P2^3;
sbitLEDCLK=P3^4;
ucharcodetable[]={0x03,0x9f};
ucharWR1,RD1;
#defineNOP3()_nop_();_nop_();_nop_()
sbitSDA=P3^7;//串行数据/地址控制端
sbitSCL=P3^6;//串行时钟
/************************************************
延时函数
*功能:
可随意设置延时时间,延时时间为ttms.晶振为12MHz
*************************************************/
voiddelay1ms(unsignedinttms)
{
unsignedchari;
while(tms--)
for(i=123;i>0;i--)
;
}
/******************************************
启动I2C总线函数
******************************************/
voidStart()
{
SCL=1;
SDA=1;
NOP3();
SDA=0;
NOP3();
SCL=0;
}
/******************************************
I2C停止
******************************************/
voidStop()
{
SDA=0;
SCL=1;
NOP3();
SDA=1;
NOP3();
}
/******************************************
I2C应答检测函数
******************************************/
voidI2C_ACK()
{
SDA=0;
NOP3();
SCL=1;
NOP3();
SCL=0;
NOP3();
SDA=1;
}
/******************************************
I2C非应答检测函数
******************************************/
voidI2C_NACK()
{
SDA=1;
NOP3();
SCL=1;
NOP3();
SCL=0;
NOP3();
SDA=0;
}
/******************************************
I2C初始化
******************************************/
voidInit_24cxx()
{
SDA=1;
NOP3();
SCL=1;
NOP3();
}
/******************************************
读I2C函数
******************************************/
ucharI2C_Read()
{
uchari,temp;
temp=0;
SDA=1;
SCL=0;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=1;
NOP3();
if(SDA==1)
{
temp=temp+1;
}
NOP3();
SCL=0;
}
returntemp;
}
/******************************************
写I2C函数
******************************************/
I2C_Write(uchardate1)
{
uchari,temp;
temp=date1;
SCL=0;
for(i=0;i<8;i++)
{
SDA=(bit)(temp&0x80);
SCL=1;
NOP3();
SCL=0;
temp=temp<<1;
}
NOP3();
}
/******************************************
写相应地址的数据
******************************************/
voidWrite_add(uintaddress,uchardate1)
{
ucharaddrh,addrl;
addrh=address>>8;
addrl=address%256;
EA=0;
Start();
I2C_Write(0xa0);//发送命令字+芯片编号+P0+W
I2C_ACK();
I2C_Write(addrh);//发高位地址
I2C_ACK();
I2C_Write(addrl);//发低位地址
I2C_ACK();
I2C_Write(date1);//发送数据
I2C_ACK();
Stop();//停止
EA=1;
}
/******************************************
读相应地址的数据
******************************************/
ucharRead_add(uintaddress)
{
ucharaddrh,addrl,temp;
addrh=address>>8;
addrl=address%256;
EA=0;
Start();
I2C_Write(0xa0);//发送命令字+芯片编号+P0+W
I2C_ACK();
I2C_Write(addrh);//发高位地址
I2C_ACK();
I2C_Write(addrl);//发低位地址
I2C_ACK();
Start();
I2C_Write(0xa1);//发送命令字+芯片编号+P0+R
I2C_ACK();
temp=I2C_Read();
I2C_NACK();
Stop();
EA=1;
returntemp;
}
/******************************************
主函数
******************************************/
main()
{
uchari;
//temp=0;
for(i=0;i<7;i++)
{
LEDCLK=1;
LEDDIN=0;
NOP3();
LEDCLK=0;
}
LEDCLK=0;
LEDDIN=1;
NOP3();
LEDCLK=1;
Init_24cxx();
WR1=0X00;
RD1=0x00;
while
(1)
{
Write_add(0x0004,WR1);
delay1ms(500);
RD1=Read_add(0X0004);
P0=table[RD1];
delay1ms(500);
}
}
实验显示结果
思考题
1、请说说I2C总线的优点有哪些?
答:
低电流、低功耗,元件价格低廉,硬件写保护,时钟和信号用电平触发,具有高抗噪声输入浪涌滤波器,时钟包含100KHZ和200KHZ两种模式。
只要求两条总线线路:
一条串行数据线SDA,一条串行时钟线SCL;每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器;它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可400kbit/s,高速模式下可达3.4Mbit/s;连接到相同总线的IC数量只受到总线的最大电容400pF限制。
2、编写页写操作子程序。
/*******************************************************************
字节数据发送函数
函数原型:
voidSendByte(UCHARc);
功能:
将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0)
发送数据正常,ack=1;ack=0表示被控器无应答或损坏。
********************************************************************/
voidSendByte(unsignedcharc)
{
unsignedcharBitCnt;
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();
功能:
用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数应答从机。
********************************************************************/
unsignedcharRcvByte()
{
unsignedcharretc;
unsignedcharBitCnt;
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);
}
3、在连续读操作到最后一个数据时,主机如果发送响应信号,会出现什么情况?
答:
在连续读操作到最后一个数据时,主机如果发送响应信号,结束接收。
4.编写一段程序,使输入输出都是显示自己的学号。
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
#definedata5000
sbitLEDDIN=P2^3;
sbitLEDCLK=P3^4;
ucharcodeDisp_Tab[]={0x03,/*0*/0x9F,/*1*/0x25,/*2*/0x0D,/*3*/0x99,/*4*/0x49,/*5*/
0x41,/*6*/0x1F,/*7*/0x01,/*8*/0x09,/*9*/0x11,/*A*/0xC1,/*b*/0x63,/*C*/
0x85,/*d*/0x61,/*E*/0x71/*F*/,0XFD/*-*/};
uchardispbuf[8];
ucharWR1,RD1;
#defineNOP3()_nop_();_nop_();_nop_()
sbitSDA=P3^7;//串行数据/地址控制端
sbitSCL=P3^6;//串行时钟
/************************************************
延时函数
*功能:
可随意设置延时时间,延时时间为ttms.晶振为12MHz
*************************************************/
voiddelay1ms(unsignedinttms)
{
unsignedchari;
while(tms--)
for(i=123;i>0;i--)
;
}
/******************************************
启动I2C总线函数
******************************************/
voidStart()
{
SDA=1;
SCL=1;
NOP3();
SDA=0;
NOP3();
SCL=0;
}
/******************************************
I2C停止
******************************************/
voidStop()
{
SDA=0;
SCL=1;
NOP3();
SDA=1;
NOP3();
}
/******************************************
I2C应答检测函数
******************************************/
voidI2C_ACK()
{
SDA=0;
NOP3();
SCL=1;
NOP3();
SCL=0;
NOP3();
SDA=1;
}
/******************************************
I2C非应答检测函数
******************************************/
voidI2C_NACK()
{
SDA=1;
NOP3();
SCL=1;
NOP3();
SCL=0;
NOP3();
SDA=0;
}
/******************************************
I2C初始化
******************************************/
voidInit_24cxx()
{
SDA=1;
NOP3();
SCL=1;
NOP3();
}
/******************************************
读I2C函数
******************************************/
ucharI2C_Read()
{
uchari,temp;
SDA=1;
SCL=0;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=1;
NOP3();
if(SDA==1)
{
temp++;
}
NOP3();
SCL=0;
}
returntemp;
}
/******************************************
写I2C函数
******************************************/
I2C_Write(uchardate1)
{
uchari,temp;
temp=date1;
SCL=0;
for(i=0;i<8;i++)
{
SDA=(bit)(temp&0x80);
SCL=1;
NOP3();
SCL=0;
temp=temp<<1;
}
SDA=1;
NOP3();
}
/******************************************
写相应地址的数据
******************************************/
voidWrite_add(uintaddress,uchardate1)
{
ucharaddrh,addrl;
addrh=address>>8;
addrl=address%256;
EA=0;
Star