万利的I2C-EEPROM例程有些问题,经本人两个昼夜的反复试验,已修改完善。
修改了两个地方,在void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16
NumByteToWrite)写操作函数和void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16
NumByteToRead)读操作函数体内的开头先要执行一句I2C_EE_WaitEepromStandbyState();
这样在以后调用写操作函数和读操作函数时就不用执行I2C_EE_WaitEepromStandbyState()了。但上电复位后先要执行一次读操作,以后就可以无限制的随便调用这两个函数了。
详细如下。
/* Includes
------------------------------------------------------------------*/ #include
"stm32f10x_lib.h" #include "i2c_ee.h" #include"delay.h"
/* Private typedef
-----------------------------------------------------------*/ /* Private
define ------------------------------------------------------------*/ #define
I2C_Speed 10000 #define I2C1_SLAVE_ADDRESS7 0xA0
#define I2C_PageSize 4
/* Private macro
-------------------------------------------------------------*/ /* Private
variables ---------------------------------------------------------*/ u16
EEPROM_ADDRESS;
/* Private function prototypes
-----------------------------------------------*/
void I2C_Configuration(void);
/******************************************************************************* *
Function Name : I2C_Configuration * Description : I2C Configuration *
Input : None * Output : None * Return :
None *******************************************************************************/ void
I2C_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* Configure I2C1 pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin =
GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode =
GPIO_Mode_AF_OD;//开漏输出 GPIO_Init(GPIOB, &GPIO_InitStructure);
/*
I2C configuration */ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//设置 I2C为
I2C模式 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//I2C快速模式 Tlow /
Thigh = 2
I2C_InitStructure.I2C_OwnAddress1 =
I2C1_SLAVE_ADDRESS7;//设置第一个设备地址
I2C_InitStructure.I2C_Ack =
I2C_Ack_Enable;//使能应答 I2C_InitStructure.I2C_AcknowledgedAddress =
I2C_AcknowledgedAddress_7bit;//应答 7位地址 I2C_InitStructure.I2C_ClockSpeed =
I2C_Speed;//设置时钟频率
/* I2C Peripheral Enable */ I2C_Cmd(I2C1,
ENABLE);//使能I2C外设 /* Apply I2C configuration after enabling it
*/ I2C_Init(I2C1, &I2C_InitStructure); }
/******************************************************************************* *
Function Name : I2C_EE_Init * Description : Initializes peripherals used by
the I2C EEPROM driver. * Input : None * Output : None * Return :
None *******************************************************************************/ void
I2C_EE_Init() { /* I2C configuration */ I2C_Configuration();
/* 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 }
/******************************************************************************* *
Function Name : I2C_EE_BufferWrite * Description : Writes buffer of data to
the I2C EEPROM. * Input : - pBuffer : pointer to the buffer containing the
data to be * written to the EEPROM. * - WriteAddr : EEPROM's internal
address to write to. * - NumByteToWrite : number of bytes to write to the
EEPROM. * Output : None * Return :
None pBuffer:指向要写入数据数组的指针 WriteAddr:24c02中要写入数据的首地址 NumByteToWrite:写入的字节数 *******************************************************************************/ void
I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16
NumByteToWrite)//将缓冲器的数据写入EEPROM { u8 NumOfPage = 0, NumOfSingle = 0, Addr
= 0, count = 0;
Addr = WriteAddr % I2C_PageSize;//写入地址是每页的第几位 count = I2C_PageSize -
Addr;//在开始的一页要写入的个数 NumOfPage = NumByteToWrite /
I2C_PageSize;//要写入的页数 NumOfSingle = NumByteToWrite %
I2C_PageSize;//不足一页的个数
I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态
/*
If WriteAddr is I2C_PageSize aligned */ if(Addr == 0) //写入地址是页的开始 { /*
If NumByteToWrite < I2C_PageSize */ if(NumOfPage == 0)
//数据小于一页 { I2C_EE_PageWrite(pBuffer, WriteAddr,
NumOfSingle);//写少于一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 } /*
If NumByteToWrite > I2C_PageSize */ else
//数据大于等于一页 { while(NumOfPage--)//要写入的页数 { I2C_EE_PageWrite(pBuffer,
WriteAddr, I2C_PageSize);
//写一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 WriteAddr +=
I2C_PageSize; pBuffer += I2C_PageSize; }
if(NumOfSingle!=0)//剩余数据小于一页 { I2C_EE_PageWrite(pBuffer, WriteAddr,
NumOfSingle);//写少于一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 } } } /*
If WriteAddr is not I2C_PageSize aligned */ else //写入地址不是页的开始 { /* If
NumByteToWrite < I2C_PageSize */ if(NumOfPage== 0)
//数据小于一页 { I2C_EE_PageWrite(pBuffer, WriteAddr,
NumOfSingle);//写少于一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 } /*
If NumByteToWrite > I2C_PageSize */ else//数据大于等于一页 { NumByteToWrite
-= count; NumOfPage = NumByteToWrite / I2C_PageSize;
//重新计算要写入的页数 NumOfSingle = NumByteToWrite %
I2C_PageSize;//重新计算不足一页的个数
if(count != 0)//在此处count一定不为0,此判断条件好象有点多余 {
I2C_EE_PageWrite(pBuffer, WriteAddr,
count);//将开始的空间写满一页 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 WriteAddr
+= count; pBuffer += count; }
while(NumOfPage--)//要写入的页数 { I2C_EE_PageWrite(pBuffer, WriteAddr,
I2C_PageSize);//写一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 WriteAddr
+= I2C_PageSize; pBuffer += I2C_PageSize; } if(NumOfSingle !=
0)//剩余数据小于一页 { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
//写少于一页的数据 I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态 } } } }
/******************************************************************************* *
Function Name : I2C_EE_ByteWrite * Description : Writes one byte to the I2C
EEPROM. * Input : - pBuffer : pointer to the buffer containing the data to be
* written to the EEPROM. * - WriteAddr : EEPROM's internal address to
write to. * Output : None * Return :
None pBuffer:指向要写入数据数组的指针 WriteAddr:24c02中要写入数据的首地址 *******************************************************************************/ void
I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)//写一个字节到EEPROM { /* Send STRAT
condition */ I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件
/* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_MODE_SELECT)); //检查最近一次 I2C事件是否是输入的事件
/* Send EEPROM address for write */ I2C_Send7bitAddress(I2C1,
EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向
/*
Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
/*
Send the EEPROM's internal address to write to */ I2C_SendData(I2C1,
WriteAddr);//通过外设 I2Cx发送地址
/* Test on EV8 and clear it
*/ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次
I2C事件是否是输入的事件
/* Send the byte to be written */ I2C_SendData(I2C1, *pBuffer); //通过外设
I2Cx发送数据
/* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件
/* Send STOP
condition */ I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件 }
/******************************************************************************* *
Function Name : I2C_EE_PageWrite * Description : Writes more than one byte to
the EEPROM with a single WRITE * cycle. The number of byte can't exceed the
EEPROM page size. * Input : - pBuffer : pointer to the buffer containing the
data to be * written to the EEPROM. * - WriteAddr : EEPROM's internal
address to write to. * - NumByteToWrite : number of bytes to write to the
EEPROM. * Output : None * Return :
None pBuffer:指向要写入数据数组的指针 WriteAddr:24c02中要写入数据的首地址 NumByteToWrite:写入的字节数 *******************************************************************************/ void
I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8
NumByteToWrite)//写少于一页的数据 { /* Send START condition
*/ I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件
/* Test on EV5
and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
//检查最近一次 I2C事件是否是输入的事件
/* Send EEPROM address for write
*/ I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS,
I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向
/* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //检查最近一次 I2C事件是否是输入的事件
/* Send the EEPROM's internal address to write to */ I2C_SendData(I2C1,
WriteAddr); //通过外设 I2Cx发送地址
/* Test on EV8 and clear it */ while(! I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //检查最近一次 I2C事件是否是输入的事件
/* While there is data to be written */ while(NumByteToWrite--)
{ /* Send the current byte */ I2C_SendData(I2C1, *pBuffer); //通过外设
I2Cx发送数据
/* Point to the next byte to be written */ pBuffer++;
/* Test on
EV8 and clear it */ while (!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件 }
/* Send STOP condition */ I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输
STOP条件 }
/******************************************************************************* *
Function Name : I2C_EE_BufferRead * Description : Reads a block of data from
the EEPROM. * Input : - pBuffer : pointer to the buffer that receives the
data read * from the EEPROM. * - ReadAddr : EEPROM's internal address to
read from. * - NumByteToRead : number of bytes to read from the EEPROM. *
Output : None * Return :
None pBuffer:指向要保存读出数据的数组的指针 ReadAddr:24c02中要读出数据的首地址 NumByteToRead:读出的字节数 *******************************************************************************/ void
I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16
NumByteToRead)//将EEPROM的数据读入缓冲器 {
I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态
/* Send START
condition */ I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件
/*
Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件
/* In the case of a
single data transfer disable ACK before reading the data
*/ if(NumByteToRead==1) { I2C_AcknowledgeConfig(I2C1,
DISABLE);//使能或者失能指定 I2C的应答功能 }
/* Send EEPROM address for write
*/ I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS,
I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向
/* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
/*
Clear EV6 by setting again the PE bit */ I2C_Cmd(I2C1, ENABLE);//使能或者失能
I2C外设
/* Send the EEPROM's internal address to write to */ I2C_SendData(I2C1,
ReadAddr); //通过外设 I2Cx发送地址
/* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件
/* Send STRAT
condition a second time */ I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输
START条件
/* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件
/* Send EEPROM
address for read */ I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS,
I2C_Direction_Receiver);//向指定的从 I2C设备传送地址字,选择接收方向
/* Test on EV6 and
clear it */ while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
/* While
there is data to be read */ while(NumByteToRead) { /* Test on EV7 and
clear it */ if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) //检查最近一次
I2C事件是否是输入的事件 { if(NumByteToRead == 2) { /* Disable Acknowledgement
*/ I2C_AcknowledgeConfig(I2C1, DISABLE);//使能或者失能指定 I2C的应答功能 }
if(NumByteToRead == 1) { /* Send STOP Condition
*/ I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件 }
/* Read a
byte from the EEPROM */ *pBuffer = I2C_ReceiveData(I2C1);//返回通过
I2Cx最近接收的数据
/* Point to the next location where the byte read will be saved
*/ pBuffer++;
/* Decrement the read bytes counter
*/ NumByteToRead--; } }
/* Enable Acknowledgement to be ready for another reception
*/ I2C_AcknowledgeConfig(I2C1, ENABLE);//使能或者失能指定 I2C的应答功能
}
/******************************************************************************* *
Function Name : I2C_EE_WaitEepromStandbyState * Description : Wait for EEPROM
Standby state * Input : None * Output : None * Return :
None *******************************************************************************/ void
I2C_EE_WaitEepromStandbyState(void) //EEPROM设为待命状态 { vu16 SR1_Tmp =
0;
do { /* Send START condition */ I2C_GenerateSTART(I2C1, ENABLE);//产生
I2Cx传输 START条件 /* Read I2C1 SR1 register */ SR1_Tmp =
I2C_ReadRegister(I2C1, I2C_Register_SR1);//读取指定的 I2C寄存器 I2C_SR1 并返回其值 /* Send
EEPROM address for write */ I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS,
I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字
,选择发送方向 }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) &
0x0002));//地址发送结束
/* Clear AF flag */ I2C_ClearFlag(I2C1,
I2C_FLAG_AF);//清除 I2Cx的应答错误标志位 }
|