初始化就不解释的太详细了,多看看数据手册,这里我直接贴代码加注释
- /**
- * @brief EEPROM_I2C_Config初始化GPIO及I2C的模式
- * @param 无
- * @retval 无
- */
- void EEPROM_I2C_GPIO_Config(void)
- {
- //GPIO初始化结构体
- GPIO_InitTypeDef GPIO_InitStructure;
-
- /* 使能 I2C 外设时钟 */
- RCC_APB1PeriphClockCmd(EEPROM_I2C_CLK, ENABLE);
-
- //使能AHB1总线上SCL和SDA所在的时钟
- RCC_AHB1PeriphClockCmd(EEPROM_I2C_SCL_GPIO_CLK|EEPROM_I2C_SDA_GPIO_CLK,ENABLE);
-
- /* 备用功能配置(除ADC和DAC外的所有非GPIO功能),使用该函数GPIO_PinAFConfig(); */
- /* 连接 PXx 到 I2C_SCL */
- GPIO_PinAFConfig(EEPROM_I2C_SCL_GPIO_PORT,EEPROM_I2C_SCL_SOURCE,EEPROM_I2C_SCL_AF); //把引脚连接到外设
- /* 连接 PXx 到 I2C_SDA */
- GPIO_PinAFConfig(EEPROM_I2C_SDA_GPIO_PORT,EEPROM_I2C_SDA_SOURCE,EEPROM_I2C_SDA_AF); //把引脚连接到外设
-
-
- /* GPIO初始化 */
- GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //i2c GPIO口必须使用开漏输出 不能使用推挽输出 开漏(OD)与推挽(PP)电路
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //可以选择UP或者NOPULL 因为外部电路有上拉电阻 内部弱上拉意义不大
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //引脚速率
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //引脚复用功能正常开启
-
- /* 配置SCL引脚 */
- GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN ; //配置SCL对应的引脚号 SCL:PB8 SDA:PB9 在stm32f407英文手册查询,引脚不唯一
- GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStructure); //初始化GPIO
-
- /* 配置SDA引脚 */
- GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN; //配置SDA引脚号
- GPIO_Init(EEPROM_I2C_SDA_GPIO_PORT, &GPIO_InitStructure); //初始化GPIO
-
-
- }
-
-
- /**
- * @brief I2C 工作模式配置
- * @param 无
- * @retval 无
- */
- void I2C_Mode_Config(void)
- {
- I2C_InitTypeDef I2C_InitStructure;
-
- /* --------------------I2C 配置 ---------------------------*/
- /* I2C 模式配置 */
- I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
- /* I2C 占空比周期配置 low/high=2/1 */
- I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; /* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
- /* I2C STM32 的 I2C 设备自己的地址长度配置 */
- I2C_InitStructure.I2C_OwnAddress1 =I2C_OWN_ADDRESS7;
- /* I2C 应答使能配置 */
- I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
- /* I2C 寻址长度配置 7bit|10bit */
- I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /* I2C的寻址模式 */
- /* I2C 速率配置 */
- I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; /* 通信速率 */
- /* I2C 初始化 */
- I2C_Init(EEPROM_I2C, &I2C_InitStructure); /* I2C1 初始化 */
- /* I2C 配置 */
- I2C_Cmd(EEPROM_I2C, ENABLE); /* 使能 I2C1 */
-
- /* I2C 应答使能配置 */
- I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
- }
-
-
- void I2C_EE_init(void)
- {
- /* I2C GPIO配置 */
- EEPROM_I2C_GPIO_Config();
-
- /* I2C配置 */
- I2C_Mode_Config();
-
- }


下面的EV事件是必须等待响应后才能继续执行下一步
EV事件看不明白的看STM32数据手册 有对I2C的寄存器的每位的作用都有讲解

