24C02、24C16进行字节、页读取、页存取操作

以下这篇文章是自己折腾了三天存储芯片后,并且能够成功进行字节操作、页操作的一篇应用型文章,不太想研究原理的可以直接采用本文的代码和注意事项。 

在对24C02或者24C16进行字节、页读取、页存取前,我们需要弄清楚I²C协议、24C02/24C16存储空间字节操作页操作的时序

  • I²C协议:I²C是什么协议网上进行百度方可知道,以下只写使用代码
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);
    }

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章