本人最近参考了 st 公司关于STM32的I2C的例程,觉得不是很适合我的应用,于是自己写了一个基于STM32F103的I2C总线EEPROM(24C256)的读写程序,总线的最高速度可达400K,现在将源代码原原本本的公布如下,希望得到高手的指点,也希望能够给和我有同样想法的同仁们一些参考价值。
注意:最好将固件库升级一下,st网站上面有 V2.03库的补丁。
u32 ulTimeOut_Time;
/*
*********************************************************************************************************
* I2C_EE_WriteStr()
*
* Description : 将一个数据块写入EEPROM 的指定的地址
*
* Argument(s) : xChip - 从器件地址
* xAddr - EEPROM存储空间地址
* xpBuf - 数据缓冲区指针
* xLen - 数据长度
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
void I2C_EE_WriteStr(u8 xChip, u16 xAddr, u8 *xpBuf, u16 xLen)
{
u8 *pbuf;
u8 err;
u8 retry;
u16 addr;
u16 len;
//
pbuf = xpBuf;
addr = xAddr;
len = xLen;
I2C_EE_Drv_BusEn(); // 允许总线,写允许
retry = 5; // 重试5次
while(len)
{
err = I2C_EE_Drv_WriteByte(xChip, addr, *pbuf);
if(err)
{
if(--retry == 0 ) // 已经试了5次,写下一个数据
{
retry = 5;
pbuf++;
addr++;
len--;
}
}
else // 顺利,写下一个数据
{
pbuf++;
addr++;
len--;
}
}
I2C_EE_Drv_BusDis(); // 失能总线,写保护
}
/*
*********************************************************************************************************
* I2C_EE_ReadStr()
*
* Description : 从EEPROM 的指定的地址读出一个数据块
*
* Argument(s) : xChip - 从器件地址
* xAddr - EEPROM存储空间地址
* xpBuf - 数据缓冲区指针
* xLen - 数据长度
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
void I2C_EE_ReadStr(u8 xChip, u16 xAddr, u8 *xpBuf, u16 xLen)
{
u8 *pbuf;
u8 err;
u8 retry;
u16 addr;
u16 len;
//
pbuf = xpBuf;
addr = xAddr;
len = xLen;
I2C_EE_Drv_BusEn(); // 允许总线,写允许
retry = 5; // 重试5次
while(len)
{
*pbuf = I2C_EE_Drv_ReadByte(xChip, addr, &err);
if(err)
{
if(--retry == 0) // 已经试了5次,读下一个数据
{
retry = 5;
pbuf++;
addr++;
len--;
}
}
else // 顺利,读下一个数据
{
pbuf++;
addr++;
len--;
}
}
I2C_EE_Drv_BusDis(); // 失能总线,写保护
}
/*
*********************************************************************************************************
* I2C_EE_Drv_Init()
*
* Description : I2C1初始化,默认情况下,I2C接口工作在从模式下。
*
* Argument(s) : xI2C_EE_Speed - 总显的速度 100000 - 400000
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
void I2C_EE_Drv_Init( u32 xI2C_EE_Speed )
{
I2C_InitTypeDef i2c_Init;
GPIO_InitTypeDef gpio_Init;
RCC_ClocksTypeDef rcc_clocks;
//
BSP_PeriphEn(I2C1_PORT_ID);
BSP_PeriphEn(I2C1_WP_PORT_ID);
BSP_PeriphEn(BSP_PERIPH_ID_I2C1); // 给 I2C1 加载时钟
//--------- Configure I2C1 pins: SCL and SDA ------
gpio_Init.GPIO_Pin = I2C1_SCL_Bit | I2C1_SDA_Bit;
gpio_Init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_Init.GPIO_Mode = GPIO_Mode_AF_OD; // 复用功能开漏输出模式
GPIO_Init(I2C1_Port, &gpio_Init);
gpio_Init.GPIO_Pin = I2C1_WP_Bit;
gpio_Init.GPIO_Speed = GPIO_Speed_10MHz;
gpio_Init.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出模式
GPIO_Init(I2C1_WP_Port, &gpio_Init);
//----------- I2C1 configuration ------------------
i2c_Init.I2C_Mode = I2C_Mode_I2C;
i2c_Init.I2C_DutyCycle = I2C_DutyCycle_2;
i2c_Init.I2C_OwnAddress1 = I2C_EE_24C256_PARA;
i2c_Init.I2C_Ack = I2C_Ack_Enable;
i2c_Init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
i2c_Init.I2C_ClockSpeed = xI2C_EE_Speed;
I2C_Init(I2C1, &i2c_Init);
BSP_IntDis(BSP_INT_ID_I2C1_EV); // 失能事件中断
BSP_IntDis(BSP_INT_ID_I2C1_ER); // 失能错误中断
I2C_EE_Drv_BusDis();
//-------------------------------------------
// 超时时间计算(5ms 超时)
//-------------------------------------------
RCC_GetClocksFreq(&rcc_clocks);
ulTimeOut_Time = (rcc_clocks.SYSCLK_Frequency /10 *5 /1000); // 等待程序的执行时间:10 个指令周期
}
/*
*********************************************************************************************************
* I2C_EE_Drv_WriteByte()
*
* Description : 将一个字节的数据写入EEPROM 的指定的地址
* 字节写模式:
*
* 起始信号
* -> 从器件地址( 包括写命令 )
* [a]-> EEPROM存储空间地址高字节
* [a]-> EEPROM存储空间地址低字节
* [a]-> 数据
* [a]-> 停止信号
*
* 共4次[a] (注:[a] - Ack 应答信号 )
*
*
* Argument(s) : xChip - 从器件地址
* xAddr - EEPROM存储空间地址
* xDat - 数据
*
* Return(s) : errcnt - 操作的结果 >0 : 操作出现错误
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
u8 I2C_EE_Drv_WriteByte(u8 xChip, u16 xAddr, u8 xDat)
{
u32 tmr;
u8 errcnt;
// _WriteEn(); // 写使能
// I2C_Cmd(I2C1, ENABLE); // 使能总线
errcnt = 0;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE); // 发送I2C的START信号,接口自动从从设备编程主设备
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))); // 检查I2C的EV5状态并清除
if(tmr ==0) errcnt++;
I2C_Send7bitAddress(I2C1, xChip, I2C_Direction_Transmitter); // 发送从地址(EEPROM设备地址)
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)));// 检查I2C的EV6状态并清除
if(tmr ==0) errcnt++;
I2C_SendData(I2C1, (u8)((xAddr >>8)&0x00ff)); // 发送 EEPROM 的存储空间地址(高字节)
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))); // 检查I2C的EV8状态并清除
if(tmr ==0) errcnt++;
I2C_SendData(I2C1, (u8)(xAddr&0x00ff)); // 发送 EEPROM 的存储空间地址(低字节)
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))); // 检查I2C的EV8状态并清除
if(tmr ==0) errcnt++;
I2C_SendData(I2C1, xDat); // 发送数据
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))); // 检查I2C的EV8状态并清除
if(tmr ==0) errcnt++;
I2C_GenerateSTOP(I2C1, ENABLE); // 发送I2C的STOP信号,接口自动从主设备编程从设备
// _WriteDis(); // 写失能
// I2C_Cmd(I2C1, DISABLE); // 失能总线
return(errcnt);
}
/*
*********************************************************************************************************
* I2C_EE_Drv_ReadByte()
*
* Description : 从EEPROM 的指定的地址读出一个字节的数据
* 选择/随机读操作:允许主器件对寄存器的任意字节进行读操作
*
* 起始信号
* -> 从器件地址( 包括写命令 )
* [a]-> EEPROM存储空间地址高字节
* [a]-> EEPROM存储空间地址低字节
* [a]-> 起始信号
* -> 从器件地址( 包括读命令 )
* [a]-> 得到数据
* -> 停止信号
*
* 共4次[a] (注:[a] - Ack 应答信号 )
*
* Argument(s) : xChip - 从器件地址
* xAddr - EEPROM存储空间地址
* xpErr - 用于返回操作结果 >0 : 操作出现错误
*
* Return(s) : 读到的数据.
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
u8 I2C_EE_Drv_ReadByte(u8 xChip, u16 xAddr, u8 *xpErr)
{
u8 dat;
u8 errcnt;
u32 tmr;
//
// _WriteEn(); // 写使能
// I2C_Cmd(I2C1, ENABLE); // 使能总线
errcnt = 0;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE); // 发送I2C的START信号,接口自动从从设备编程主设备
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))); // 检查I2C的EV5状态并清除
if(tmr ==0) errcnt++;
I2C_Send7bitAddress(I2C1, xChip, I2C_Direction_Transmitter); // 发送从地址(EEPROM设备地址)和写命令
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)));// 检查I2C的EV6状态并清除
if(tmr ==0) errcnt++;
I2C_SendData(I2C1, (u8)((xAddr >>8)&0x00ff)); // 发送 EEPROM 的存储空间地址(高字节)
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))); // 检查I2C的EV8状态并清除
if(tmr ==0) errcnt++;
I2C_SendData(I2C1, (u8)(xAddr&0x00ff)); // 发送 EEPROM 的存储空间地址(低字节)
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))); // 检查I2C的EV8状态并清除
if(tmr ==0) errcnt++;
I2C_GenerateSTART(I2C1, ENABLE); // 发送I2C的START信号,接口自动从从设备编程主设备
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))); // 检查I2C的EV5状态并清除
if(tmr ==0) errcnt++;
I2C_Send7bitAddress(I2C1, xChip, I2C_Direction_Receiver); // 发送从地址(EEPROM设备地址)和读命令
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))); // 检查I2C的EV6状态并清除
if(tmr ==0) errcnt++;
tmr = ulTimeOut_Time;
while((tmr--)&&(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))); // 检查I2C的EV7状态并清除
if(tmr ==0) errcnt++;
*xpErr = errcnt;
dat = I2C_ReceiveData(I2C1); // 接收数据
I2C_GenerateSTOP(I2C1, ENABLE); // 发送I2C的STOP信号,接口自动从主设备编程从设备
// _WriteDis(); // 写失能
// I2C_Cmd(I2C1, DISABLE); // 失能总线
return(dat);
}
/*
*********************************************************************************************************
* I2C_EE_Drv_WriteEn(), I2C_EE_Drv_WriteDis()
*
* Description : write protect 0: 写允许 1: 写保护
*
* Argument(s) : none.
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : (1)
*-------------------------------------------------------------------------------------------------------
* Modified by :
* Modified date :
* Description :
*-------------------------------------------------------------------------------------------------------
*********************************************************************************************************
*/
void I2C_EE_Drv_BusEn(void)
{
GPIO_ResetBits(I2C1_WP_Port,I2C1_WP_Bit); // 写允许
I2C_Cmd(I2C1, ENABLE); // 使能总线
}
void I2C_EE_Drv_BusDis(void)
{
I2C_Cmd(I2C1, DISABLE); // 失能总线
GPIO_SetBits(I2C1_WP_Port,I2C1_WP_Bit); // 写保护
}