本帖最后由 Vence 于 2019-9-26 12:51 编辑
以下这篇文章是自己折腾了三天存储芯片后,并且能够成功进行字节操作、页操作的一篇应用型文章,不太想研究原理的可以直接采用本文的代码和注意事项。
在对24C02或者24C16进行字节、页读取、页存取前,我们需要弄清楚I2C协议、24C02/24C16存储空间、字节操作和页操作的时序
————————————————
版权声明:本文为CSDN博主「Pvence」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40814407/article/details/101228190
I2C协议:I2C是什么协议网上进行百度方可知道,以下只写使用代码
- void i2cStart(void) //开始时序
- {
- SDA=1;
- SCL=1;
- _delay(2); //延时2μs
- SDA=0;
- _delay(2);
- SCL=0;
- }
-
- void i2cStop(void) //结束时序
- {
- SDA=0;
- _delay(2);
- SCL=1;
- _delay(2);
- SDA=1;
- }
-
- void i2cAck_MCU(void) //应答时序
- {
- SDA=0;
- _delay(2);
- SCL=1;
- _delay(2);
- SCL=0;
- _delay(2);
- SDA=1;
- _delay(4);
- }
-
-
- void i2cNoAck_MCU(void) //非应答时序
- {
- SDA=1;
- _delay(2);
- SCL=1;
- _delay(2);
- SCL=0;
- _delay(2);
复制代码 24C02/24C16存储空间大小24C02就是有2Kbit = 2000/8 = 250个字节,24C16就是有16kbit = 2000个字节,24C02一页最多可以写入8个字节,因此可以分成32页,24C16一页最多可以写入16个字节,因此可以分成128页。
字节写操作
- void WriteByte_24LC16B(unsigned char input)
- {
- unsigned char bit_count;
- for(bit_count=8;bit_count!=0;bit_count--)
- {
- _delay(2);
- SDA=(_Bool)(input&0x80);
- _delay(2);
- SCL=1;
- _delay(2);
- SCL=0;
- input=input<<1;
- _delay(2);
- }
- SDA=1;
- SDA_CTRL=1; //这里需要看自己使用的芯片设置SDA的IO口为输入状态,我用的是HT45F67芯片,SDA端口设置为输入状态,用于判断SDA是否接到主机的应答信号
- _delay(2);
- SCL=1;
- _delay(2);
- if(SDA == 1)
- ack = 0;
- else
- ack = 1;
- SCL=0;
- SDA_CTRL=0; //此处根据自己所使用的芯片将SDA所在的Io口设置为输出状态
- }
-
- void Write_24LC16B(unsigned char Wdata,unsigned int RomAddress)
- {
- unsigned char block;
- WriteDeviceAddress=0B10100000;
- block=RomAddress/256;
- RomAddress=RomAddress%256;
- WriteDeviceAddress=WriteDeviceAddress|(block<<1);
- i2cStart();
- WriteByte_24LC16B(WriteDeviceAddress);
- WriteByte_24LC16B((unsigned char)RomAddress);
- WriteByte_24LC16B(Wdata);
- i2cStop();
- _delay(5500);
- }
复制代码
字节读操作
- unsigned char ReadByte_24LC16B()
- {
- unsigned char bit_count,rbyte=0;
- SDA=1;
- SDA_CTRL=1;
- _delay(10);
- for(bit_count=8;bit_count!=0;bit_count--)
- {
- rbyte=rbyte<<1;
- _delay(2);
- SCL=1;
- rbyte=rbyte|((unsigned char)(SDA));
- _delay(2);
- SCL=0;
- _delay(2);
- }
- SDA_CTRL=0;
- return(rbyte);
- }
-
-
- unsigned char Read_24LC16B(unsigned int RomAddress)
- {
- unsigned char output,block;
- ReadDeviceAddress=0B10100001;
- WriteDeviceAddress=0B10100000;
- block=RomAddress/256;
- RomAddress=RomAddress%256;
- WriteDeviceAddress=WriteDeviceAddress|(block<<1);
- ReadDeviceAddress=ReadDeviceAddress|(block<<1);
- i2cStart();
- WriteByte_24LC16B(WriteDeviceAddress);
- WriteByte_24LC16B((unsigned char)RomAddress);
- i2cStart();
- WriteByte_24LC16B(ReadDeviceAddress);
- output=ReadByte_24LC16B();
- i2cNoAck_MCU();
- i2cStop();
- _delay(2000);
- return(output);
- }
复制代码
页写操作
- Wdata为输入数组的首地址,RomAddress为需要进行存储的地址,范围在0~2047之间,cnt为一次需要写入的字节个数,建议采用8的倍数的cnt,因为本函数不采用自动分页,不是8的倍数会在超出页写入最多的字节数之后覆盖掉原来的数。
- void WritePage_24LC16B(unsigned char *Wdata,unsigned int RomAddress,unsigned char cnt)
- {
- unsigned char block;
- WriteDeviceAddress=0B10100000;
- block=RomAddress/256;
- RomAddress=RomAddress%256;
- WriteDeviceAddress=WriteDeviceAddress|(block<<1);
- i2cStart();
- WriteByte_24LC16B(WriteDeviceAddress);
- WriteByte_24LC16B((unsigned char)RomAddress);
- while(cnt--)
- {
- WriteByte_24LC16B(*Wdata++);
- }
- i2cStop();
- }
-
- 注意:连续进行多页写操作,需要在WritePage_24LC16B函数后添加150μs以上的延迟,这段时间,24C02内部需要将数据存储到芯片内部。
- 例子:
- D_buffer[8] = {1,2,3,4,5,6,7,8};
- WritePage_24LC16B(D_buffer,0,8);
- _delay(150); //延迟150μs以及以上
- WritePage_24LC16B(D_buffer,8,8);
复制代码
页读操作
- void ReadPage_24LC16B(unsigned char *Rdata,unsigned int RomAddress,unsigned char cnt)
- {
- unsigned char block;
- ReadDeviceAddress=0B10100001;
- WriteDeviceAddress=0B10100000;
- block=RomAddress/256;
- RomAddress=RomAddress%256;
- WriteDeviceAddress=WriteDeviceAddress|(block<<1);
- ReadDeviceAddress=ReadDeviceAddress|(block<<1);
- i2cStart();
- WriteByte_24LC16B(WriteDeviceAddress);
- WriteByte_24LC16B((unsigned char)RomAddress);
- i2cStart();
- WriteByte_24LC16B(ReadDeviceAddress);
- while(cnt>1)
- {
- *Rdata++ = ReadByte_24LC16B();
- cnt--;
- i2cAck_MCU(); //发送完读地址后,需要应答一下
- }
- *Rdata = ReadByte_24LC16B();
- i2cNoAck_MCU(); //读取最后一个字节需要非应答
- i2cStop();
- _delay(2000);
- }
复制代码
|