[STM32F1]

stm32 硬件i2c读写24c02

[复制链接]
3686|16
手机看帖
扫描二维码
随时随地手机跟帖
swg897570|  楼主 | 2019-3-25 23:05 | 显示全部楼层 |阅读模式
大家好,我刚才用32硬件读写24c02有的地方不明白为什么。上程序,程序测试没有问题
/********************************************************************************
* 文件名  :i2c_ee.c
* 描述    :i2c EEPROM(AT24C02)应用函数库         
* 实验平台:野火STM32开发板
* 硬件连接:-----------------
*          |                 |
*          |  PB6-I2C1_SCL          |
*          |  PB7-I2C1_SDA   |
*          |                 |
*           -----------------
* 库版本  :ST3.5.0
* 作者    :保留
* 论坛    :http://www.amobbs.com/forum-1008-1.html
* 淘宝    :http://firestm32.taobao.com
**********************************************************************************/
#include "24cxx.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_gpio.h"

#define I2C_Speed              100000       //100k 速度
#define I2C1_OWN_ADDRESS7    0x0A           //stm32z自身I2C地址,自己定义的
#define I2C_PageSize           8                        /* AT24C02每页有8个字节 */

u16 EEPROM_ADDRESS;

/*
* 函数名:I2C_GPIO_Config
* 描述  :I2C1 I/O配置
* 输入  :无
* 输出  :无
* 调用  :内部调用
*/
static void I2C_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

        // 使能与 I2C1 有关的时钟 /
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  

  // PB6-I2C1_SCL、PB7-I2C1_SDA/
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;               // 开漏输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/*
* 函数名:I2C_Configuration
* 描述  :I2C 工作模式配置
* 输入  :无
* 输出  :无
* 调用  :内部调用
*/
static void I2C_Mode_Configu(void)
{
  I2C_InitTypeDef  I2C_InitStructure;

  /* I2C 配置 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 =I2C1_OWN_ADDRESS7;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;

  /* 使能 I2C1 */
  I2C_Cmd(I2C1, ENABLE);

  /* I2C1 初始化 */
  I2C_Init(I2C1, &I2C_InitStructure);


}

/*
* 函数名:I2C_EE_Init
* 描述  :I2C 外设(EEPROM)初始化
* 输入  :无
* 输出  :无
* 调用  :外部调用
*/
void I2C_EE_Init(void)
{

  I2C_GPIO_Config();

  I2C_Mode_Configu();

/* 根据头文件i2c_ee.h中的定义来选择EEPROM要写入的地址 */
#ifdef EEPROM_Block0_ADDRESS
  /* 选择 EEPROM Block0 来写入 */
  EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif

#ifdef EEPROM_Block1_ADDRESS  
        /* 选择 EEPROM Block1 来写入 */
  EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif

#ifdef EEPROM_Block2_ADDRESS  
        /* 选择 EEPROM Block2 来写入 */
  EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif

#ifdef EEPROM_Block3_ADDRESS  
        /* 选择 EEPROM Block3 来写入 */
  EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}

/*
* 函数名:I2C_EE_BufferWrite
* 描述  :将缓冲区中的数据写到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_BufferWrite(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) //如果写的小于一页,也就是只写NumOfSingle个数据
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else  //如果写的大于等于一页,也就是写NumOfPage个整页     
    {
      while(NumOfPage--)
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
            I2C_EE_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;
      }

      if(NumOfSingle!=0) //写完整页后剩下的不够一页的
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        I2C_EE_WaitEepromStandbyState();
      }
    }
  }
  /* If WriteAddr is not I2C_PageSize aligned  */
  else //通写入的初始地址不是从页的开始写,这个要比前面的要复杂很多
  {
    /* If NumByteToWrite < I2C_PageSize */
    if(NumOfPage== 0)
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;       

      if(count != 0) //先把第一页的几个数据写进去例如我写的首地址为5,则count=3,则从5写到7
      {  
        I2C_EE_PageWrite(pBuffer, WriteAddr, count);
        I2C_EE_WaitEepromStandbyState();
        WriteAddr += count;   //写地址加上count,前面没有对齐的数据写完,该写中间对齐的部分
        pBuffer += count;
      }

      while(NumOfPage--)
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
        I2C_EE_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;  
      }
      if(NumOfSingle != 0)//最后写最后几个没有对齐的数据,不够一整页
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        I2C_EE_WaitEepromStandbyState();
      }
    }
  }  
}

