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
#endif
u8 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后从写缓冲器到存储器需要5ms
WriteSize-=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