24CXX系列芯片属于EEPROM(Electrically Erasable Programmable read only memory)即电可擦可编程只读存储器,是一种掉电后数据不丢失(不挥发)存储芯片。
      24CXX系列芯片数据说明:见下表(只做参考,只表明常用24CXX器件的常用数据,具体使用请查阅器件数据手册):
如24C02BN容量=2KB,但写缓冲区(页容量)=8K,而不是下表中给出的16K;

型号

存储容量

页数

写缓冲器容量(页容量)

A2引脚功能

A1引脚功能

A0引脚功能

存储数据地址位数

24C01

1K=128Byte*8

16

8

A2

A1

A0

8

24C02

2K=256Byte*8

16

16

A2

A1

A0

8

24C04

4K=512Byte*8

32

16

A2

A1

P8

8

24C08

8K=1024Byte*8

64

16

A2

P9

P8

8

24C16

16K=2048Byte*8

128

16

P10

P9

P8

8

24C32

32K=4096Byte*8

256

32

a2

a1

a0

16

24C64

64K=8192Byte*8

512

32

a2

a1

a0

16

24C128

128K=16384Byte*8

512

64

NC

NC

NC

16

1、    “型号”:24Cxx系列型号的标称C后面的参数代表其存储容量大小,单位为KB,这里的1KB=1024bit;
2、    “存储容量”:24Cxx系列存储数据为8位(bit)格式,根据其容量可以计算出各型号具体存储数据的字节(Byte)数;
3、    “页数”和“写缓冲器容量”:为减少器件的功耗,每个24CXX器件都有一个写缓冲器,器件收到总线发来的数据时,先写入缓冲器并进行应答,直到器件收到总线上发出的STOP信号后,器件将收到的数据写入其内部存储器中;
收到总线STOP信号后,器件将数据从写缓冲器写入存储器中,这个过程需要5ms,如果后面需要进行立即读取或再次写入操作,必须延时>5ms。
“写缓冲器容量”就代表器件可以一次性写入数据的大小,也就是“页”大小。24CXX系列“写缓冲器”(页容量)大小不同,再根据器件存储器大小,“页数”也不相同。
页写:每次对器件的写入(写缓冲器),可以进行多字节数据连续写(只要总线不发出STOP信号),写缓冲器地址位自动+1,如果写入的字节数超过写缓冲器容量,地址计数器自动翻转,从写缓冲器0x00地址重新计数,并覆盖原先写入的数据。
如果在对器件的写操作是从数据地址的0x00地址位开始,在写缓冲器也是从0x00位开始,写满一页需要写入字节数也就等于写缓冲器容量大小;如果设定的写数据地址不是0x00,对于写入写缓冲器的位置地址就是“写数据初始地址%写缓冲器容量(求余)”,这时写满第1页的字节数不一定等于写缓冲器容量大小。
4、    “存储数据地址位数”:(数据存储地址和器件地址不是一个概念),24CXX器件内部存储的每个字节(Byte)都可以进行单独的读写操作(单字节读写),“存储数据地址位数”就代表了其用于寻址的地址位长度。根据容量不同,24C01/02使用8位数据地址位,24C04/08/16虽然也使用了8位的数据地址位,但8位数据地址最大0xff,表示最高可寻址256位(0~255),而24C04/08/16的存储容量有512/1024/2048Byte,明显不够,这时就看图中黄色标注部分,也就是下面说到的A2、A1和A0的其他功能;
5、    “A2”、“A1”、“A0”引脚功能:24CXX系列不同型号器件的这3个引脚接法不同,部分型号可以悬空,但统一接VSS代表0,接VCC代表1。不同型号器件的这3个引脚功能也不同,具体如下:
功能1:图中引脚功能为A2、A1或A0时,说明这3个引脚可以配置为器件的总线地址(通过分别接VSS或VCC),也表示了同一I2C总线上可以连接的同一型号的器件数量。如24C01/02可以接8个,而24C16在同一个I2C总线上只能接1个器件;
功能2:引脚功能位P8、P9和P10时(黄色标注部分),其代表的是数据帧地址。刚才已经说了,24C04存储容量有512Byte,使用8位地址数据寻址只能寻址256位,这里其A0引脚的功能就是数据地址位的第9位,这样其实际寻址功能为2^9=512,24C08和24C16也同理。所以在操作24C04/08/16器件时,如果要使用全部的存储空间,相应P8、P9或P10引脚应单独使用IO控制。