/*
* 函数名:I2C_EE_ByteWrite
* 描述  :写一个字节到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
  /* Send STRAT condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  /* Send the EEPROM's internal address to write to */
  I2C_SendData(I2C1, WriteAddr);

  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* Send the byte to be written */
  I2C_SendData(I2C1, *pBuffer);

  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* Send STOP condition */
  I2C_GenerateSTOP(I2C1, ENABLE);
}

/*
* 函数名:I2C_EE_PageWrite
* 描述  :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
*         不能超过EEPROM页的大小。AT24C02每页有8个字节。
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008

  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));  

  /* Send the EEPROM's internal address to write to */   
  I2C_SendData(I2C1, WriteAddr);  

  /* Test on EV8 and clear it */
  while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* While there is data to be written */
  while(NumByteToWrite--)  
  {
    /* Send the current byte */
    I2C_SendData(I2C1, *pBuffer);

    /* Point to the next byte to be written */
    pBuffer++;

    /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  }

  /* Send STOP condition */
  I2C_GenerateSTOP(I2C1, ENABLE);
}


/*
* 函数名:I2C_EE_BufferRead
* 描述  :从EEPROM里面读取一块数据。
* 输入  :-pBuffer 存放从EEPROM读取的数据的缓冲区指针。
*         -WriteAddr 接收数据的EEPROM的地址。
*         -NumByteToWrite 要从EEPROM读取的字节数。
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
  //*((u8 *)0x4001080c) |=0x80;
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008


  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);
  //*((u8 *)0x4001080c) &=~0x80;

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2C1, ENABLE);

  /* Send the EEPROM's internal address to write to */
  I2C_SendData(I2C1, ReadAddr);  

  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* Send STRAT condition a second time */  
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send EEPROM address for read */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  /* While there is data to be read */
  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      /* Disable Acknowledgement */
      I2C_AcknowledgeConfig(I2C1, DISABLE);

      /* Send STOP Condition */
      I2C_GenerateSTOP(I2C1, ENABLE);
    }

    /* Test on EV7 and clear it */
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
    {      
      /* Read a byte from the EEPROM */
      *pBuffer = I2C_ReceiveData(I2C1);

      /* Point to the next location where the byte read will be saved */
      pBuffer++;

      /* Decrement the read bytes counter */
      NumByteToRead--;        
    }   
  }

  /* Enable Acknowledgement to be ready for another reception */
  I2C_AcknowledgeConfig(I2C1, ENABLE);
}


/*
* 函数名:I2C_EE_WaitEepromStandbyState
* 描述  :Wait for EEPROM Standby state
* 输入  :无
* 输出  :无
* 返回  :无
* 调用  :
*/
void I2C_EE_WaitEepromStandbyState(void)      
{
  vu16 SR1_Tmp = 0;

  do
  {
    /* Send START condition */
    I2C_GenerateSTART(I2C1, ENABLE);
    /* Read I2C1 SR1 register */
    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
    /* Send EEPROM address for write */
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));

  /* Clear AF flag */
  I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    /* STOP condition */   
    I2C_GenerateSTOP(I2C1, ENABLE);
}

/*************************END OF FILE*************************************/
以下是.h文件内容



#include "stm32f10x_i2c.h"

/* EEPROM Addresses defines */
#define EEPROM_Block0_ADDRESS 0xA0   /* E2 = 0 *///AT24C0x的I2C硬件地址
//#define EEPROM_Block1_ADDRESS 0xA2 /* E2 = 0 */
//#define EEPROM_Block2_ADDRESS 0xA4 /* E2 = 0 */
//#define EEPROM_Block3_ADDRESS 0xA6 /* E2 = 0 */

