I2C读写CAT24WCxx存储器
目录
一、STM32模拟I2C通讯
1.1 I2C总线的数据传送
1、 数据位的有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
2、 起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
//产生起始信号
void I2C_Start(void)
{
I2C_SDA_OUT(); //GPIO_Pin=I2C_SDA;GPIO_Speed=GPIO_Speed_50MHz;GPIO_Mode=GPIO_Mode_Out_PP;
//GPIO_Init(GPIOB,&GPIO_InitStructure);
I2C_SDA_H; //GPIO_SetBits(GPIO_I2C,I2C_SDA)
I2C_SCL_H; //GPIO_SetBits(GPIO_I2C,I2C_SCL)
delay_us(5);
I2C_SDA_L; //GPIO_ResetBits(GPIO_I2C,I2C_SDA)
delay_us(6);
I2C_SCL_L; //GPIO_ResetBits(GPIO_I2C,I2C_SCL)
}
//产生终止信号
void I2C_Stop(void)
{
I2C_SDA_OUT(); //同上
I2C_SCL_L; //同上
I2C_SDA_L; //同上
I2C_SCL_H;
delay_us(6);
I2C_SDA_H;
delay_us(6);
}
3、数据传送格式
(1)字节传送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
在总线的一次数据传送过程中,可以有以下几种组合方式:
a、主机向从机发送数据,数据传送方向在整个传送过程中不变:
b、主机在第一个字节后,立即从从机读数据
c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。
注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。A表示应答, A非表示非应答(高电平)。S表示起始信号,P表示终止信号。
//主机产生应答信号ACK
void I2C_Ack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
//主机不产生应答信号NACK
void I2C_NAck(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
二、CAT24WCxx存储器的工作原理
CAT24WC01/02/04/08/16是一个1K/2K/4K/8K/16K位串行CMOS,EEPROM内部含有128/256/512/1024/2048个8位字节CATALYST公司的先进CMOS技术实质上减少了器件的功耗,CAT24WC01有一个8字节页写缓冲器CAT24WC02/04/08/16有一个16字节页写缓冲器,该器件通过I2C总线接口进行操作有一个专门的写保护功能
2.1总线时序
2.2 写周期时序
2.3 字节写
2.3.1器件寻址
主器件通过发送一个起始信号启动发送过程,然后发送它所要寻址的从器件的地址。8位从器件地址的高4位固定为(1010)。接下来的3位(A2、A1、A0)为器件的地址位,用来定义哪个器件以及器件的哪个部分被主器件访问,上述8个CAT24WC01/02,4个CAT24WC04,2个CAT24WC08,1个CAT24WC16可单独被系统寻址。从器件8位地址的最低位,作为读写控制位。“1”表示对从器件进行读操作,“0”表示对从器件进行写操作。在主器件发送起始信号和从器件地址字节后,CAT24WC01/02/04/08/16监视总线并当其地址与发送的从地址相符时响应一个应答信号(通过SDA线)。CAT24WC01/02/04/08/16再根据读写控制位(R/W)的状态进行读或写操作。
void AT24Cxx_WriteOneByte(u16 addr,u8 dt)
{
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(0xA0);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Send_Byte(dt);
I2C_Wait_Ack();
I2C_Stop();
delay_ms(10);
}
void AT24Cxx_WriteTwoByte(u16 addr,u16 dt)
{
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(0xA0);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Send_Byte(dt>>8);
I2C_Wait_Ack();
I2C_Send_Byte(dt&0xFF);
I2C_Wait_Ack();
I2C_Stop();
delay_ms(10);
}
2.4 读字节
2.4.1顺序读
在CAT24Cxx发送完一个8位字节数据后,主器件产生一个应答信号来响应,告知CAT24Cxx主器件要求更多的数据,对应每个主机产生的应答信号CAT24Cxx将发送一个8位数据字节。当主器件不发送应答信号而发送停止位时结束此操作。
从CAT24Cxx输出的数据按顺序由N到N+1输出。读操作时地址计数器在CAT24Cxx整个地址内增加,这样整个寄存器区域可在一个读操作内全部读出,当读取的字节超过E(对于24WC01,E=127;对24WC02,E=255;对24WC04,E=511;对24WC08,E=1023;对24WC16,E=2047)计数器将翻转到零并继续输出数据字节。
u8 AT24Cxx_ReadOneByte(u16 addr)
{
u8 temp=0;
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(0xA0);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte(0xA1);
I2C_Wait_Ack();
temp=I2C_Read_Byte(0); //0 代表NACK
I2C_Stop();
return temp;
}
u16 AT24Cxx_ReadTwoByte(u16 addr)
{
u16 temp=0;
I2C_Start();
if(EE_TYPE>AT24C16)
{
I2C_Send_Byte(0xA0);
I2C_Wait_Ack();
I2C_Send_Byte(addr>>8); //发送数据地址高位
}
else
{
I2C_Send_Byte(0xA0+((addr/256)<<1));///器件地址+数据地址
}
I2C_Wait_Ack();
I2C_Send_Byte(addr%256);//双字节是数据地址低位
//单字节是数据地址低位
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte(0xA1);
I2C_Wait_Ack();
temp=I2C_Read_Byte(1); // 1 代表ACK
temp<<=8;
temp|=I2C_Read_Byte(0); // 0 代表NACK
I2C_Stop();
return temp;
}