遇到的问题:在实际操作中使用STM32的I2C总线读写24CXX系列EEPROM时,遇到很多问题,陆陆续续学习了好几天,才一一解决。主要的问题有:
1、    开始使用的是板载24C02,在以起始地址0x00进行操作,单字节读写正常,使用多页写时要注意,根据器件的数据手册,写数据首先是写入写缓冲器中,页写就是指向写缓冲器连续写入多个字节,只有在写满写缓冲器(页)或数据字节已经写完,当器件收到总线发出STOP信号后,器件将写缓冲器中数据转写入存储器中,这个事件需要5ms的时间,而且在此期间器件不会对总线做任何反应的。所以在进行页写、总线有多个发送STOP程序之间,或者写完立即读的时候,必须在每个STOP信号后延时5ms。
2、    在使用板载的24C02时,调试页写程序,按照查找的资料,包括程序中定义的24C02参数,应该是写缓冲器为16字节(页容量),也就是每次连续写最多16位,但实际情况是写入和读出的数据不符。最后仔细查看板载的芯片型号,详细的型号为24C02BN,再次查看数据手册,才发现这个型号的24C02,写缓冲器(页容量)是8位,而不是24C02的16位,修改程序,调用程序中24C01定义的参数,读写相符。
3、    使用的是板载24C02,在以起始地址不等于0x00进行操作时,例如起始地址0x05,写入看不出来异常,但是读取时从第0x08位置数据错误,最后确认数据在写入写缓冲器时,并不是始终都是从写缓冲器的头部开始写入,而是根据页(写缓冲器)对应(映射)的存储器地址来写入的。例如起始地址0x05,则在写入写缓冲器时也是从第6位开始写入,写到第8位就算写满本页,需要发送STOP使器件将写缓冲器的内容转写到存储器对应地址中。
4、    I2C总线可以挂在多个器件,正好手上有24C32芯片,刚开始调试单字节读写程序时就发现读写24C02正常,读写24C32不符的问题,仔细查看数据手册,发现24C32因为存储容量较大,数据的地址位使用8位已经不能够定义,24C32使用了16位数据地址长度,程序中也需要对各个芯片的数据地址位长度进行定义。同时也知道了24C04/08/16芯片的A0、A1和A2引脚的不同功能,虽然这三个型号也是8位数据地址位,但同样引用了A0/A1/A2的引脚硬件控制作为存储器数据地址的第9/10/11位;

