AT24CXX系列程序

存储空间分配
AT24C02A,2K 串行 EEPROM:共 32 页,每页 8 字节,寻址字需 8 位。
AT24C04A,4K 串行 EEPROM:共 32 页,每页 16 字节,寻址字需 9 位。
AT24C08A,8K 串行 EEPROM:共 64 页,每页 16 字节,寻址字需 10 位。
AT24C16A,16K 串行 EEPROM:共 128 页,每页 16 字节,寻址字需 11 位。

图为 几类不同容量的芯片的存储空间结构,24C16以下空间的大于8位后的寻址高位地址在片选地址中选择,详细看芯片手册。另外要注意的就是字节页,一次连续写入的数据量不能超过一页的数据量。有些老款的芯片甚至不支持跨页写入。为了适用也参照不跨页写入的方法写这个程序。而读取数据没有这个限制,只要单片机开辟的缓存够大,可以一直连续读下去。

      /*****24Cxx Seriel EEPROM*************************/
#define EEPROM 8
/********
01 -> 24C01;   02 -> 24C02;  04 -> 24C04;   08 -> 24C08;
16 -> 24C16;   32 -> 24C32;  64 -> 24C64;   128 -> 24C128;
256-> 24C256;  512 -> 24C512;  
*****/

#if EEPROM==1
   #define PAGE_SIZE           8
   #define EE_SIZE             0x007F
#elif EEPROM==2
   #define PAGE_SIZE           16 
   #define EE_SIZE             0x00FF
#elif EEPROM==4
   #define PAGE_SIZE           16
   #define EE_SIZE             0x01FF
#elif EEPROM==8
   #define PAGE_SIZE           16
   #define EE_SIZE             0x03FF
#elif EEPROM==16
   #define PAGE_SIZE           16
   #define EE_SIZE             0x07FF
#elif EEPROM==32
   #define PAGE_SIZE           32
   #define EE_SIZE             0x0FFF
#elif EEPROM==64
   #define PAGE_SIZE           32
   #define EE_SIZE             0x1FFF
#elif EEPROM==128
   #define PAGE_SIZE           64
   #define EE_SIZE             0x3FFF
#elif EEPROM==256
   #define PAGE_SIZE           64
   #define EE_SIZE             0x7FFF
#elif EEPROM==512
   #define PAGE_SIZE           128
   #define EE_SIZE             0xFFFF
#endif 

头文件可以写成预编译模式,方便移植后修改,PAGE_SIZE为一页的存储量,EE_SIZE为芯片的存储量,而后一些程序的判断也根据选择的存储芯片来判断。
顶层用于外部程序调用的函数只有两个,读和写两个情况而已

        unsigned char EEPROM_Write(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumbyteToWrite);
        unsigned char EEPROM_Read(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite);
传递函数有三个:
pBuffer:要存储或读出来的数据所在的变量存储区字符串头指针;
WriteAddress/ReadAddress:要存入EEPROM所在的存储空间的第一个存储空间地址;
NumbyteToWrite:数据写入或读出的字节个数;
这样的应用比较简单 例如在头文件中分配了两类数据的存储空间起始地址DATA1、DATA2
#define DATA1  0x0010
#define DATA2  0x0050
存储数据所在缓存 EE_Buffer[20],应用程序如下写法:
EEPROM_Write(EE_Buffer,DATA1,20);
这样EE_Buffer内的数据便被写入EEPROM中 0x10~0x30 的数据存储空间中了。
合理的分配陪EEPROM 的存储空间对数据管理非常重要。甚至于可以作为一个小型黑匣子一样。



unsigned char EEPROM_Write(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumbyteToWrite)
{
  unsigned char TempBuffer,Temp2Buffer;
  if((WriteAddress+NumbyteToWrite) > EE_SIZE)  //判断是否超出存储空间
    {
      return 0;
    }
  else
    {// 连续写入两次避免因EMC等因素造成的写入失败情况
      IIC_WriteBuffer(pBuffer,WriteAddress,NumbyteToWrite);
      IIC_WriteBuffer(pBuffer,WriteAddress,NumbyteToWrite);
        
        //读取eeprom 的数据与缓存中的数据对比 相同为确认写入成功
      IIC_ReadBuffer(&TempBuffer,WriteAddress+NumbyteToWrite-1,1);
      Temp2Buffer=*(pBuffer+NumbyteToWrite-1);
      if(TempBuffer==Temp2Buffer)
         return 1;
      else
        return 0;
    }
}

