搜索
bottom↓
回复: 272

被STM32的I2C调戏了两天,终于花半小时用模拟I2C将其消灭,公布代码

  [复制链接]

出1070入962汤圆

发表于 2009-7-13 14:54:35 | 显示全部楼层 |阅读模式
这个模拟I2C的代码也是在本站下载的,原来是访问EEPROM的。

我使用STM32来访问I2C接口的铁电存储器,FM24CL16,2K字节,比访问EEPROM要方便一点,所以简单修改了一下,比原来少很多。

感谢ground网友提供的原始代码! FM24CL16的手册由于文件服务器问题,暂时传不上来。等阿莫弄好了再传吧。


代码就不打包了,直接贴上来了
=================================
I2C的引脚配置:

/* Configure I2C1 pins: SCL and SDA */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
=================================
/*******************************************************************************
* File Name          : i2c_fram.h
* Author             : MCD Application Team
* Version            : V2.0.1
* Date               : 06/13/2008
* Description        : Header for i2c_ee.c module
*******************************************************************************/
/* Define to prevent recursive inclusion ------------------------------------ */
#ifndef __I2C_FRAM_H
#define __I2C_FRAM_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/


/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */


bool I2C_FRAM_BufferWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite);
bool I2C_FRAM_BufferRead(u8* pBuffer, u16 ReadAddr, u16 NumByteToRead);

#endif /* __I2C_FRAM_H */

=================================
/*******************************************************************************
* File Name          : i2c_fram.c
* Author             : Appcat
* Version            : V0.0.1
* Date               : 07/11/2009
* Description        : This file provides a set of functions needed to manage the
*                      communication between I2C peripheral and I2C FM24CL16 FRAM.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "i2c_fram.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define I2C_Speed              100000
#define I2C1_SLAVE_ADDRESS7    0xA0
#define I2C_PageSize           256

#define SCL_H         GPIOB->BSRR = GPIO_Pin_6
#define SCL_L         GPIOB->BRR  = GPIO_Pin_6
   
#define SDA_H         GPIOB->BSRR = GPIO_Pin_7
#define SDA_L         GPIOB->BRR  = GPIO_Pin_7

#define SCL_read      GPIOB->IDR  & GPIO_Pin_6
#define SDA_read      GPIOB->IDR  & GPIO_Pin_7


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
vu8 FRAM_ADDRESS;

/* Private function prototypes -----------------------------------------------*/

/**/
void I2C_delay(void)
{       
   u8 i=150; //这里可以优化速度        ,经测试最低到5还能写入
   while(i)
   {
     i--;
   }
}

bool I2C_Start(void)
{
        SDA_H;
        SCL_H;
        I2C_delay();
        if(!SDA_read)return FALSE;        //SDA线为低电平则总线忙,退出
        SDA_L;
        I2C_delay();
        if(SDA_read) return FALSE;        //SDA线为高电平则总线出错,退出
        SDA_L;
        I2C_delay();
        return TRUE;
}

void I2C_Stop(void)
{
        SCL_L;
        I2C_delay();
        SDA_L;
        I2C_delay();
        SCL_H;
        I2C_delay();
        SDA_H;
        I2C_delay();
}

void I2C_Ack(void)
{       
        SCL_L;
        I2C_delay();
        SDA_L;
        I2C_delay();
        SCL_H;
        I2C_delay();
        SCL_L;
        I2C_delay();
}

void I2C_NoAck(void)
{       
        SCL_L;
        I2C_delay();
        SDA_H;
        I2C_delay();
        SCL_H;
        I2C_delay();
        SCL_L;
        I2C_delay();
}

bool I2C_WaitAck(void)          //返回为:=1有ACK,=0无ACK
{
        SCL_L;
        I2C_delay();
        SDA_H;                       
        I2C_delay();
        SCL_H;
        I2C_delay();
        if(SDA_read)
        {
      SCL_L;
      return FALSE;
        }
        SCL_L;
        return TRUE;
}

