存储空间分配
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*************************/在实际应用中要注意的便是存储空间的分配,已经空间长度的输入,这样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有自动地址溢出的功能