unsigned char EEPROM_Read(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite) 
{
  if((ReadAddress+NumbyteToWrite) > EE_SIZE) 
    {
      return 0;
    }
  else
    {
      IIC_ReadBuffer(pBuffer,ReadAddress,NumbyteToWrite);
      IIC_ReadBuffer(pBuffer,ReadAddress,NumbyteToWrite);
      return 1;
    }
}

        接下来的是是IIC_ReadBuffer、IIC_WriteBuffer,两个函数主要是对存入数据的处理,如页面内写入,超过页面数量的数据处理等,我这里把函数定义为static 函数只能对内部应用,外部只能调用上面的两个函数,累似于API函数一样,这也可以避免不必要的程序调用书写。IIC_ReadBuffer函数相对简单,因为读取没有对页面的限制,可以无限制的读下去。读取缓存的函数只对地址做一下判断即可。写入函数较为复杂,需判断数据起始存储地址 和页等关系
static void IIC_ReadBuffer(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite);
static void IIC_WriteBuffer(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumByteToWrite);

void IIC_ReadBuffer(unsigned char* pBuffer,unsigned int ReadAddress,unsigned char NumbyteToWrite)
{
  u8 PageAddress=0;
  /******pageAddress is over 8bit***********/
/******判断存储地址是否超过8位************/
#if EEPROM < 32
  PageAddress=(u8)(ReadAddress>>7)&0x0E|ReadAddress_EEPROM;
#else
  PageAddress=WriteAddress_EEPROM;
#endif 


IIC_ReadPage(pBuffer,PageAddress,ReadAddress,NumbyteToWrite); 
}

void IIC_WriteBuffer(unsigned char* pBuffer,unsigned int WriteAddress,unsigned char NumByteToWrite)
{
  u8 NumOfPage=0,NumOfSingle=0; //
  u16 Part=0;//
  u8 PageAddress=0;
  /******pageAddress is over 8bit***********/
  /******判断存储地址是否超过8位************/
#if EEPROM < 32
  PageAddress=(u8)(WriteAddress>>7)&0x0E|WriteAddress_EEPROM;
#else
  PageAddress=WriteAddress_EEPROM;
#endif 
  
  /*********判断起始地址与跨页地址的字节个数********/
  Part=WriteAddress/PAGE_SIZE;
  if(Part!=0)
    {
      Part=PAGE_SIZE*(Part+1)-WriteAddress;      
    }
  else 
    {
      Part=PAGE_SIZE-WriteAddress;
    }
  /******/
  if(Part >= NumByteToWrite)
    {
        /***写入的数据个数小于跨页剩余的个数可直接写入 ***/
      IIC_WritePage(pBuffer,PageAddress,WriteAddress,NumByteToWrite);
    }
  else
    {
      NumOfPage = (NumByteToWrite-Part)/PAGE_SIZE;  
      NumOfSingle = (NumByteToWrite-Part)%PAGE_SIZE;   
      pBuffer = IIC_WritePage(pBuffer,PageAddress,WriteAddress,Part);
    /***1.写入的数据个数大于跨页剩余的个数先把剩余的跨页个数填充满 ***/
      NumByteToWrite -= Part;
      WriteAddress += Part;


      while(NumOfPage--)
        {     
          pBuffer = IIC_WritePage(pBuffer,PageAddress,WriteAddress,PAGE_SIZE);
        /***2.按计算的数据量占页面数,连续写入页面*******/
          WriteAddress += PAGE_SIZE;
        
        }   
      if(NumOfSingle!=0)
        {
          IIC_WritePage(pBuffer,PageAddress,WriteAddress,NumOfSingle);
         /***3.补充页面写完后超出的不足一页数据量的数据***/
        }
    }
}