void I2C_EE_Init(void);
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite);
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr);
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite);
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead);
void I2C_EE_WaitEepromStandbyState(void);



/*---------------------------------------------以下是我程序----------------------------------------------*/
int main(void)
{
        init_int();                   //系统初始化
        IWDG_Init() ;                 //看门狗
    delay_init();                      // * 系统时钟SysTick         即滴答定时器
    I2C_EE_Init();                //24c02 i2c
        preg_open();                  //开机数码管显示
       

       
        WriteBuffer[0]=1;
    WriteBuffer[1]=2;
        WriteBuffer[2]=3;
        WriteBuffer[3]=4;
        WriteBuffer[4]=5;
       
    WriteBuffer[8]=10;
    WriteBuffer[9]=20;
        WriteBuffer[10]=30;
        WriteBuffer[11]=40;
        WriteBuffer[12]=50;
       

            
        while(1)
        {       


     delay_ms(1);                     //延时1ms
     PCout(13)=~PCout(13);           //led 闪烁
        // set.dlsplay_num=keyscan();      //读取按键值
               
     display(num.dot_on,num.dot_bit,num.play_min,num.play_max,num.flicker_bit);          //显示函数
     set_disp(set.dlsplay_xze,set.dlsplay_num,set.dlsplay_shi,set.dlsplay_ge,set.dlsplay_bit,set.display_led,FZ.shiwan,FZ.wan,FZ.qian,FZ.bai,FZ.shi,FZ.ge);      
        // delay_ms(1);                     //延时1ms
     abc=keyscan();      //读取按键值
                if(abc==16)
                {
             I2C_EE_BufferWrite(WriteBuffer,0,8);  //写入
                }else         if(abc==32)
                {
                eprom_out();                    //数据读取
                set.dlsplay_num=ReadBuffer[1];       
                }
               
         IWDG->KR=0XAAAA;   //清看门狗  
        }
       
       
}

void eprom_out(void)    //  数据读取
{
          I2C_EE_BufferRead(ReadBuffer,0,8);    //读取
}

/*-------------------------------------------------------*/
问题1:void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)   Buffer这个是要保持的数据8位,WriteAddr是页地址吗?24c02是256页 每页8字节,NumByteToWrite这个是指要保持数据字节数量吗?
我试了一下  I2C_EE_BufferWrite(WriteBuffer,0,8);  //写入  这个意思是WriteBuffer数组里面有8个字节写入0页地址?但是我看了一下如果8改256可以全部写入,不明白为什么?
问题2: I2C_EE_BufferWrite(WriteBuffer,0,8); 这个如何保存一个单一的8位数据,而不是用数组,有时候数组不方便






使用特权

评论回复
玛尼玛尼哄| | 2019-3-25 23:37 | 显示全部楼层
肯定不是页地址了。擦 的时候才按页

使用特权

评论回复
gaoke231| | 2019-3-26 08:20 | 显示全部楼层
硬件IIC 不是有点bug  用模拟IIC试一下

使用特权

评论回复
swg897570|  楼主 | 2019-3-26 09:10 | 显示全部楼层
gaoke231 发表于 2019-3-26 08:20
硬件IIC 不是有点bug  用模拟IIC试一下

硬件还是可以实现的,读写也没有什么问题

使用特权

评论回复
swg897570|  楼主 | 2019-3-26 09:11 | 显示全部楼层
玛尼玛尼哄 发表于 2019-3-25 23:37
肯定不是页地址了。擦 的时候才按页

那个是什么?

使用特权

评论回复
lolplmlk| | 2019-3-26 13:52 | 显示全部楼层
可以用结构体保存数据

使用特权

评论回复
蝴蝶泉2018| | 2019-3-26 17:16 | 显示全部楼层
考虑一下eeprom的特点吧。如果每页是8个字节,那么一次烧录最多就是8个字节(地址需要要对齐)。 超过此页地址的话,下一个字节又从此页首地址来了。
EEPROM 手册上有写这些的

使用特权