void I2C_SendByte(u8 SendByte) //数据从高位到低位//
{
    u8 i=8;
    while(i--)
    {
        SCL_L;
        I2C_delay();
      if(SendByte&0x80)
        SDA_H;  
      else
        SDA_L;   
        SendByte<<=1;
        I2C_delay();
                SCL_H;
        I2C_delay();
    }
    SCL_L;
}

u8 I2C_ReceiveByte(void)  //数据从高位到低位//
{
    u8 i=8;
    u8 ReceiveByte=0;

    SDA_H;                               
    while(i--)
    {
      ReceiveByte<<=1;      
      SCL_L;
      I2C_delay();
          SCL_H;
      I2C_delay();       
      if(SDA_read)
      {
        ReceiveByte|=0x01;
      }
    }
    SCL_L;
    return ReceiveByte;
}

bool I2C_FRAM_BufferWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
        u8 Addr = 0, count = 0;

        Addr = WriteAddr / I2C_PageSize;

        count = WriteAddr % I2C_PageSize;

        Addr = Addr << 1;

        Addr = Addr & 0x0F;  

        FRAM_ADDRESS = I2C1_SLAVE_ADDRESS7 | Addr;

    if (!I2C_Start()) return FALSE;
    I2C_SendByte(FRAM_ADDRESS);//设置器件地址+段地址
    if (!I2C_WaitAck())
        {
                I2C_Stop();
                return FALSE;
        }
    I2C_SendByte(count);   //设置段内地址      
        I2C_WaitAck();       
          
        while(NumByteToWrite--)
        {
          I2C_SendByte(* pBuffer);
          I2C_WaitAck();
      pBuffer++;
        }
        I2C_Stop();
          //注意:因为这里要等待EEPROM写完,可以采用查询或延时方式(10ms)
          //Systick_Delay_1ms(10);
        return TRUE;
}


//读出1串数据         
bool I2C_FRAM_BufferRead(u8* pBuffer, u16 WriteAddr, u16 NumByteToRead)
{               
        u8 Addr = 0, count = 0;

    Addr = WriteAddr / I2C_PageSize;

        count = WriteAddr % I2C_PageSize;

        Addr = Addr << 1;

        Addr = Addr & 0x0F;  

        FRAM_ADDRESS = I2C1_SLAVE_ADDRESS7 | Addr;
       
        if (!I2C_Start()) return FALSE;

    I2C_SendByte(FRAM_ADDRESS);//设置器件地址+段地址

    if (!I2C_WaitAck())
        {
                I2C_Stop();
                return FALSE;
        }

    I2C_SendByte(count);   //设置低起始地址      
    I2C_WaitAck();
    I2C_Start();
    I2C_SendByte(FRAM_ADDRESS | 0x01);
    I2C_WaitAck();
    while(NumByteToRead)
    {
      *pBuffer = I2C_ReceiveByte();
      if(NumByteToRead == 1)I2C_NoAck();
      else I2C_Ack();
      pBuffer++;
      NumByteToRead--;
    }
    I2C_Stop();
    return TRUE;
}

=================================

出0入0汤圆

发表于 2009-7-13 14:58:29 | 显示全部楼层
怎么不用硬件的I2C,要用模拟的呢?

出0入0汤圆

发表于 2009-7-13 14:59:27 | 显示全部楼层
up

出0入0汤圆

发表于 2009-7-13 15:25:22 | 显示全部楼层
CPU速度越快,相对来说,模拟I2C效率也就越低。

出1070入962汤圆

 楼主| 发表于 2009-7-13 15:34:01 | 显示全部楼层
咱这是具体问题具体对待,STM32的硬件I2C我不敢说它次,是我水平太次了,光那几个标志位都搞晕了。所以用了模拟的I2C。我就郁闷,挺简单一个东西,给STM32搞的这么高深,不服不行啊。

出0入0汤圆

发表于 2009-7-13 15:39:17 | 显示全部楼层
北纬 22°32' 03" 东经 114°01' 06"
--------------------------------------------------
深航大夏?