剩下的是IIC_WritePage()、IIC_ReadPage()两个函数是芯片的IIC通讯底层函数,根据单片机的IIC通讯模式写入即可。以上的程序可通用到任何24Cxx 系列所应用的程序。

     在实际应用中要注意的便是存储空间的分配,已经空间长度的输入,这样EEPROM的使用便能得心应手


void I2C_EE_Init()
{
 /* depending on the EEPROM Address selected in the i2c_ee.h file */
#ifdef EEPROM_Block0_ADDRESS
 /* Select the EEPROM Block0 to write on */
 EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif
#ifdef EEPROM_Block1_ADDRESS
 /* Select the EEPROM Block1 to write on */
 EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif
#ifdef EEPROM_Block2_ADDRESS
 /* Select the EEPROM Block2 to write on */
 EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif
#ifdef EEPROM_Block3_ADDRESS
 /* Select the EEPROM Block3 to write on */
 EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}
void I2C_ByteWrite(u8* pBuffer, u8 WriteAddr)//дһ¸ö×Ö½Ú
{
  
    I2C_GenerateSTART(I2C1, ENABLE); //ÆðʼÐźÅ
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//Çå³ýEV5  
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//·¢ËÍ´ÓÆ÷¼þµØÖ·
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//Çå³ýEV6
    I2C_SendData(I2C1, WriteAddr);//дµÄµØÖ·00~FF
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8-1
    I2C_SendData(I2C1, *pBuffer); //·¢ËÍÊý¾Ý
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Çå³ýEv8
    I2C_GenerateSTOP(I2C1, ENABLE);//²úÉúÍ£Ö¹ÐźÅ
}
void I2C_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)//Á¬Ðøд¶à¸ö×Ö½Ú
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // ÅжÏ×ÜÏßÊÇ·ñ·±Ã¦
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//EV5 
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//·¢ËÍ´ÓÆ÷¼þµØÖ·
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//Çå³ýEV6  
    I2C_SendData(I2C1, WriteAddr);//дµÄµØÖ·00~FF  
    while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8-1
    while(NumByteToWrite--)  
    {
        I2C_SendData(I2C1, *pBuffer); 
        pBuffer++; 
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Çå³ýEv8
    } 
    I2C_GenerateSTOP(I2C1, ENABLE);//²úÉúÍ£Ö¹ÐźÅ
}
void I2C_WaitEepromStandbyState(void)//µÈ´ý²Ù×÷Íê³É      
{
  vu16 SR1_Tmp = 0;
  do
  {
    I2C_GenerateSTART(I2C1, ENABLE);//ÆðʼÐźÅ
    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);//¶ÁÈ¡¼Ä´æÆ÷±ê־λ
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  }
  while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
  I2C_ClearFlag(I2C1, I2C_FLAG_AF);//Çå³ý
  I2C_GenerateSTOP(I2C1, ENABLE); 
}


void I2C_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)//ºÍ25X16Ò»Ñù
{
    u8 NumOfPage = 0;
u8 NumOfSingle = 0; 
u8 Addr = 0; 
u8 count = 0;


    Addr = WriteAddr %  I2C_PageSize;//¿´¿´²»ÂúÒ»Ò³µÄÓÃÁ˶àÉÙ
    count =I2C_PageSize-Addr;//²»ÂúһҳûÓõIJ¿·Ö
    NumOfPage =  NumByteToWrite / I2C_PageSize;//Ò»¸ö¶àÉÙÒ³
    NumOfSingle = NumByteToWrite % I2C_PageSize;//²»ÂúÒ»Ò³×Ö½ÚÊý


    if(Addr == 0)//ҳͷ¿ªÊ¼Ð´
    {
   
        if(NumOfPage == 0)//²»ÂúÒ»Ò³
        {
            I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
            I2C_WaitEepromStandbyState();
        }
    
        else//³¬¹ýÒ»Ò³  
        {
       while(NumOfPage--)//Õûҳд
       { 
I2C_PageWrite(pBuffer, WriteAddr,I2C_PageSize);
       I2C_WaitEepromStandbyState();
           WriteAddr +=  I2C_PageSize;
           pBuffer += I2C_PageSize;
       }

       if(NumOfSingle!=0)//²»ÂúÕûÒ³µÄ
       {
           I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
           I2C_WaitEepromStandbyState();
       }
        }
    }
 
    else//ÆðʼµØÖ·²»ÊÇҳͷ
    {
        if(NumOfPage== 0) 
        {
            I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
            I2C_WaitEepromStandbyState();
        }
        else
        {
            NumByteToWrite -= count;
            NumOfPage =  NumByteToWrite / I2C_PageSize;
            NumOfSingle = NumByteToWrite % I2C_PageSize;
            if(count != 0)
            {  
       I2C_PageWrite(pBuffer, WriteAddr, count);
       I2C_WaitEepromStandbyState( );
       WriteAddr += count;
       pBuffer += count;
            } 
            while(NumOfPage--)
            {
                I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
                I2C_WaitEepromStandbyState();
                WriteAddr +=  I2C_PageSize;
                pBuffer += I2C_PageSize;  
            }
            if(NumOfSingle != 0)
            {
                I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle); 
                I2C_WaitEepromStandbyState();
            }
        }
    }  
}

