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