评论回复
swg897570|  楼主 | 2019-3-31 17:13 | 显示全部楼层
蝴蝶泉2018 发表于 2019-3-26 17:16
考虑一下eeprom的特点吧。如果每页是8个字节,那么一次烧录最多就是8个字节(地址需要要对齐)。 超过此页 ...

谢谢  我看一下

使用特权

评论回复
hanzhen654| | 2019-3-31 19:18 | 显示全部楼层
火哥的代码应该没问题,仔细检查下代码

使用特权

评论回复
swg897570|  楼主 | 2019-4-3 21:33 | 显示全部楼层

/********************************************************************************
* 文件名  :i2c_ee.c
* 描述    :i2c EEPROM(AT24C02)应用函数库         
* 实验平台:野火STM32开发板
* 硬件连接:-----------------
*          |                 |
*          |  PB6-I2C1_SCL          |
*          |  PB7-I2C1_SDA   |
*          |                 |
*           -----------------
* 库版本  :ST3.5.0
* 作者    :保留
* 论坛    :http://www.amobbs.com/forum-1008-1.html
* 淘宝    :http://firestm32.taobao.com
**********************************************************************************/
#include "24cxx.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_gpio.h"

#define I2C_Speed              100000       //100k 速度
#define I2C1_OWN_ADDRESS7    0x0A           //stm32z自身I2C地址,自己定义的
#define I2C_PageSize           8                        /* AT24C02每页有8个字节 */

u16 EEPROM_ADDRESS;

/*
* 函数名:I2C_GPIO_Config
* 描述  :I2C1 I/O配置
* 输入  :无
* 输出  :无
* 调用  :内部调用
*/
static void I2C_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

        // 使能与 I2C1 有关的时钟 /
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  
   
  // PB6-I2C1_SCL、PB7-I2C1_SDA/
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;               // 开漏输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}






/*
* 函数名:I2C_Configuration
* 描述  :I2C 工作模式配置
* 输入  :无
* 输出  :无
* 调用  :内部调用
*/
static void I2C_Mode_Configu(void)
{
  I2C_InitTypeDef  I2C_InitStructure;

  /* I2C 配置 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 =I2C1_OWN_ADDRESS7;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
  
  /* 使能 I2C1 */
  I2C_Cmd(I2C1, ENABLE);

  /* I2C1 初始化 */
  I2C_Init(I2C1, &I2C_InitStructure);

   
}

/*
* 函数名:I2C_EE_Init
* 描述  :I2C 外设(EEPROM)初始化
* 输入  :无
* 输出  :无
* 调用  :外部调用
*/
void I2C_EE_Init(void)
{

  I2C_GPIO_Config();

  I2C_Mode_Configu();

/* 根据头文件i2c_ee.h中的定义来选择EEPROM要写入的地址 */
#ifdef EEPROM_Block0_ADDRESS
  /* 选择 EEPROM Block0 来写入 */
  EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif

#ifdef EEPROM_Block1_ADDRESS  
        /* 选择 EEPROM Block1 来写入 */
  EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif

#ifdef EEPROM_Block2_ADDRESS  
        /* 选择 EEPROM Block2 来写入 */
  EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif

#ifdef EEPROM_Block3_ADDRESS  
        /* 选择 EEPROM Block3 来写入 */
  EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}

/*
* 函数名:I2C_EE_BufferWrite
* 描述  :将缓冲区中的数据写到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_BufferWrite(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) //如果写的小于一页,也就是只写NumOfSingle个数据
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else  //如果写的大于等于一页,也就是写NumOfPage个整页     
    {
      while(NumOfPage--)
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
            I2C_EE_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;
      }

      if(NumOfSingle!=0) //写完整页后剩下的不够一页的
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        I2C_EE_WaitEepromStandbyState();
      }
    }
  }
  /* If WriteAddr is not I2C_PageSize aligned  */
  else //通写入的初始地址不是从页的开始写,这个要比前面的要复杂很多
  {
    /* If NumByteToWrite < I2C_PageSize */
    if(NumOfPage== 0)
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;       
      
      if(count != 0) //先把第一页的几个数据写进去例如我写的首地址为5,则count=3,则从5写到7
      {  
        I2C_EE_PageWrite(pBuffer, WriteAddr, count);
        I2C_EE_WaitEepromStandbyState();
        WriteAddr += count;   //写地址加上count,前面没有对齐的数据写完,该写中间对齐的部分
        pBuffer += count;
      }
      
      while(NumOfPage--)
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
        I2C_EE_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;  
      }
      if(NumOfSingle != 0)//最后写最后几个没有对齐的数据,不够一整页
      {
        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        I2C_EE_WaitEepromStandbyState();
      }
    }
  }  
}