关于怎么检测EV事件响应I2C库中给了I2C_CheckEvent()函数非常方便
上面的注释给了各种EV事件应该对应选择什么参数
- /**
- * @brief Checks whether the last I2Cx Event is equal to the one passed
- * as parameter.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @param I2C_EVENT: specifies the event to be checked.
- * This parameter can be one of the following values:
- * @arg I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: EV1
- * @arg I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: EV1
- * @arg I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED: EV1
- * @arg I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED: EV1
- * @arg I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED: EV1
- * @arg I2C_EVENT_SLAVE_BYTE_RECEIVED: EV2
- * @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_DUALF): EV2
- * @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_GENCALL): EV2
- * @arg I2C_EVENT_SLAVE_BYTE_TRANSMITTED: EV3
- * @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_DUALF): EV3
- * @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_GENCALL): EV3
- * @arg I2C_EVENT_SLAVE_ACK_FAILURE: EV3_2
- * @arg I2C_EVENT_SLAVE_STOP_DETECTED: EV4
- * @arg I2C_EVENT_MASTER_MODE_SELECT: EV5
- * @arg I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: EV6
- * @arg I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: EV6
- * @arg I2C_EVENT_MASTER_BYTE_RECEIVED: EV7
- * @arg I2C_EVENT_MASTER_BYTE_TRANSMITTING: EV8
- * @arg I2C_EVENT_MASTER_BYTE_TRANSMITTED: EV8_2
- * @arg I2C_EVENT_MASTER_MODE_ADDRESS10: EV9
- *
- * @note For detailed description of Events, please refer to section I2C_Events
- * in stm32f4xx_i2c.h file.
- *
- * @retval An ErrorStatus enumeration value:
- * - SUCCESS: Last event is equal to the I2C_EVENT
- * - ERROR: Last event is different from the I2C_EVENT
- */
- ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
- {
- uint32_t lastevent = 0;
- uint32_t flag1 = 0, flag2 = 0;
- ErrorStatus status = ERROR;
-
- /* Check the parameters */
- assert_param(IS_I2C_ALL_PERIPH(I2Cx));
- assert_param(IS_I2C_EVENT(I2C_EVENT));
-
- /* Read the I2Cx status register */
- flag1 = I2Cx->SR1;
- flag2 = I2Cx->SR2;
- flag2 = flag2 << 16;
-
- /* Get the last event value from I2C status register */
- lastevent = (flag1 | flag2) & FLAG_MASK;
-
- /* Check whether the last event contains the I2C_EVENT */
- if ((lastevent & I2C_EVENT) == I2C_EVENT)
- {
- /* SUCCESS: last event is equal to I2C_EVENT */
- status = SUCCESS;
- }
- else
- {
- /* ERROR: last event is different from I2C_EVENT */
- status = ERROR;
- }
- /* Return status */
- return status;
- }
其中对EV事件响应设置了超时等待,如果超时了还未响应则返回回调函数打印出报错信息
- /* ------------------对EEPROM写入1字节数据----------------------- */
- //Buffer :要写入的数据
- //Addr :要写入EEPROM的单元格地址
- uint32_t EEPROM_byte_write(u8 Buffer , u8 Addr)
- {
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C,ENABLE);
-
- //等待EV5事件响应
- TimeOut_count = I2C_time_out;
- while(!I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT))
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(0);
- }
-
- //发送要写入的EEPROM的地址和读写方向
- I2C_Send7bitAddress(EEPROM_I2C , EEPROM_ADDRESS , I2C_Direction_Transmitter);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(1);
- }
-
- //发送要写入EEPROM的单元地方
- I2C_SendData(EEPROM_I2C,Addr);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(2);
- }
-
- //发送要写入的数据
- I2C_SendData(EEPROM_I2C , Buffer);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(3);
- }
-
- //发送停止信号
- I2C_GenerateSTOP(I2C1,ENABLE);
-
- return 0;
- }
- //addr : 要读取的单元格地址
- //DATA :读取的内容存放区
- uint32_t EPPROM_Random_Read(u8 addr , u8 *Data)
- {
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C,ENABLE);
-
- //等待EV5事件响应
- TimeOut_count = I2C_time_out;
- while(!I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT))
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(4);
- }
-
- //发送要写入的EEPROM的地址和读写方向 先选择写方向写入单元格地址
- I2C_Send7bitAddress(EEPROM_I2C , EEPROM_ADDRESS , I2C_Direction_Transmitter);
-
- //等待EV6事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(5);
- }
-
- //发送要读取EEPROM的单元地方
- I2C_SendData(EEPROM_I2C,addr);
-
- //等待EV8_2事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(6);
- }
-
- //---------------------------------------------------------------------------------------------------------
- //-----------------------产生第二次起始信号---------------------------------------------------------
-
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C,ENABLE);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(!I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT))
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(7);
- }
-
- //*********************************读方向************************************************
- //发送要写入的EEPROM的地址和读方向
- I2C_Send7bitAddress(EEPROM_I2C , EEPROM_ADDRESS , I2C_Direction_Receiver);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(8);
- }
-
- I2C_AcknowledgeConfig(EEPROM_I2C , DISABLE);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(9);
- }
-
- *Data = I2C_ReceiveData(EEPROM_I2C);
-
- //发送停止信号
- I2C_GenerateSTOP(I2C1,ENABLE);
-
- return 0;
- }
STM32对EEPROM写入后立马读取是会报错的
必须等待写入事件响应后才能读取,因为在数据写入的时候
位 7 TxE:数据寄存器为空 (Data register empty)(发送器) 还没发送完毕的时候是不能读取的
所以写了个wait函数用来等待发送完毕检测
- //等待内部写入操作完成
- //写入完成返回1 失败发送0
- uint8_t Wait_for_StandBy(void)
- {
- uint32_t wait_count = 0xFFFF;
- while(wait_count--)
- {
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C,ENABLE);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(!I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT))
- {
- if((TimeOut_count--) == 0) return I2C_timeout_callback(10);
- }
-
- //发送要写入的EEPROM的地址和读写方向
- I2C_Send7bitAddress(EEPROM_I2C , EEPROM_ADDRESS , I2C_Direction_Transmitter);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while(TimeOut_count--)
- {
- if(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == SUCCESS)
- {
- //发送停止信号
- I2C_GenerateSTOP(I2C1,ENABLE);
- return 1;
- }
- }
- }
- //发送停止信号
- I2C_GenerateSTOP(I2C1,ENABLE);
- return 0;
- }
注意在检测的时候也是需要起始信号和停止信号的,对EEPROM的地址一直写入直到成功代表STM32已经对EEPROM写入完成
这个函数只需要添加在读写函数之间就好了
- int main(void)
- {
-
- /*初始化UART 配置模式为 115200 8-N-1,中断接收*/
- Debug_USART_Config();
-
-
- printf("这是一个EEPROM读写实验\n");
-
- printf("\r\n 欢迎使用野火 STM32 F407 开发板。\r\n");
-
- printf("\r\n 这是一个I2C外设(AT24C02)读写测试例程 \r\n");
-
- I2C_EE_init();
-
- u8 Data;
-
- //在EEPROM的0x00单元地址 写入0x12
- EEPROM_byte_write(0x12 , 0x00);
-
- //写完马上读会出错 在写入时是不能读的
- Wait_for_StandBy();
-
- //读取EEPROM的单元格0x00地址数据存入 Data中
- EPPROM_Random_Read(0x00 , &Data);
-
- printf(" \r\n EEPROM读写实验结束 data = 0x%02x \n",Data);
-
- while(1)
- {
-
- }
- }

- uint32_t I2C_timeout_callback(uint8_t errorCode)
- {
- printf("I2C 等待超时 , 错误代码 errorCode = %d \r\n",errorCode);
-
- return 0;
- }