出0入0汤圆

发表于 2009-7-13 15:48:58 | 显示全部楼层
北纬 22°32' 03" 东经 114°01' 06"
深航大夏?
---------------------------------
很近了。

经纬度取的是谷歌地球上面显示的经纬度。

出0入0汤圆

发表于 2009-7-13 16:12:50 | 显示全部楼层
前段时间也用模拟的实现了

出0入0汤圆

发表于 2009-7-13 16:21:56 | 显示全部楼层
车公庙,海松大厦,我曾在那里工作,公司现已迁入科技园北区。

出0入0汤圆

发表于 2009-7-13 22:17:26 | 显示全部楼层
我有同感,也调STM32的I2C半天,连I2C启动波形都调不出来,最后还是用模拟I2C搞定了

出0入0汤圆

发表于 2009-7-24 17:02:51 | 显示全部楼层
我用中断方式调了半天,一点头绪都没。查询方式还是可以调的,半天也就好了。实在佩服ST把I2C搞成这样,累啊!

出0入0汤圆

发表于 2009-7-24 17:42:23 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-7-24 17:43:45 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-7-24 18:37:02 | 显示全部楼层
用STM32硬件IIC的示例代码,没有出过问题
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name          : i2c_ee.c
* Author             : MCD Application Team
* Version            : V2.0.1
* Date               : 06/13/2008
* Description        : This file provides a set of functions needed to manage the
*                      communication between I2C peripheral and I2C M24C08 EEPROM.
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "i2c_ee.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define I2C_Speed              100000//400000
#define I2C1_SLAVE_ADDRESS7    0xA0
#define I2C_PageSize           16

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u16 EEPROM_ADDRESS;

/* Private function prototypes -----------------------------------------------*/
void I2C_Configuration(void);

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
* Function Name  : I2C_Configuration
* Description    : I2C Configuration
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void I2C_Configuration(void)
{
  I2C_InitTypeDef  I2C_InitStructure;

  /* I2C configuration */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
  
  /* I2C Peripheral Enable */
  I2C_Cmd(I2C1, ENABLE);
  /* Apply I2C configuration after enabling it */
  I2C_Init(I2C1, &I2C_InitStructure);
}

/*******************************************************************************
* Function Name  : I2C_EE_Init
* Description    : Initializes peripherals used by the I2C EEPROM driver.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void I2C_EE_Init()
{
  /* GPIO configuration */
  //GPIO_Configuration();
  GPIO_InitTypeDef  GPIO_InitStructure;

  /* Configure I2C1 pins: SCL and 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_Configuration();

  /* depending on the EEPROM Address selected in the i2c_ee.h file */
#ifdef EEPROM_Block0_ADDRESS
  /* Select the EEPROM Block0 to write on */
  EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif
#ifdef EEPROM_Block1_ADDRESS
  /* Select the EEPROM Block1 to write on */
  EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif
#ifdef EEPROM_Block2_ADDRESS
  /* Select the EEPROM Block2 to write on */
  EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif
#ifdef EEPROM_Block3_ADDRESS
  /* Select the EEPROM Block3 to write on */
  EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}

/*******************************************************************************
* Function Name  : I2C_EE_BufferWrite
* Description    : Writes buffer of data to the I2C EEPROM.
* Input          : - pBuffer : pointer to the buffer  containing the data to be
*                    written to the EEPROM.
*                  - WriteAddr : EEPROM's internal address to write to.
*                  - NumByteToWrite : number of bytes to write to the EEPROM.
* Output         : None
* Return         : None
*******************************************************************************/
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)
    {
      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_EE_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    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();
      }
    }
  }
  /* 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)
      {  
        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();
      }
    }
  }  
}

/*******************************************************************************
* Function Name  : I2C_EE_ByteWrite
* Description    : Writes one byte to the I2C EEPROM.
* Input          : - pBuffer : pointer to the buffer  containing the data to be
*                    written to the EEPROM.
*                  - WriteAddr : EEPROM's internal address to write to.
* Output         : None
* Return         : None
*******************************************************************************/
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);
}