/*
* 函数名:I2C_EE_ByteWrite
* 描述  :写一个字节到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
  /* Send STRAT condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
      
  /* Send the EEPROM's internal address to write to */
  I2C_SendData(I2C1, WriteAddr);
  
  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* Send the byte to be written */
  I2C_SendData(I2C1, *pBuffer);
   
  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  
  /* Send STOP condition */
  I2C_GenerateSTOP(I2C1, ENABLE);
}

/*
* 函数名:I2C_EE_PageWrite
* 描述  :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
*         不能超过EEPROM页的大小。AT24C02每页有8个字节。
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
   
  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);
  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
  
  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));  

  /* Send the EEPROM's internal address to write to */   
  I2C_SendData(I2C1, WriteAddr);  

  /* Test on EV8 and clear it */
  while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* While there is data to be written */
  while(NumByteToWrite--)  
  {
    /* Send the current byte */
    I2C_SendData(I2C1, *pBuffer);

    /* Point to the next byte to be written */
    pBuffer++;
  
    /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  }

  /* Send STOP condition */
  I2C_GenerateSTOP(I2C1, ENABLE);
}


/*
* 函数名:I2C_EE_BufferRead
* 描述  :从EEPROM里面读取一块数据。
* 输入  :-pBuffer 存放从EEPROM读取的数据的缓冲区指针。
*         -WriteAddr 接收数据的EEPROM的地址。
*         -NumByteToWrite 要从EEPROM读取的字节数。
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
  //*((u8 *)0x4001080c) |=0x80;
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
   
   
  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);
  //*((u8 *)0x4001080c) &=~0x80;
  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
  
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2C1, ENABLE);

  /* Send the EEPROM's internal address to write to */
  I2C_SendData(I2C1, ReadAddr);  

  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  
  /* Send STRAT condition a second time */  
  I2C_GenerateSTART(I2C1, ENABLE);
  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
  
  /* Send EEPROM address for read */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);
  
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
  
  /* While there is data to be read */
  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      /* Disable Acknowledgement */
      I2C_AcknowledgeConfig(I2C1, DISABLE);
      
      /* Send STOP Condition */
      I2C_GenerateSTOP(I2C1, ENABLE);
    }

    /* Test on EV7 and clear it */
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
    {      
      /* Read a byte from the EEPROM */
      *pBuffer = I2C_ReceiveData(I2C1);

      /* Point to the next location where the byte read will be saved */
      pBuffer++;
      
      /* Decrement the read bytes counter */
      NumByteToRead--;        
    }   
  }

  /* Enable Acknowledgement to be ready for another reception */
  I2C_AcknowledgeConfig(I2C1, ENABLE);
}