void I2C1_GPIO_Config()
{
GPIO_InitTypeDef  GPIO_InitStructure; 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;    
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void I2C1_Config()
{
I2C_InitTypeDef  I2C_InitStructure; 
    I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 =0XA0;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 400000;
I2C_Init(I2C1, &I2C_InitStructure);//
I2C_Cmd(I2C1, ENABLE);//´ò¿ªI2C1
I2C_AcknowledgeConfig(I2C1, ENABLE);//ÔÊÐíÓ¦´ð
}

void I2C_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//¶ÁÒ»´®Êý
{  
 
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));// ÅжÏ×ÜÏßÊÇ·ñ·±Ã¦
    I2C_GenerateSTART(I2C1, ENABLE); //ÆðʼÐźÅ
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//EV5 
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//·¢ËÍ´ÓÆ÷¼þµØÖ·
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//Çå³ýEV6
    I2C_Cmd(I2C1, ENABLE);
    I2C_SendData(I2C1, ReadAddr);//Òª¶ÁÊý¾ÝµÄµØÖ·  
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8-1
    I2C_GenerateSTART(I2C1, ENABLE);//ÆðʼÐźÅ
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//Çå³ýEV5
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);//¸æËßÆ÷¼þ  ÎÒÒª¶ÁÊý¾Ý
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6
    while(NumByteToRead)  
    {
        if(NumByteToRead == 1)//Ê£×îºóÒ»¸öÊý¾Ýʱ
        {
            I2C_AcknowledgeConfig(I2C1, DISABLE);//¹Ø±ÕÓ¦´ð
            I2C_GenerateSTOP(I2C1, ENABLE);// ʹÄÜÍ£Ö¹
        }
        if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))//EV7  ÓнÓÊÕʱ  
        {      
            *pBuffer = I2C_ReceiveData(I2C1);//µôÓÿ⺯Êý
             pBuffer++; //
             NumByteToRead--;//        
        }   
     }
    I2C_AcknowledgeConfig(I2C1, ENABLE);//´ò¿ªÓ¦´ð   ΪÏÂÒ»´Î×¼±¸
}


1. 注意24C16的管脚7是写保护,需要把它拉低

2.如果没有级联。最好A2 A1 A0 最好都接地

2.  24C16只能挂1个

3.  24C16的A2,A1,A0都是扇区地址

     I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

     EEPROM_ADDRESS就是八个扇区代表 0XA0 0XA2 0XA4 0XA6 0XA8 0XAA 0XAC 0XAE

     Send7bit意思是前7位自己决定最后一位方向为由I2C_Direction_Transmitter决定,看源码就知道了

     I2C_SendData(I2C1, WriteAddr1);决定每个扇区内256个字节的具体地址

4   24C16有8个扇区(block) 128个页   2048字节  16k位

     1扇区有16页       1页有16字节

4.  24C16的IIC函数第二个地址是从0开始,每256byte进行加一次地址,也就是说每次读写最大就是256byte,超过了的,要重新写地址,第二次地址= 0+256开始,继续最大写256byte  ,第三次地址是0+256+256这样循环下去写   好像24C16有自动地址溢出的功能



已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页