/*******************************************************************************
* Function Name  : I2C_EE_PageWrite
* Description    : Writes more than one byte to the EEPROM with a single WRITE
*                  cycle. The number of byte can't exceed the EEPROM page size.
* Input          : - pBuffer : pointer to the buffer containing the data to be
*                    written to the EEPROM.
*                  - WriteAddr : EEPROM's internal address to write to.
*                  - NumByteToWrite : number of bytes to write to the EEPROM.
* Output         : None
* Return         : None
*******************************************************************************/
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
  /* 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);
}

/*******************************************************************************
* Function Name  : I2C_EE_BufferRead
* Description    : Reads a block of data from the EEPROM.
* Input          : - pBuffer : pointer to the buffer that receives the data read
*                    from the EEPROM.
*                  - ReadAddr : EEPROM's internal address to read from.
*                  - NumByteToRead : number of bytes to read from the EEPROM.
* Output         : None
* Return         : None
*******************************************************************************/
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
  /* 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));
  
  /* 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);
}

/*******************************************************************************
* Function Name  : I2C_EE_WaitEepromStandbyState
* Description    : Wait for EEPROM Standby state//置EEPROM为待命状态
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
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);
}

/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

出0入0汤圆

发表于 2009-7-24 18:39:09 | 显示全部楼层
应用
I2C_EE_Init();
I2C_EE_BufferRead((u8 *)&ee_buf,0,16);
I2C_EE_BufferWrite((u8 *)&ee_buf,0,16);

出1070入962汤圆

 楼主| 发表于 2009-7-24 18:47:41 | 显示全部楼层
不知道和公布的ST的那个程序有多少差别,抽空再改到铁电上试试去。

出10入0汤圆

发表于 2009-7-25 12:18:04 | 显示全部楼层
我也搞了几天。差点想用模拟的。

出0入0汤圆

发表于 2009-7-28 16:39:45 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-1 14:30:24 | 显示全部楼层
被STM32的I2C调戏了两天,终于花半小时用模拟I2C将其消灭
--------------------
哈哈.

再看看吧.是可以用硬件解决的.

出1070入962汤圆

 楼主| 发表于 2010-3-1 14:44:36 | 显示全部楼层
确实可以使用硬件解决的,但是,如果使用公布的那个例程,没啥问题,如果整合到一起跑,问题就来了。初略看过ST的一个文档,说I2C的中断级别要最高,我就不明白了,一个低速的总线,为啥要求中断优先级别比SPI,CAN还高?

目前软件I2C工作良好,stm32的速度够快,没觉得不爽的,前几天被SPI的NSS引脚也郁闷了一把,差点也软件了SPI,呵呵,后来仅仅软件了NSS。

出0入0汤圆

发表于 2010-3-2 09:52:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-2 15:14:23 | 显示全部楼层
mark

出10入0汤圆

发表于 2010-3-4 08:24:52 | 显示全部楼层
回复【19楼】Appcat 苹果猫
----------------------------------------------------------------
一样会有问题。没有时就没有,有的时候就会一直有。有没有事主要出现在开机时刻。

我就偿过了。起初都认为好了。后来不知道什么时候又出现了。但如果好的时候,我就可以一直读写了。

出0入0汤圆

发表于 2010-3-4 08:38:04 | 显示全部楼层
mark一下是

出0入0汤圆

发表于 2010-3-4 08:46:45 | 显示全部楼层
回复【楼主位】Appcat 苹果猫
-----------------------------------------------------------------------

mark

出0入0汤圆

发表于 2010-5-16 15:19:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-17 10:25:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-18 15:00:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-27 13:45:58 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-27 15:21:37 | 显示全部楼层
学习一下了,正在调试IIC

出0入0汤圆

发表于 2010-6-11 19:22:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-11 20:46:11 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-11 22:18:33 | 显示全部楼层
这个问题也烦了我两天,开始用了ST的例程调好了,跑了有半个多月一直很正常。结果前两天调程序时,修改了一些别的地方,IIC却硬是跑不起来了,一上电就停在了查询总线忙那,换成ST的IIC EEPROM的例子也不行。使用N种方法后无果,连芯片都换了,最后只好模拟IIC搞定。

出0入0汤圆

发表于 2010-6-12 18:30:01 | 显示全部楼层
请教一下

  //注意:因为这里要等待EEPROM写完,可以采用查询或延时方式(10ms)
  //Systick_Delay_1ms(10);

查询方式是怎么实现的,对延迟等到EEPROM实际操作完成理解,可是查询方式呢,具体查询什么可以确定EEPROM写完呢? 谢谢了

出0入0汤圆

发表于 2010-8-26 15:09:44 | 显示全部楼层
延时是照抄“Appcat 苹果猫”的。
STM103ZET6访问FM24CL64的代码。

#include "stm32f10x.h"
#include "Includes.h"
#include "Constants.h"
#include "Functions.h"
#include "Globals.h"

#define IIC_SCL_OUT   GPIOB->CRL |= 0x03000000
#define IIC_SDA_IN    GPIOB->CRL &= 0xCFFFFFFF
#define IIC_SDA_OUT   GPIOB->CRL |= 0x30000000
#define IIC_SDA_BIT   GPIOB->IDR & GPIO_Pin_7

#define IIC_SCL0      GPIOB->BRR  = GPIO_Pin_6
#define IIC_SCL1      GPIOB->BSRR = GPIO_Pin_6
#define IIC_SDA0      GPIOB->BRR  = GPIO_Pin_7
#define IIC_SDA1      GPIOB->BSRR = GPIO_Pin_7
#define ERRORCOUNT    3

/*************************************************************
@Fn:
@Br:
@Pa:
@Rt:
*************************************************************/
void ConfigSoftI2C1( void ){
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit( &GPIO_InitStructure );             /* 初始化变量 */
  
  /*-- GPIO Configuration */
  /* Configure PB.6/PB.7 as Open drain */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;    /* I2C引脚 */
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/************************************************
函 数 名: IICStart()
功    能:启动IIC总线
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:无
************************************************/
void IICStart( void ){
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SCL0;
  IIC_SDA1;
  IIC_SCL1;
  
  DelayI2C();
  
  IIC_SDA0;
  
  DelayI2C();
  
  IIC_SCL0;
  IIC_SDA1;
}
/************************************************
函 数 名: IICStop()
功    能:停止IIC总线
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:无
************************************************/
void IICStop( void ){
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SCL0;
  IIC_SDA0;
  IIC_SCL1;
  
  DelayI2C();
  
  IIC_SDA1;
  
  DelayI2C();
  
  IIC_SCL0;
}
/************************************************
函 数 名: IICRecAck()
功    能:检查应答位
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:0: 有应答; 1: 无应答
************************************************/
u8 IICRecAck( void ){
  u8 ack;
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SCL0;
  IIC_SDA0;
  IIC_SCL1;
  IIC_SDA_IN;
  if( IIC_SDA_BIT )ack = 1;
  else
    ack = 0;
  IIC_SCL0;
  return( ack );
}
/************************************************
函 数 名: IICAck()
功    能:对IIC总线产生应答
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:无
************************************************/
void IICAck( void ){
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SDA0;
  IIC_SCL1;
  
  DelayI2C();
  
  IIC_SCL0;
  
  DelayI2C();
  
  IIC_SDA1;
}
/************************************************
函 数 名: IICNoAck()
功    能:不对IIC总线产生应答
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:无
************************************************/
void IICNoAck( void ){
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SDA1;
  IIC_SCL1;
  
  DelayI2C();
  
  IIC_SCL0;
}
/************************************************
函 数 名: IICSendByte()
功    能:往EEPROM写入1Byte数据
说    明:
调    用:
全局变量:
入口参数:WriteData: 写入的数据
出口参数:无
返 回 值:无
************************************************/
void IICSendByte( u8 WriteData ){
  u8 i;
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  for( i = 8;i > 0;i-- )
    {
    IIC_SCL0;
    if( WriteData & 0x80 )IIC_SDA1;
    else
      IIC_SDA0;
    IIC_SCL1;
    WriteData <<= 1;
    }
  IIC_SCL0;
}
/************************************************
函 数 名: IICReceiveByte()
功    能:从EEPROM读取1Byte数据
说    明:
调    用:
全局变量:
入口参数:无
出口参数:无
返 回 值:ReadData
************************************************/
u8 IICReceiveByte( void ){
  u8 i, ReadData;
  IIC_SCL_OUT;
  IIC_SDA_OUT;
  IIC_SCL0;
  IIC_SDA1;
  IIC_SDA_IN;
  for( i = 0;i < 8; i++ )
    {
    IIC_SCL1;
    ReadData <<= 1;
    if( IIC_SDA_BIT )ReadData |= 0x01;
    IIC_SCL0;
    }
  return( ReadData );
}
/************************************************
函 数 名: WriteReadIIC()
功    能:对EEPROM读/写数据
说    明:先写地址,后读/写数据
调    用:IICStart(),IICSendByte(),IICRecAck(),
          IICNoAck(),IICAck(),IICReceiveByte(),
          IICStop(),delay_nus()
全局变量:
入口参数:DataBuff: 读写数据输入/输出缓冲区的首址,
          ByteQuantity: 读写数据的字节数量,
          Address: EEPROM片内地址, ControlByte: EEPROM的控制字节
          ControlByte具体形式: (1)(0)(1)(0)(A2)(A1)(A0)(R/W),
                其中R/W = 1,表示读操作;R/W = 0为写操作;
                A2,A1,A0为EEPROM的页选或片选地址
出口参数:无
返 回 值:0: 读/写操作成功; 1: 读/写操作失败
************************************************/
u8 WriteReadIIC( u8 *DataBuff, u8 ByteQuantity,
                u16 Address, u8 ControlByte ){
  u8 i = ERRORCOUNT, Errorflag = 1,j;
  while( i-- )
    {
    IICStart();
    IICSendByte( ControlByte & 0xFE );
    if( IICRecAck() )continue;
    IICSendByte(( u8 )( Address >> 8 ));
    if( IICRecAck() )continue;
    IICSendByte(( u8 )Address );
    if( IICRecAck() )continue;
    if(!( ControlByte & 0x01 ))
      {
      j = ByteQuantity;
      Errorflag = 0;        //Clr errorflag
      while( j-- )
        {
        IICSendByte( *DataBuff++ );
        if( IICRecAck() == 0 )continue;
        Errorflag = 1;
        break;
        }
      if( Errorflag == 1 )continue;
      break;
      }
    else
      {
      IICStart();
      IICSendByte( ControlByte );
      if( IICRecAck() )continue;
      while( --ByteQuantity )
        {
        *DataBuff++ = IICReceiveByte();
        IICAck();
        }
      *DataBuff = IICReceiveByte(); //read last byte data
      IICNoAck();
      Errorflag = 0;
      break;
      }
    }
  IICStop();
  IIC_SCL1;
  return( Errorflag );
}
/*************************************************************
@Fn:
@Br:
@Pa:
@Rt:
*************************************************************/
void DelayI2C( void ){
  u8 i = 15;
  while( i )  
    {  
    i--;  
    }  
}

出0入0汤圆

发表于 2010-8-27 13:55:38 | 显示全部楼层
回复【4楼】Appcat 苹果猫
咱这是具体问题具体对待,stm32的硬件i2c我不敢说它次,是我水平太次了,光那几个标志位都搞晕了。所以用了模拟的i2c。我就郁闷,挺简单一个东西,给stm32搞的这么高深,不服不行啊。
-----------------------------------------------------------------------

我也是搞不定,可能是太高级了吧,用软件一下就搞定

出0入0汤圆

发表于 2010-8-27 14:38:16 | 显示全部楼层
看来以后要搞的话也要用模拟的了。太难受了

出0入0汤圆

发表于 2010-8-27 16:47:25 | 显示全部楼层
STM32的模拟I2C,硬件I2C,FM24CL64,标记一下!

出0入0汤圆

发表于 2010-9-14 15:10:33 | 显示全部楼层
请问LZ,程序中为什么SDA只有设为输出?不能设为输入?

出0入0汤圆

发表于 2010-9-15 10:45:00 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-9-15 11:49:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-15 13:59:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-15 17:20:27 | 显示全部楼层
好东西,顶一下。

我现在用的是硬件的I2C,起初用的还可以(但是总有些不安,因为当初调试的时候,没改什么,莫名其妙就好了),空闲时多方测试发现,通信过程中不被中断或者干扰的话,通信还是正常的,一旦有任何中断或者干扰什么的,I2C铁定会挂掉,就连复位都无法恢复,只能通过断电,再上电才能恢复,硬件还是又明显的缺陷呀。

不过,现在能用就用者吧,到实在不行,再用模拟的吧。

出0入0汤圆

发表于 2010-9-15 17:40:23 | 显示全部楼层
如果stm32是个人的话,一定会自杀

出0入0汤圆

发表于 2010-9-19 13:58:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-19 21:38:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-26 17:05:11 | 显示全部楼层
14楼公布的源码,是否是中断方式?中断处理函数呢?

出0入0汤圆

发表于 2010-9-26 17:58:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 12:32:42 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 13:19:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 13:59:39 | 显示全部楼层
我也碰到过这个问题,后来发现是没有接外部上拉电阻的关系,接上就可以了

出0入0汤圆

发表于 2010-9-27 17:40:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 17:42:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-27 18:04:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-8 21:53:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-9 14:59:00 | 显示全部楼层
楼主猫咪 不错。。。

出0入0汤圆

发表于 2010-10-9 15:51:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-10 14:39:38 | 显示全部楼层
牛!

出0入0汤圆

发表于 2010-10-26 19:14:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-22 14:55:06 | 显示全部楼层
STM32 I2C 模拟的不好啊?

出0入0汤圆

发表于 2010-11-22 15:25:31 | 显示全部楼层
听说I2C有BUG的

出0入0汤圆

发表于 2010-11-22 19:37:33 | 显示全部楼层
学习了,呵呵

出0入0汤圆

发表于 2010-11-30 15:35:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-1 16:23:51 | 显示全部楼层
好像mcu的硬件iic都比较难调啊~不过还是硬件的好。

出0入0汤圆

发表于 2010-12-10 14:34:17 | 显示全部楼层
苹果的代码有点奇怪,为什么不用设置为输入呢?

都是开漏输出的方式。

出0入0汤圆

发表于 2010-12-10 16:21:03 | 显示全部楼层
本人的产品中spi也是硬件的,但nss脚用软件的。

出0入0汤圆

发表于 2010-12-10 16:28:47 | 显示全部楼层
提前记号

出0入0汤圆

发表于 2010-12-11 07:07:11 | 显示全部楼层
受益非浅

出0入137汤圆

发表于 2010-12-11 08:01:00 | 显示全部楼层
回复【66楼】nuc120
苹果的代码有点奇怪,为什么不用设置为输入呢?
都是开漏输出的方式。
-----------------------------------------------------------------------

开漏输出才可以双向啊,可以读啊

出0入0汤圆

发表于 2010-12-30 15:12:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-30 15:57:34 | 显示全部楼层
mark一下

出0入0汤圆

发表于 2010-12-31 10:26:11 | 显示全部楼层
记下号

出0入0汤圆

发表于 2011-1-26 11:27:05 | 显示全部楼层
记下号

出0入0汤圆

发表于 2011-1-26 12:52:00 | 显示全部楼层
用STM32的硬件IIC,紧凑连续做两个完整的IIC操作,你就等着崩溃吧.哈哈.....

出0入0汤圆

发表于 2011-1-26 15:32:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-26 22:02:03 | 显示全部楼层
估计也会被i2c搞死,先标记

出0入0汤圆

发表于 2011-1-28 14:44:17 | 显示全部楼层
强奸IIC

出0入0汤圆

发表于 2011-1-29 17:13:21 | 显示全部楼层
硬件I2C问题,,mark一下。下次做I2C的时候再过来看看。呵呵。谢谢楼主。

出0入0汤圆

发表于 2011-1-31 17:39:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-1 08:31:39 | 显示全部楼层
记号

出0入0汤圆

发表于 2011-2-7 14:08:34 | 显示全部楼层
Mark一下

出0入0汤圆

发表于 2011-2-7 14:50:48 | 显示全部楼层
stm32的硬件iic可以用的,我一直都在用,暂时遇到的问题都能解决;
用软件模拟一般也可以,很多情况下效率的区别与硬件iic区别不大,毕竟都在等待。在使用事件驱动(如中断方式或调度方式)时效率才能较好地体现。
在用硬件iic的时候,要明白它是状态机模式,平时使用的情况如接口一片24eeprom的使用,只是它的一个子集;它同时具有主收、主发、从收、从发的两种状态四个方向数据传递模式,还有总线仲裁;它可以产生设计者“不希望遇到”或者说“没料到”的情况返回,如果处理不是全集而只是子集,很容易挂起。

出0入0汤圆

发表于 2011-2-7 20:53:44 | 显示全部楼层
个人觉得,这不是工程师解决问题应该用的方式!

出0入0汤圆

发表于 2011-2-7 22:05:20 | 显示全部楼层
今天看了ST的错误手册,才发现I2C与FSMC有冲突。
同时, I2C还有其它的硬件错误。

出0入0汤圆

发表于 2011-2-15 09:59:57 | 显示全部楼层
硬件I2C到底可以用不?

出0入0汤圆

发表于 2011-2-17 11:55:14 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-18 19:10:01 | 显示全部楼层

出0入0汤圆

发表于 2011-2-27 23:25:09 | 显示全部楼层
学习了

出0入0汤圆

发表于 2011-2-28 03:11:44 | 显示全部楼层
没有效率的方法 :)

