【原创】基于STM32F103的I2C总线EEPROM的读写,带超时检测

  本人最近参考了 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); // 写保护

}