实验二 I2C存储器实验电信1班.docx
《实验二 I2C存储器实验电信1班.docx》由会员分享,可在线阅读,更多相关《实验二 I2C存储器实验电信1班.docx(32页珍藏版)》请在冰点文库上搜索。
实验二I2C存储器实验电信1班
实验十六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,0x25,0x0c,0x69,0x48,0x41,0x1f,0x01,0x09};
ucharcodea[]={0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
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;
LEDCLK=0;
for(i=0;i<8;i++)
{
LEDDIN=1;
NOP3();
LEDCLK=1;
NOP3();
LEDCLK=0;
}
Init_24cxx();
WR1=0X01;
RD1=0x00;
while
(1)
{
Write_add(0x0004,WR1);
delay1ms(500);
RD1=Read_add(0X0004);
P0=table[RD1];
delay1ms(500);
}
}
实验现象
看到数码管有8位显示WR1传送的数
思考题
1、请说说I2C总线的优点有哪些?
答、I2C总线组成的控制系统占用I/O口少,功耗低,可以挂接多个器件。
2、编写页写操作子程序。
答、/******************************************
读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=date;
SCL=0;
for(i=0;i<8;i++)
{
SDA=(bit)(temp&0x80);
SCL=1;
NOP3();
SCL=0;
temp=temp<<1;
}
NOP3();
}
/******************************************
写相应地址的数据
voidWrite_add(uintaddress,uchardate)
{
UcharI;
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();
for(i=0;i<8;i++)
{
I2C_Write(date1);//发送数据
I2C_ACK();
}
Stop();//停止
EA=1;
}
/******************************************
读相应地址的数据
******************************************/
ucharRead_add(uintaddress)
{
ucharaddrh,addrl,temp,i;
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();
For(i=0,i<8,i++)
{
I2C_Write(0xa1);//发送命令字+芯片编号+P0+R
I2C_ACK();
}
temp=I2C_Read();
I2C_NACK();
Stop();
EA=1;
returntemp;
}
3、在连续读操作到最后一个数据时,主机如果发送响应信号,会出现什么情况?
4.用8位数码管分别显示接受数据和发送数据即024
#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;
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;
}
/************