出0入0汤圆

发表于 2011-3-27 16:36:27 | 显示全部楼层
用模拟的需要接上拉电阻吗?我用它写的ltc2635驱动一直未成功,郁闷好几天了ltc2635是IIC的

出0入0汤圆

发表于 2011-5-20 11:12:18 | 显示全部楼层
我晕,这人I2C不会出问题吧。我画好的板在做了,I2C还接着几个器件呢。

出0入0汤圆

发表于 2011-5-20 20:49:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-26 11:35:48 | 显示全部楼层
我承认STM32我还很不熟,虽然已经有好几个作为产品的东西在用,也没见过出啥问题,都是用到哪看到哪,学到哪啊。
看到前面各位高人的讨论,我也不敢用硬件了,决定用软件模拟解决之,毕竟,软件模拟I2C我已经有成熟的东西了。

出0入0汤圆

发表于 2011-5-31 19:35:47 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-5-31 20:57:39 | 显示全部楼层
好东西

出0入0汤圆

发表于 2011-6-1 13:55:30 | 显示全部楼层
学习了

出0入0汤圆

发表于 2011-6-1 21:29:28 | 显示全部楼层
IIC,stm32早晚要用到。


mark,mark

出0入0汤圆

发表于 2011-6-2 18:54:12 | 显示全部楼层
受教了

出0入0汤圆

发表于 2011-6-4 11:35:42 | 显示全部楼层
兄弟,很很感谢你啊, 我用这个程序访问i2c接口的freescale的mma7660三维加速度传感器成功了。 如果大家谁有需要可以发邮件到62718@163.com给我要。 其实稍微看看文档就可以搞定。

出0入0汤圆

发表于 2011-6-8 13:11:08 | 显示全部楼层
楼主为什么去掉了 SDA 输入输出的转换?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 07:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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