/*
* 函数名:I2C_EE_WaitEepromStandbyState
* 描述  :Wait for EEPROM Standby state
* 输入  :无
* 输出  :无
* 返回  :无
* 调用  :
*/
void I2C_EE_WaitEepromStandbyState(void)      
{
  vu16 SR1_Tmp = 0;

  do
  {
    /* Send START condition */
    I2C_GenerateSTART(I2C1, ENABLE);
    /* Read I2C1 SR1 register */
    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
    /* Send EEPROM address for write */
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
  
  /* Clear AF flag */
  I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    /* STOP condition */   
    I2C_GenerateSTOP(I2C1, ENABLE);
}




/*--------------------------------8位-----------------------------------------*/
void EEPROM_W8(u8 add,u8 data)       //写一个字节数据
  {
    I2C_EE_BufferWrite(&data,add,1);   
}

unsigned char EEPROM_r8(u8 add)      //读一个字节数据
  {
    u8 data ;
    I2C_EE_BufferRead(&data,add,1);    //读取     
    return(data);
}
  
/*--------------------------------16位-----------------------------------------*/
void EEPROM_W16(u8 add,u16 data)       //写2个字节数据
  {
    u16 data_1;
    u8 data_h,data_L;
          
    data_1=data>>8;
    data_h=data_1;
    data_L=data;
    I2C_EE_BufferWrite(&data_h,add,1);   
    I2C_EE_BufferWrite(&data_L,add+1,1);
}
  
unsigned int EEPROM_r16(u8 add)      //读2个字节数据
  {
     u16 data ,data_k;
     u8 data_h,data_l;

         I2C_EE_BufferRead(&data_h,add,1);    //读取
     I2C_EE_BufferRead(&data_l,add+1,1);    //读取
     data_k=data_h;
     data=data_k<<8;
     data=data+data_l;
     return(data);
}
/*---------------------------------32位----------------------------------------------------*/
void EEPROM_W32(u8 add,u32 data)       //写4个字节数据
  {
          u8 data1,data2,data3,data4;
          
          data1=data>>24;   
          data2=data>>16;
          data3=data>>8;
          data4=data;
          
      EEPROM_W8(add,data1) ;      //写一个字节数据
      EEPROM_W8(add+1,data2);       //写一个字节数据
          EEPROM_W8(add+2,data3);      //写一个字节数据
          EEPROM_W8(add+3,data4);      //写一个字节数据
}

unsigned long  EEPROM_r32(u8 add)      //读4个字节数据
  {
    u32 data_32_1,data_32_2,data_32_3,data_32_4;
    u32  data;
          
   
     data_32_1=EEPROM_r8(add);
     data_32_2=EEPROM_r8(add+1);  
     data_32_3=EEPROM_r8(add+2);  
     data_32_4=EEPROM_r8(add+3);  
          
     data_32_1=data_32_1<<24;
     data_32_2=data_32_2<<16;
     data_32_3=data_32_3<<8;
     data=data_32_1+data_32_2+data_32_3+data_32_4;
     return(data);
}

/*************************END OF FILE*************************************/

搞定了,之前一直认为是一个页地址可以放8个char型,后来仔细看了一下,一页应该只能放一个char  256页 2kb  2402

优化了一下

                        EEPROM_W16(0x00,1000) ;
                        EEPROM_W16(0x02,2000);       写  0x02  地址     2000数据


                       ReadBuffer2[1]=EEPROM_r16(0x00) ;   //读取数据
                      ReadBuffer2[2]=EEPROM_r16(0x02) ;

使用特权

评论回复
paotangsan| | 2019-4-10 10:34 | 显示全部楼层
用模拟的试试看

使用特权

评论回复
wowu| | 2019-4-10 11:12 | 显示全部楼层
非常感谢楼主分享

使用特权

评论回复
磨砂| | 2019-4-11 08:26 | 显示全部楼层
使用模拟iic试试看

使用特权

评论回复
蝴蝶泉2018| | 2019-5-15 12:11 | 显示全部楼层
从另一角度讲,模拟I2C也有很多好处。首先,它比较灵活,很方便调试,每个信号的输出都可以暂停调试,遇到异常容易发现(这个是开发人员喜欢的)。其次,处理异常也非常方便,不行就重发嘛,对于总线被拉住时尤其方便。最后不受管脚分布限制(当然,强烈建议设置OPENDRAIN 模式)。 缺点也是有的:首先不方便做从设备,其次占用CPU时间稍多,速度稍慢一些,对I2C 通许协议要了解多一点。我个人喜欢参考EEPROM手册中的时序图写模拟I2C

使用特权

评论回复
wangjiahao88| | 2019-5-16 08:19 | 显示全部楼层
感觉 硬件读写 不如软件读写的好用!

使用特权

评论回复
swg897570|  楼主 | 2019-6-18 22:01 | 显示全部楼层
硬件i2c st的有bagel,改模拟了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名: http://swg8888.taobao.com/

27

主题

142

帖子

1

粉丝