萬利的I2C-EEPROM例程有些問題,經(jīng)本人兩個晝夜的反復試驗,已修改完善。 本文引用地址:http://m.butianyuan.cn/article/201611/315433.htm修改了兩個地方,在void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)寫操作函數(shù)和void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)讀操作函數(shù)體內(nèi)的開頭先要執(zhí)行一句I2C_EE_WaitEepromStandbyState(); 這樣在以后調用寫操作函數(shù)和讀操作函數(shù)時就不用執(zhí)行I2C_EE_WaitEepromStandbyState()了。但上電復位后先要執(zhí)行一次讀操作,以后就可以無限制的隨便調用這兩個函數(shù)了。 詳細如下。 /* 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 : EEPROMs internal address to write to. * - NumByteToWrite : number of bytes to write to the EEPROM. * Output : None * Return : None pBuffer:指向要寫入數(shù)據(jù)數(shù)組的指針 WriteAddr:24c02中要寫入數(shù)據(jù)的首地址 NumByteToWrite:寫入的字節(jié)數(shù) *******************************************************************************/ void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)//將緩沖器的數(shù)據(jù)寫入EEPROM { u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0; Addr = WriteAddr % I2C_PageSize;//寫入地址是每頁的第幾位 count = I2C_PageSize - Addr;//在開始的一頁要寫入的個數(shù) NumOfPage = NumByteToWrite / I2C_PageSize;//要寫入的頁數(shù) NumOfSingle = NumByteToWrite % I2C_PageSize;//不足一頁的個數(shù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) /* If WriteAddr is I2C_PageSize aligned */ if(Addr == 0) //寫入地址是頁的開始 { /* If NumByteToWrite < I2C_PageSize */ if(NumOfPage == 0) //數(shù)據(jù)小于一頁 { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//寫少于一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) } /* If NumByteToWrite > I2C_PageSize */ else //數(shù)據(jù)大于等于一頁 { while(NumOfPage--)//要寫入的頁數(shù) { I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize); //寫一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) WriteAddr += I2C_PageSize; pBuffer += I2C_PageSize; } if(NumOfSingle!=0)//剩余數(shù)據(jù)小于一頁 { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//寫少于一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) } } } /* If WriteAddr is not I2C_PageSize aligned */ else //寫入地址不是頁的開始 { /* If NumByteToWrite < I2C_PageSize */ if(NumOfPage== 0) //數(shù)據(jù)小于一頁 { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//寫少于一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) } /* If NumByteToWrite > I2C_PageSize */ else//數(shù)據(jù)大于等于一頁 { NumByteToWrite -= count; NumOfPage = NumByteToWrite / I2C_PageSize; //重新計算要寫入的頁數(shù) NumOfSingle = NumByteToWrite % I2C_PageSize;//重新計算不足一頁的個數(shù)
if(count != 0)//在此處count一定不為0,此判斷條件好象有點多余 { I2C_EE_PageWrite(pBuffer, WriteAddr, count);//將開始的空間寫滿一頁 I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) WriteAddr += count; pBuffer += count; }
while(NumOfPage--)//要寫入的頁數(shù) { I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);//寫一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) WriteAddr += I2C_PageSize; pBuffer += I2C_PageSize; } if(NumOfSingle != 0)//剩余數(shù)據(jù)小于一頁 { I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle); //寫少于一頁的數(shù)據(jù) I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) } } } } /******************************************************************************* * 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 : EEPROMs internal address to write to. * Output : None * Return : None pBuffer:指向要寫入數(shù)據(jù)數(shù)組的指針 WriteAddr:24c02中要寫入數(shù)據(jù)的首地址 *******************************************************************************/ void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)//寫一個字節(jié)到EEPROM { /* Send STRAT condition */ I2C_GenerateSTART(I2C1, ENABLE);//產(chǎn)生 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設備傳送地址字,選擇發(fā)送方向 /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//檢查最近一次 I2C事件是否是輸入的事件
/* Send the EEPROMs internal address to write to */ I2C_SendData(I2C1, WriteAddr);//通過外設 I2Cx發(fā)送地址 /* 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發(fā)送數(shù)據(jù)
/* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//檢查最近一次 I2C事件是否是輸入的事件 /* Send STOP condition */ I2C_GenerateSTOP(I2C1, ENABLE);//產(chǎn)生 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 cant exceed the EEPROM page size. * Input : - pBuffer : pointer to the buffer containing the data to be * written to the EEPROM. * - WriteAddr : EEPROMs internal address to write to. * - NumByteToWrite : number of bytes to write to the EEPROM. * Output : None * Return : None pBuffer:指向要寫入數(shù)據(jù)數(shù)組的指針 WriteAddr:24c02中要寫入數(shù)據(jù)的首地址 NumByteToWrite:寫入的字節(jié)數(shù) *******************************************************************************/ void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)//寫少于一頁的數(shù)據(jù) { /* Send START condition */ I2C_GenerateSTART(I2C1, ENABLE);//產(chǎn)生 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設備傳送地址字,選擇發(fā)送方向 /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //檢查最近一次 I2C事件是否是輸入的事件 /* Send the EEPROMs internal address to write to */ I2C_SendData(I2C1, WriteAddr); //通過外設 I2Cx發(fā)送地址 /* 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發(fā)送數(shù)據(jù) /* 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);//產(chǎn)生 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 : EEPROMs internal address to read from. * - NumByteToRead : number of bytes to read from the EEPROM. * Output : None * Return : None pBuffer:指向要保存讀出數(shù)據(jù)的數(shù)組的指針 ReadAddr:24c02中要讀出數(shù)據(jù)的首地址 NumByteToRead:讀出的字節(jié)數(shù) *******************************************************************************/ void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//將EEPROM的數(shù)據(jù)讀入緩沖器 { I2C_EE_WaitEepromStandbyState();//EEPROM設為待命狀態(tài) /* Send START condition */ I2C_GenerateSTART(I2C1, ENABLE);//產(chǎn)生 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設備傳送地址字,選擇發(fā)送方向 /* 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 EEPROMs internal address to write to */ I2C_SendData(I2C1, ReadAddr); //通過外設 I2Cx發(fā)送地址 /* 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);//產(chǎn)生 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);//產(chǎn)生 I2Cx傳輸 STOP條件 }
/* Read a byte from the EEPROM */ *pBuffer = I2C_ReceiveData(I2C1);//返回通過 I2Cx最近接收的數(shù)據(jù) /* 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設為待命狀態(tài) { vu16 SR1_Tmp = 0; do { /* Send START condition */ I2C_GenerateSTART(I2C1, ENABLE);//產(chǎn)生 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設備傳送地址字 ,選擇發(fā)送方向 }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));//地址發(fā)送結束 /* Clear AF flag */ I2C_ClearFlag(I2C1, I2C_FLAG_AF);//清除 I2Cx的應答錯誤標志位 |
評論