野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 29937|回复: 8

关于STM32 I2C读写外设EEPROM器件AT24C02的问题

[复制链接]
发表于 2014-1-18 09:34:51 | 显示全部楼层 |阅读模式
本帖最后由 ljlucker 于 2014-1-18 09:41 编辑

有ISO例程或者《STM32库开发实战指南》的朋友可以一起来看一下。我在运行自己写的程序或者例程时都会出现一个奇怪的现象。
程序有点长,看过书或者看过例程的朋友主要看重点就可以了,以下是例程:
#include "stm32f10x_conf.h"   
#include "stdio.h"

#define EEPROM_Block0_ADDRESS 0xA0;
#define I2C1_OWN_ADDRESS7 0x0A
#define EEP_Fristpage 0x00
#define I2C_Speed 400000
#define I2C_PageSize 8

uint16_t EEPORM_ADDRESS;

u8 I2C_Buf_Write[256];
u8 I2C_Buf_Read[256];

static void I2C_GPIO_Config(void)//端口配置,这不是重点,可以跳过
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  

  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);
}

static void I2C_Mode_Configu(void)//配置I2C,这也不是重点,可以跳过
{
  I2C_InitTypeDef  I2C_InitStructure;

  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;

  I2C_Init(I2C1, &I2C_InitStructure);

  I2C_Cmd(I2C1, ENABLE);   
}

void I2C_EE_Init(void)//I2C初始化,不是问题重点
{

  I2C_GPIO_Config();

  I2C_Mode_Configu();
}

void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  

  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  I2C_SendData(I2C1, WriteAddr);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_SendData(I2C1, *pBuffer);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_GenerateSTOP(I2C1, ENABLE);
}

void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)//写一页数据,问题在这个程序中
{
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

  I2C_GenerateSTART(I2C1, ENABLE);

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //仿真时,程序一直停在这里执行不下去

  I2C_SendData(I2C1, WriteAddr);  

  while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  while(NumByteToWrite--)  
  {
    I2C_SendData(I2C1, *pBuffer);

    pBuffer++;

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  }

  I2C_GenerateSTOP(I2C1, ENABLE);
}

void I2C_EE_WaitEepromStandbyState(void) //这段程序没问题     
{
  vu16 SR1_Tmp = 0;
  do
  {
    I2C_GenerateSTART(I2C1, ENABLE);

    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
    I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);
  }
        while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));

  I2C_ClearFlag(I2C1, I2C_FLAG_AF);
  I2C_GenerateSTOP(I2C1, ENABLE);
}


//这段程序执行不下去的原因是因为里面调用了void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)程序。
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(Addr == 0)
  {
    if(NumOfPage == 0)
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    else  
    {
      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();
      }
    }
  }
  else
  {
    if(NumOfPage== 0)
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;        

      if(count != 0)
      {  
        I2C_EE_PageWrite(pBuffer, WriteAddr, count);
        I2C_EE_WaitEepromStandbyState();
        WriteAddr += 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();
      }
    }
  }  
}

void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));   

  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  I2C_Cmd(I2C1, ENABLE);

  I2C_SendData(I2C1, ReadAddr);  

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Receiver);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      I2C_AcknowledgeConfig(I2C1, DISABLE);

      I2C_GenerateSTOP(I2C1, ENABLE);
    }

    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
    {      

      *pBuffer = I2C_ReceiveData(I2C1);

      pBuffer++;

      NumByteToRead--;        
    }   
  }

  I2C_AcknowledgeConfig(I2C1, ENABLE);
}

void I2C_Test(void)
{
  u16 i;

  printf("写入数据\n\r");

  for ( i=0; i<=255; i++ )
  {   
    I2C_Buf_Write = i;

    printf("0x%02X ", I2C_Buf_Write);
    if(i%16 == 15)   
        printf("\n\r");   
   }

  I2C_EE_BufferWrite( I2C_Buf_Write,EEP_Fristpage, 256);

  printf("\n\r读出数据\n\r");

  I2C_EE_BufferRead(I2C_Buf_Read,EEP_Fristpage, 256);

  for (i=0; i<256; i++)
  {        
     if(I2C_Buf_Read != I2C_Buf_Write)
     {
        printf("0x%02X ", I2C_Buf_Read);
        printf("错误:I2C EEPROMD写入与读出的数据不一样\n\r");
        return;
     }
    printf("0x%02X ", I2C_Buf_Read);
    if(i%16 == 15) printf("\n\r");
  }
  printf("I2C(AT24C02)测试成功\n\r");
}

哪位高手可以帮忙看一下吗,万能的管理员,我现在很迷惘找不出问题所在,能不能知道我一下。我会很感谢你的。

回复

使用道具 举报

发表于 2014-1-18 09:37:08 | 显示全部楼层
不要仿真,直接运行,仿真的时候有些时序时间你是控制不了的。

要仿真的话可以用模拟I2C的例程。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-18 09:40:27 | 显示全部楼层
fire 发表于 2014-1-18 09:37
不要仿真,直接运行,仿真的时候有些时序时间你是控制不了的。

要仿真的话可以用模拟I2C的例程。

