/**
* @brief Returns the most recent received data by the I2Cx peripheral.
* @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
* @retval The value of the received data.
*/
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx)
10-I2C控制器获取最新的通信事件涵数
/**
* @brief Returns the last I2Cx Event.
* @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
*
* @note For detailed description of Events, please refer to section I2C_Events
* in stm32f4xx_i2c.h file.
*
* @retval The last event
*/
uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx)
以上就是这些部分,具体的其他部分请查看相关.c以及.h文件和数据手册。
15.3 应用
#include "bsp_i2c_ee.h"
#include "bsp_usart.h"
uint16_t EEPROM_ADDRESS;
static __IO uint32_t I2CTimeout = I2CT_LONG_TIMEOUT;
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
/**
* @brief I2C 工作模式配置
* @param 无
* @retval 无
*/
void I2C_Config(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------第1步--------------------*/
/*时钟使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); //I2C2时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE); //GPIO时钟使能
/*-------------------第2步--------------------*/
/*GPIO引脚复用*/
GPIO_PinAFConfig(GPIOH, GPIO_PinSource4, GPIO_AF_I2C2); //将PH4复用给I2C2
GPIO_PinAFConfig(GPIOH, GPIO_PinSource5, GPIO_AF_I2C2); //将PH5复用给I2C2
/*初始化GPIO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//开漏输出模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//使能上拉
GPIO_Init(GPIOH, &GPIO_InitStructure);// 初始化PH4:SCL
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOH, &GPIO_InitStructure);// 初始化PH5:SDA
/*-------------------第3步--------------------*/
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C模式 */
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // SCL 时钟线的占空比
I2C_InitStructure.I2C_OwnAddress1 =I2C_OWN_ADDRESS7; // 从机时,自身器件地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ; // 使能ACK相应
//7bit的寻址模式
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000; // 通信速率<=400K
I2C_Init(I2C2, &I2C_InitStructure); // I2C2 初始化
/*-------------------第4步--------------------*/
I2C_Cmd(I2C2, ENABLE); // 使能 I2C2
/*-------------------第5步--------------------*/
I2C_AcknowledgeConfig(I2C2, ENABLE); //使能IIC ACK功能
EEPROM_ADDRESS = 0xA0;//EEPROM器件地址
}
/**
* @brief 将缓冲区中的数据写到I2C EEPROM中
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
void I2C_Buffer_Write(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
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;
/* If WriteAddr is I2C_PageSize aligned */
if(Addr == 0)
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage == 0)
{
I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
while(NumOfPage--)
{
I2C_Page_Write(pBuffer, WriteAddr, I2C_PageSize);
I2C_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle!=0)
{
I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
}
}
/* If WriteAddr is not I2C_PageSize aligned */
else
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage== 0)
{
I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(count != 0)
{
I2C_Page_Write(pBuffer, WriteAddr, count);
I2C_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
}
while(NumOfPage--)
{
I2C_Page_Write(pBuffer, WriteAddr, I2C_PageSize);
I2C_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
}
}
}
/**
* @brief 写一个字节到I2C EEPROM中
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @retval 无
*/
uint32_t I2C_Byte_Write(u8* pBuffer, u8 WriteAddr)
{
/* Send STRAT condition 启动操作*/
I2C_GenerateSTART(I2C2, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV5 and clear it 检测总线是否忙*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
}
/* Send EEPROM address for write 发送器件地址 写操作 */
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV6 and clear it 等待ACK*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
/* Send the EEPROM's internal address to write to 发送器件内写地址 */
I2C_SendData(I2C2, WriteAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV8 and clear it 等待ACK*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
/* Send the byte to be written 写数据*/
I2C_SendData(I2C2, *pBuffer);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV8 and clear it 等待ACK*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
/* Send STOP condition 停止操作*/
I2C_GenerateSTOP(I2C2, ENABLE);
return 1;
}
/**
* @brief 在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
* 不能超过EEPROM页的大小,AT24C02每页有8个字节
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
uint32_t I2C_Page_Write(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) //检测IIC控制器是否忙 确认没有总线上没有通信
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
}
/* Send START condition 启动操作*/
I2C_GenerateSTART(I2C2, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
}
/* Send EEPROM address for write 写器件地址 写操作*/
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV6 ((uint32_t)0x00070082) and clear it 等待ACK 确认以下信息: TRA-发送器/接收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
}
/* Send the EEPROM's internal address to write to 发送器件内写地址*/
I2C_SendData(I2C2, WriteAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器/接收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成 */
while(! I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
}
/* While there is data to be written */
while(NumByteToWrite--)
{
/* Send the current byte 写数据*/
I2C_SendData(I2C2, *pBuffer);
/* Point to the next byte to be written */
pBuffer++;
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器/接收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成*/
while (!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
}
}
/* Send STOP condition 停止操作*/
I2C_GenerateSTOP(I2C2, ENABLE);
return 1;
}
/**
* @brief 从EEPROM里面读取一块数据
* @param
* @arg pBuffer:存放从EEPROM读取的数据的缓冲区指针
* @arg WriteAddr:接收数据的EEPROM的地址
* @arg NumByteToWrite:要从EEPROM读取的字节数
* @retval 无
*/
uint32_t I2C_Buffer_Read(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//*((u8 *)0x4001080c) |=0x80;
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) //检测IIC控制器是否忙
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
}
/* Send START condition 启动操作*/
I2C_GenerateSTART(I2C2, ENABLE);
//*((u8 *)0x4001080c) &=~0x80;
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
/* Send EEPROM address for write 写器件地址 写操作*/
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV6 ((uint32_t)0x00070082) and clear it 等待ACK 确认以下信息: TRA-发送器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);
}
// /* Clear EV6 by setting again the PE bit 清除事件6 实际测试去掉也没有出错*/
// I2C_Cmd(I2C2, ENABLE);
/* Send the EEPROM's internal address to write to 发送器件内读地址*/
I2C_SendData(I2C2, ReadAddr);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成 */
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);
}
/* Send STRAT condition a second time 重亲启动操作*/
I2C_GenerateSTART(I2C2, ENABLE);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);
}
/* Send EEPROM address for read 发送器件地址+1 读操作*/
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Receiver);
I2CTimeout = I2CT_FLAG_TIMEOUT;
/* Test on EV6 ((uint32_t)0x00030002) and clear it 等待ACK 确认以下信息: TRA-接收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)*/
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);
}
/* While there is data to be read */
while(NumByteToRead)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
if(NumByteToRead == 1)//最后一个数据的话
{
/* Disable Acknowledgement 禁止ACK 结束数据接收*/
I2C_AcknowledgeConfig(I2C2, DISABLE);
/* Send STOP Condition 停止操作*/
I2C_GenerateSTOP(I2C2, ENABLE);
}
else
/* Enable Acknowledgement to be ready for another reception 使能ACK 重复数据接收*/
I2C_AcknowledgeConfig(I2C2, ENABLE);
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)==0) //等待数据接收结束 ((uint32_t)0x00030040) BUSY-总线正在进行通信, MSL-主/从模式, and RXNE-数据寄存器非空 flags
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
{
/* Read a byte from the device 读取数据*/
*pBuffer = I2C_ReceiveData(I2C2);
/* Point to the next location where the byte read will be saved */
pBuffer++;
/* Decrement the read bytes counter */
NumByteToRead--;
}
}
return 1;
}
/**
* @brief Wait for EEPROM Standby state
* @param 无
* @retval 无
*/
void I2C_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
/* Send START condition */
I2C_GenerateSTART(I2C2, ENABLE);
/* Read I2C2 SR1 register */
SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));
/* Clear AF flag */
I2C_ClearFlag(I2C2, I2C_FLAG_AF);
/* STOP condition */
I2C_GenerateSTOP(I2C2, ENABLE);
}
/**
* @brief Basic management of the timeout situation.
* @param errorCode:错误代码,可以用来定位是哪个环节出错.
* @retval 返回0,表示IIC读取失败.
*/
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
/* Block communication and all processes */
return 0;
}
/*********************************************END OF FILE**********************/
#ifndef __I2C_EE_H
#define __I2C_EE_H
#include "stm32f4xx.h"
/* AT24C01/02每页有8个字节 */
//#define I2C_PageSize 8
/* AT24C04/08A/16A每页有16个字节 */
#define I2C_PageSize 16
/* STM32 I2C 快速模式 */
#define I2C_Speed 400000
/* 这个地址只要与STM32外挂的I2C器件地址不一样即可 */
#define I2C_OWN_ADDRESS7 0X0A
/*I2C接口*/
#define EEPROM_I2C I2C2
#define EEPROM_I2C_CLK RCC_APB1Periph_I2C2
#define EEPROM_I2C_CLK_INIT RCC_APB1PeriphClockCmd
#define EEPROM_I2C_SCL_PIN GPIO_Pin_4
#define EEPROM_I2C_SCL_GPIO_PORT GPIOH
#define EEPROM_I2C_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH
#define EEPROM_I2C_SCL_SOURCE GPIO_PinSource4
#define EEPROM_I2C_SCL_AF GPIO_AF_I2C2
#define EEPROM_I2C_SDA_PIN GPIO_Pin_5
#define EEPROM_I2C_SDA_GPIO_PORT GPIOH
#define EEPROM_I2C_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH
#define EEPROM_I2C_SDA_SOURCE GPIO_PinSource5
#define EEPROM_I2C_SDA_AF GPIO_AF_I2C2
/*等待超时时间*/
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
/*
* AT24C02 2kb = 256 B , 1个块 32 页, 8 字节/页,Block0
* AT24C04 4kb = 512 B , 2个块2*32 页,16 字节/页,Block0~1
* AT24C08 8kb = 1K B , 4个块4*32 页,16 字节/页,Block0~3
* AT24C16 16kb = 2K B , 8个块8*32 页,16 字节/页,Block0~7
*
* Device Address
* 1 0 1 0 A2 A1 A0 R/W
* 1 0 1 0 0 0 0 0 = 0XA0
* 1 0 1 0 0 0 0 1 = 0XA1
*/
/* EEPROM Addresses defines */
#define EEPROM_Block0_ADDRESS 0xA0 /* 块0 AT24C02 AT24C04 AT24C08 AT24C16*/
#define EEPROM_Block1_ADDRESS 0xA2 /*块1 AT24C04 AT24C08 AT24C16*/
#define EEPROM_Block2_ADDRESS 0xA4 /*块2 AT24C08 AT24C16*/
#define EEPROM_Block3_ADDRESS 0xA6 /*块3 AT24C08 AT24C16*/
#define EEPROM_Block4_ADDRESS 0xA8 /* 块4 AT24C16*/
#define EEPROM_Block5_ADDRESS 0xAA /*块5 AT24C16*/
#define EEPROM_Block6_ADDRESS 0xAC /*块6 AT24C16*/
#define EEPROM_Block7_ADDRESS 0xAE /*块7 AT24C16*/
void I2C_Config(void);
void I2C_Buffer_Write(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite);
uint32_t I2C_Byte_Write(u8* pBuffer, u8 WriteAddr);
uint32_t I2C_Page_Write(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite);
uint32_t I2C_Buffer_Read(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead);
void I2C_WaitEepromStandbyState(void);
#endif /* __I2C_EE_H */