/*****************************************************************
*  课例名称:学习STM32固件库I2C总线
*  内容说明:IIC总线上EEPROM存储器按页写操作及读的例程
*  平台芯片:STM32F103ZE
*  端口说明:I2C1_SCK=PB6;I2C1_SDA=PB7
*                        USART1_Tx=PA9;USART1_Rx=PA10;
*  其他说明:24CXX系列的型号只定义了容量大小,但尾标不同,其页容量和
*            数据地址字节长度也不同,具体以数据手册为准
*****************************************************************/
#include "stm32f10x.h"
#include "stdio.h"/*********************定义I2C初始化数据**********************/
#define I2C_Speed         400000            //I2C1设置数据传输速度
#define I2C1_OWN_ADDRESS7 0X0a              //主设备的从地址/********************定义I2C中线器件参数*********************/
#define EE_24C32_ADDRESS    0xae        //定义器件型号和器件地址
/*根据型号,定义PAGE_SIZE写存储器(页)大小和数据地址位长度*/
#ifdef EE_24C01_ADDRESS#define PAGE_SIZE           8#define WORD_ADDR_SIZE      8#define EEPROM_ADDRESS      EE_24C01_ADDRESS
#endif
#ifdef EE_24C02_ADDRESS#define PAGE_SIZE           16#define WORD_ADDR_SIZE      8#define EEPROM_ADDRESS      EE_24C02_ADDRESS
#endif
#ifdef EE_24C04_ADDRESS#define PAGE_SIZE           16#define WORD_ADDR_SIZE      8#define EEPROM_ADDRESS      EE_24C04_ADDRESS
#endif
#ifdef EE_24C08_ADDRESS#define PAGE_SIZE           16#define WORD_ADDR_SIZE      8#define EEPROM_ADDRESS      EE_24C08_ADDRESS
#endif
#ifdef EE_24C16_ADDRESS#define PAGE_SIZE           16#define WORD_ADDR_SIZE      8#define EEPROM_ADDRESS      EE_24C16_ADDRESS
#endif
#ifdef EE_24C32_ADDRESS#define PAGE_SIZE           32#define WORD_ADDR_SIZE      16#define EEPROM_ADDRESS      EE_24C32_ADDRESS
#endif
#ifdef EE_24C64_ADDRESS#define PAGE_SIZE           32#define WORD_ADDR_SIZE      16#define EEPROM_ADDRESS      EE_24C64_ADDRESS
#endif
#ifdef EE_24C128_ADDRESS#define PAGE_SIZE           64#define WORD_ADDR_SIZE      16#define EEPROM_ADDRESS      EE_24C128_ADDRESS
#endifu8 ReadData;  //第二次测试读取数据变量
int fputc(int ch,FILE *f);
void Delay_MS(u16 nms);
void USART1_GPIO_Config(void);
void I2C1_GPIO_Config(void);
void I2C_WriteData(u8 addr,u8* dat,u8 size);
void I2C_PageWrite(u8 WriteAddr,u8* WriteDat,u16 WriteSize);
void I2C_ReadData(u8 ReadAddr,u8* ReadDat,u16 ReadSize);/*****************************************************************
*  名称:Pritf重定向子函数
*****************************************************************/
int fputc(int ch,FILE *f)
{  while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); USART_SendData(USART1,(unsigned char)ch);    while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);  return (ch);
}
/*****************************************************************
*  名称:SysTick_MS延时子函数
*****************************************************************/
void Delay_MS(u16 nms)
{u32 temp;SysTick->LOAD = 9000*nms;SysTick->VAL=0X00;//清空计数器SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源do{temp=SysTick->CTRL;//读取当前倒计数值}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达SysTick->CTRL=0x00; //关闭计数器SysTick->VAL =0X00; //清空计数器
}/*****************************************************************
*  名称:USART1|GPIOA初始化子函数
*****************************************************************/
static void USART1_GPIO_Config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;                        GPIO_InitStruct.GPIO_Pin=(GPIO_Pin_9|GPIO_Pin_10);                 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&GPIO_InitStruct);  //配置USART1_Tx=PA9;USART1_Rx=PA10;端口为复用推挽输出模式USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate=9600;USART_InitStruct.USART_WordLength=USART_WordLength_8b;USART_InitStruct.USART_StopBits=USART_StopBits_1;USART_InitStruct.USART_Parity=USART_Parity_No;USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;USART_Init(USART1,&USART_InitStruct);USART_Cmd(USART1,ENABLE);
}/*****************************************************************
*  名称:I2C1|GPIOB初始化子函数
*****************************************************************/
static void I2C1_GPIO_Config(void)
{GPIO_InitTypeDef  GPIO_InitStructure; /* 使能与 I2C1 有关的时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);         /* PB6-I2C1_SCL、PB7-I2C1_SDA*/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);I2C_InitTypeDef  I2C_InitStructure; /* I2C 配置 */I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;/* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;I2C_InitStructure.I2C_OwnAddress1 = I2C1_OWN_ADDRESS7; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;/* I2C的寻址模式 */I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;/* 通信速率 */I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;/* I2C1 初始化 */I2C_Init(I2C1, &I2C_InitStructure);/* 使能 I2C1 */I2C_Cmd(I2C1, ENABLE);
}
/*****************************************************************
*  名称:I2C总线等待EEPROM状态检测子函数
*****************************************************************/
//void I2C_EE_WaitEepromStandbyState(void)
//{
//  vu16 SR1_Tmp = 0;
//  do
//  {
//      /* Send START condition */
//      I2C_GenerateSTART(I2C1, ENABLE);
//      /* Read I2C1 SR1 register */
//      SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
//      /* Send EEPROM address for write */
//      I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
//  }
//  while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));//  /* Clear AF flag */
//  I2C_ClearFlag(I2C1, I2C_FLAG_AF);
//      /* STOP condition */
//  I2C_GenerateSTOP(I2C1, ENABLE);
//}/*****************************************************************
*  函数名称:I2C总线向EEPROM写数据子函数
*  函数说明:使I2C向EEPROM器件发送数据前的准备工作
*  输入参数:addr - 写入的数据起始地址
*            dat  - 写入的数据
*            size - 写入的数据长度
*  输出参数:无
*****************************************************************/
void I2C_WriteData(u8 addr,u8* dat,u8 size)
{
//  I2C_EE_WaitEepromStandbyState();/* [1]Send STRAT condition向I2C总线发送START信号 */I2C_GenerateSTART(I2C1, ENABLE);/* [2]Test on EV5 and clear it验证EV5事件 */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  /* [3]Send EEPROM address for write发送从设备地址 */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);/* [4]Test on EV6 and clear it验证EV6事件 */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));if(WORD_ADDR_SIZE==16)                            //如果器件数据地址位长度为16位{/* [5]Send the EEPROM's internal address to write to发送写数据的起始地址 */I2C_SendData(I2C1, addr>>8);          //发送高8位数据地址位/* [6]Test on EV8 and clear it验证EV8事件 */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));        }/* [5]Send the EEPROM's internal address to write to发送写数据的起始地址 */I2C_SendData(I2C1, addr);                        //发送低8位数据地址位/* [6]Test on EV8 and clear it验证EV8事件 */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));while(size){/* [7]Send the current byte发送数据字节 */I2C_SendData(I2C1,*dat);/* [8]Test on EV8 and clear it验证EV8事件 */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));printf("0x%02X ",*dat);                      //以16进制显示发送的数据dat++;size--;}/* [9]Send STOP condition发送STOP信号 */I2C_GenerateSTOP(I2C1, ENABLE);
}/*****************************************************************
*  函数名称:I2C总线向EEPROM按页写数据子函数
*  函数说明:按页向EEPROM写数据
*  输入参数:WriteAddr - 写入的数据起始地址
*            WriteDat  - 写入的数据
*            WriteSize - 写入的数据长度
*  输出参数:无
*****************************************************************/
void I2C_PageWrite(u8 WriteAddr,u8* WriteDat,u16 WriteSize)
{/*FirstPageSize-首页字节数;NumPage-页数;LastPageSize-尾页字节数*/u8 FirstPageSize=0,NumPage=0,LastPageSize=0;FirstPageSize=(PAGE_SIZE-(WriteAddr%PAGE_SIZE));        //根据写入数据起始地址计算首页字节数if(WriteSize>FirstPageSize)                                                   //如果写入数据字节数>计算的写入首页{I2C_WriteData(WriteAddr,WriteDat,FirstPageSize); //写入首页字节数据Delay_MS(6);                                                                          //24CXX器件每次写操作STOP后从写缓冲器到存储器需要5msWriteSize-=FirstPageSize;                                                 //计算目前仍需要写入数据字节数WriteAddr+=FirstPageSize;                                                 //计算目前仍需要写入数据地址WriteDat+=FirstPageSize;                                                   //计算目前仍需要写入数据指针NumPage=WriteSize/PAGE_SIZE;                                            //计算目前仍需要写入数据的页数LastPageSize=WriteSize%PAGE_SIZE;                                  //计算目前写入整页后余的字节数(尾页字节数) }else{I2C_WriteData(WriteAddr,WriteDat,WriteSize);          return; //如果写入数据字节数<=计算的写入首页字节数,则按数据字节数写入首页后直接跳出子函数} while(NumPage>0)                 //如果页数大于0,逐页写入{I2C_WriteData(WriteAddr,WriteDat,PAGE_SIZE);WriteAddr+=PAGE_SIZE;WriteDat+=PAGE_SIZE;NumPage--;Delay_MS(6);}if(LastPageSize>0)                     //如果尾页仍有剩余的字节数,继续写入{I2C_WriteData(WriteAddr,WriteDat,LastPageSize);  Delay_MS(6);}
}/*****************************************************************
*  名称:I2C总线从EEPROM读数据子函数
*****************************************************************/
void I2C_ReadData(u8 ReadAddr,u8* ReadDat,u16 ReadSize)
{  //*((u8 *)0x4001080c) |=0x80; while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));   /* Send START condition */I2C_GenerateSTART(I2C1, ENABLE);//*((u8 *)0x4001080c) &=~0x80;/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));/* Clear EV6 by setting again the PE bit */I2C_Cmd(I2C1, ENABLE);if(WORD_ADDR_SIZE==16)                       //如果器件数据地址位长度为16位{/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, ReadAddr>>8);/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));     }/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, ReadAddr);/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/* Send STRAT condition a second time */  I2C_GenerateSTART(I2C1, ENABLE);/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for read */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));/* While there is data to be read */while(ReadSize)  {if(ReadSize == 1){/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C1, DISABLE);/* Send STOP Condition */I2C_GenerateSTOP(I2C1, ENABLE);}/* Test on EV7 and clear it */if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  {      /* Read a byte from the EEPROM */*ReadDat = I2C_ReceiveData(I2C1);/* Point to the next location where the byte read will be saved */ReadDat++; /* Decrement the read bytes counter */ReadSize--;        }   }/* Enable Acknowledgement to be ready for another reception */I2C_AcknowledgeConfig(I2C1, ENABLE);
}void I2C_ByteRead(u8 Addr)
{  //*((u8 *)0x4001080c) |=0x80; while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));    /* Send START condition */I2C_GenerateSTART(I2C1, ENABLE);//*((u8 *)0x4001080c) &=~0x80;/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));/* Clear EV6 by setting again the PE bit */I2C_Cmd(I2C1, ENABLE);if(WORD_ADDR_SIZE==16){/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, Addr>>8);/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));        }/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, Addr);/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/* Send STRAT condition a second time */  I2C_GenerateSTART(I2C1, ENABLE);/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for read */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C1, DISABLE);/* Send STOP Condition */I2C_GenerateSTOP(I2C1, ENABLE);/* Test on EV7 and clear it */while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));/* Read a byte from the EEPROM */ReadData = I2C_ReceiveData(I2C1);    //  /* Enable Acknowledgement to be ready for another reception */
//  I2C_AcknowledgeConfig(I2C1, ENABLE);}
/*****************************************************************
*  函数名称:I2C总线向24CXX器件读写测试主函数
*  函数说明:使用USART1串口打印显示功能,
*            写入时:首先显示发送数组的内容,然后在
*            向24CXX写入时再次逐个显示写入的内容;
*            读取时:先显示读取并验证读取的数据是否正确,再使用
*            单字节读取显示进行验证;
*****************************************************************/
int main(void)
{ u8 i;u8 WriteTab[68];                 //测试用写数据数组u8 ReadTab[68];                       //测试用读数据数组u16 DataAddr=0x05;               //测试用数据起始地址u16 DataSize=68;                    //测试用数据长度   USART1_GPIO_Config();I2C1_GPIO_Config();    printf("\r\n ********** STM32固件库I2C外设读写EEPROM器件测试例程 ********** \r\n");printf("写入的数据\n\r");for(i=0;i<DataSize;i++)             //填充并显示WriteTab[]数组{WriteTab[i]=i;printf("0x%02X ",WriteTab[i]);if(i%16 == 15)    printf("\n\r");        }printf("\r\n写入的数据\n\r");I2C_PageWrite(DataAddr,WriteTab,DataSize);
//  Delay_MS(30);I2C_ReadData(DataAddr,ReadTab,DataSize);for(i=0;i<DataSize;i++){if(ReadTab[i] != WriteTab[i]){printf("\r\n0x%02X\r\n ", ReadTab[i]);printf("\r\n错误:I2C EEPROM写入与读出的数据不一致\r\n");     }}printf("\r\n读取的数据\n\r");for(i=0;i<DataSize;i++){printf("0x%02X ", ReadTab[i]);}printf("\r\n读取的数据\n\r");for(i=0;i<DataSize;i++){I2C_ByteRead(DataAddr+i);printf("0x%02X ", ReadData);}printf("\r\n ********** STM32固件库I2C外设读写EEPROM器件测试例程 ********** \r\n");    while (1);
}

初学24CXX系列EEPROM使用详解STM32库函数I2C总线相关推荐

  1. Docker系列07—Dockerfile 详解

    Docker系列07-Dockerfile 详解 1.认识Dockerfile 1.1 镜像的生成途径 基于容器制作  dockerfile,docker build 基于容器制作镜像,已经在上篇Do ...

  2. mongo 3.4分片集群系列之六:详解配置数据库

    这个系列大致想跟大家分享以下篇章: 1.mongo 3.4分片集群系列之一:浅谈分片集群 2.mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3.mongo 3.4分片集群系列之三:搭建 ...

  3. ftm模块linux驱动,飞思卡尔k系列_ftm模块详解.doc

    飞思卡尔k系列_ftm模块详解 1.5FTM模块1.5.1 FTM模块简介FTM模块是一个多功能定时器模块,主要功能有,PWM输出.输入捕捉.输出比较.定时中断.脉冲加减计数.脉冲周期脉宽测量.在K1 ...

  4. React Native按钮详解|Touchable系列组件使用详解

    转载自:http://www.devio.org/2017/01/10/React-Native按钮详解-Touchable系列组件使用详解/ 在做App开发过程中离不了的需要用户交互,说到交互,我们 ...

  5. Material Design系列之BottomNavigationView详解

    Material Design系列之BottomNavigationView详解 Material Design官方文档Bottom navigation的介绍 BottomNavigationVie ...

  6. React 源码系列 | React Context 详解

    目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api.大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(react-redux). 想想项 ...

  7. Landsat系列数据级别详解

    Landsat系列数据级别详解 转载自此文:https://www.cnblogs.com/icydengyw/p/12056211.html 一.Landsat Collection 1 Lands ...

  8. 小猫爪:i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解

    i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解 1 前言 2 FlexCAN简介 2.1 MB(邮箱)系统 2.1.1 正常模式下 2.1.2 激活了CAN FD情况下 2. ...

  9. CISCO X8系列AP升级详解

    X8系列AP升级详解 准备工作 1.将AP连接到可获取IP地址的设备:交换机.家用路由或者猫等 2.用终端通过CONSOLE线连接AP,默认用户名为:cisco 密码为:Cisco 3.在AP获取到地 ...

最新文章

  1. js 获取鼠标在画布的位置_javascript求鼠标在canvas画布里的坐标
  2. ugui unity 取消选择_Unity暑期萌新入门:环境篇
  3. 【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器
  4. Django之管理权限
  5. nginx mozilla_如何开始为Mozilla贡献力量
  6. 将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小)
  7. linux mysql 主从分离_MySQL主从分离基本配置
  8. 从join on和where执行顺序认识T-SQL查询处理执行顺序
  9. sourceInsight4 破解笔记(完美破解)【转】
  10. [转载] 【Java核心技术卷】关于除以0的计算
  11. android app运行显示两个图标
  12. Linux CentOS上用iptables设置防火墙遇到的问题
  13. python 模块之 bisect
  14. 环保线绕电阻器的主要特性和应用分析
  15. 偏最小二乘法(SIMPLS---未简化)
  16. AngularJS 事件
  17. bailian.openjudge 2692:假币问题
  18. 【数学建模】2022亚太赛A题 结晶器熔炼结晶过程序列图像特征提取与建模分析
  19. 新旧iPhone齐发力,苹果成最大赢家,中国手机靠小米挽回颜面
  20. background-attachment: fixed

热门文章

  1. wps合并所有sheet页_wps表格多个sheet合并
  2. 进程与MMU、TLB之间的疑问
  3. edu-【Linux 与 Python编程2021】Linux知识训练,Linux之用户管理,Linux文件/目录管理
  4. C语言刷题(6)(猜名次)——“C”
  5. 爱普生Epson Stylus C86 打印机驱动
  6. 智慧盲盒系统开发实例分享
  7. 金山安全卫士软件开源了!
  8. 关于自动拣DD的外挂文件
  9. 微信小程序登录与服务器交换数据的流程
  10. SQL语句大全[300个关键字]