可是我直接运行的时候,只把写入的数据输出了,就是只执行了
  printf(写入数据\n\r");
  for ( i=0; i<=255; i++ )
  {   
    I2C_Buf_Write = i;

    printf("0x%02X ", I2C_Buf_Write);
    if(i%16 == 15)   
    printf("\n\r");  
  }
但是程序里面还有好几个printf的输出信息都没有出现
回复 支持 反对

使用道具 举报

发表于 2014-1-18 09:44:38 | 显示全部楼层
ljlucker 发表于 2014-1-18 09:40
可是我直接运行的时候,只把写入的数据输出了,就是只执行了
  printf(写入数据\n\r");
  for ( i=0; i

直接运行ISO自带的例程可以嘛?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-18 10:04:49 | 显示全部楼层
本帖最后由 ljlucker 于 2014-1-18 10:14 编辑
fire 发表于 2014-1-18 09:44
直接运行ISO自带的例程可以嘛?

自带的可以,但是我把ISO中的bsp_i2c_ee.c里面的内容复制到我自己编的程序里面,再调用就出现问题了,我在想是不是我复制的时候出现问题了。我自己再细心检查一遍。发现问题我再在帖子里总结一下。
能不能再问你一个问题,就是关于void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)这个程序。例程给出的是下面的程序:
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));      
  I2C_GenerateSTART(I2C1, ENABLE);
  
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);

  //作为主机接收为什么不是使用I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED事件
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  I2C_Cmd(I2C1, ENABLE);//这地方为什么要插入这一句
  I2C_SendData(I2C1, ReadAddr);  

  //发送数据之后,作为主机接收为什么不是使用I2C_EVENT_MASTER_BYTE_RECEIVED事件
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  I2C_GenerateSTART(I2C1, ENABLE);//为什么还要调用一次这程序
  
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  
  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Receiver);//为什么又要发一次地址
  
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      I2C_AcknowledgeConfig(I2C1, DISABLE);      
      I2C_GenerateSTOP(I2C1, ENABLE);
    }
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
    {      

      *pBuffer = I2C_ReceiveData(I2C1);
      pBuffer++;      
      NumByteToRead--;        
    }   
  }
  I2C_AcknowledgeConfig(I2C1, ENABLE);
}

看STM32使用手册中I2C主机接受的时序图。先后触发了Ex5(I2C_EVENT_MASTER_MODE_SELECT),
Ex6(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED),Ex7(I2C_EVENT_MASTER_BYTE_RECEIVED)事件。
如果是我自己写的话,我会把读I2C的程序写成下面这样:
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));      
  I2C_GenerateSTART(I2C1, ENABLE);
  
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//检查事件5
  I2C_Send7bitAddress(I2C1,EEPORM_ADDRESS, I2C_Direction_Transmitter);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //检测事件6
  I2C_SendData(I2C1, ReadAddr);   
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));//检测事件7
  
  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      I2C_AcknowledgeConfig(I2C1, DISABLE);     
      I2C_GenerateSTOP(I2C1, ENABLE);
    }
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
    {      
      *pBuffer = I2C_ReceiveData(I2C1);
      pBuffer++;      
      NumByteToRead--;        
    }   
  }
  I2C_AcknowledgeConfig(I2C1, ENABLE);
}

我不懂的地方是,在原ISO例程里面主机接收的程序为什么调用了两次I2C_GenerateSTART(I2C1, ENABLE);还调用了一次I2C_Cmd(I2C1, ENABLE);。可以指出我写的程序出现什么错了吗,把读I2C的这个程序思路讲解一下可以吗。
回复 支持 反对

使用道具 举报

发表于 2014-1-18 16:15:43 | 显示全部楼层
ljlucker 发表于 2014-1-18 10:04
自带的可以,但是我把ISO中的bsp_i2c_ee.c里面的内容复制到我自己编的程序里面,再调用就出现问题了,我在 ...

我同你一样啊啊,我用的是ISO板子,,,用自带程序的硬件I2C没问题,,,但加入了LCD初始化函数后(也是自带的啊!),就不行了,,,后面的printf不输出了,,,火哥求解啊啊啊
回复 支持 反对

使用道具 举报

发表于 2014-1-18 16:16:41 | 显示全部楼层
fire 发表于 2014-1-18 09:44
直接运行ISO自带的例程可以嘛?

火哥,我用的是ISO板子,,,用自带程序的硬件I2C没问题,,,但加入了LCD初始化函数后(也是自带的啊!),就不行了,,,后面的printf不输出了,,,火哥求解啊啊啊
回复 支持 反对

使用道具 举报

发表于 2014-1-18 16:18:12 | 显示全部楼层
asdkouu 发表于 2014-1-18 16:15
我同你一样啊啊,我用的是ISO板子,,,用自带程序的硬件I2C没问题,,,但加入了LCD初始化函数后(也是自 ...

使用了lcd初始化函数的话,要在main函数里把lcd初始化函数放到串口初始化函数的前面,这好像是stm32芯片的bug,fsmc和串口外设同时用的时候就要这样
回复 支持 反对

使用道具 举报

发表于 2014-1-18 16:25:39 | 显示全部楼层
随风 发表于 2014-1-18 16:18
使用了lcd初始化函数的话,要在main函数里把lcd初始化函数放到串口初始化函数的前面,这好像是stm32芯片的 ...

。。。还是不行
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-23 06:22 , Processed in 0.031414 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表