I2C扫描从设备方法

I2C扫描从设备方法

说明

这几天在研究0.96寸OLED屏;但是一直都点不亮,同事建议用I2C扫描从设备地址,如是写了这个函数;虽然最终确定不是软件问题,但是解题思路很好,因此记录下来;MCU是STM32F103VE.

思路

I2C发送从设备地址,检测哪些地址有应答,则把这些地址答应出来,即可知道此I2C挂载了多少从设备;

代码

I2C_SCAN.H

#ifndef __I2C_SCAN_H
#define __I2C_SCAN_H
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"

/**************************I2C参数定义,I2C1或I2C2********************************/
#define             EEPROM_I2Cx                                I2C1
#define             EEPROM_I2C_APBxClock_FUN                   RCC_APB1PeriphClockCmd
#define             EEPROM_I2C_CLK                             RCC_APB1Periph_I2C1
#define             EEPROM_I2C_GPIO_APBxClock_FUN              RCC_APB2PeriphClockCmd
#define             EEPROM_I2C_GPIO_CLK                        RCC_APB2Periph_GPIOB     
#define             EEPROM_I2C_SCL_PORT                        GPIOB   
#define             EEPROM_I2C_SCL_PIN                         GPIO_Pin_6
#define             EEPROM_I2C_SDA_PORT                        GPIOB 
#define             EEPROM_I2C_SDA_PIN                         GPIO_Pin_7


/*等待超时时间*/
#define I2CT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT         ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))

/*信息输出*/
#define EEPROM_DEBUG_ON         0

#define EEPROM_INFO(fmt,arg...)           printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
#define EEPROM_ERROR(fmt,arg...)          printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
#define EEPROM_DEBUG(fmt,arg...)          do{\
                                          if(EEPROM_DEBUG_ON)\
                                          printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
                                          }while(0)



void I2C_SCAN_Init(void);

//主函数调用下面函数,如果检测地址0~200中间是否有外设的地址,把200写入进去即可
uint32_t I2C_SCAN(uint32_t TEST_ADDRESS);
#endif /*__BSP_I2C_24C02_H*/

I2C_SCAN.C

#include "i2c_scan.h"


static __IO uint32_t  I2CTimeout = I2CT_LONG_TIMEOUT;   


static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);

static  void I2C_GPIO_Config(void)
{
    //PB6=SCL;PB7=SDA   I2C1
    GPIO_InitTypeDef    GPIO_InitStructure;

    //使能GPIOB时钟;使能I2C时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    //复用开漏输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    //复用开漏输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

static  void I2C_Mode_Config(void)
{
    I2C_InitTypeDef I2C_InitStructure;

    //设置速度为400Khz
    I2C_InitStructure.I2C_ClockSpeed = 100000;
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    //占空比1:2
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    //指定自身地址
    I2C_InitStructure.I2C_OwnAddress1 = 0x10;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    //设备地址七位
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init(I2C1,&I2C_InitStructure);
}

void I2C_SCAN_Init(void)
{
    I2C_GPIO_Config();
    I2C_Mode_Config();
}


uint32_t I2C_SCAN(uint32_t TEST_ADDRESS)
{
    while(TEST_ADDRESS>0)
    {
        /* Send STRAT condition */
      I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

      I2CTimeout = I2CT_FLAG_TIMEOUT;  
      /* Test on EV5 and clear it */
      while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))  
      {
        if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
      } 

      I2CTimeout = I2CT_FLAG_TIMEOUT;
      /* Send EEPROM address for write */
      I2C_Send7bitAddress(EEPROM_I2Cx, TEST_ADDRESS, I2C_Direction_Transmitter);

      /* Test on EV6 and clear it */
      while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
      {
        if((--I2CTimeout) == 0) break;
      }
     if(I2CTimeout>0) printf("%#x\n",TEST_ADDRESS);  
      /* Send STOP condition */
     I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
     TEST_ADDRESS--;

    }    
}


/**
  * @brief  Basic management of the timeout situation.
  * @param  errorCode:错误代码,可以用来定位是哪个环节出错.
  * @retval 返回0,表示IIC读取失败.
  */
static  uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* Block communication and all processes */
  EEPROM_ERROR("I2C 等待超时!errorCode = %d",errorCode);

  return 0;
}

最终打印效果&不解的地方

本次挂载了两个从设备,一个是24C02地址为0XA0;一个是OLED,地址为0X78;但最终打印出来的数据如下:
0xaf
0xae
0xad
0xac
0xab
0xaa
0xa9
0xa8
0xa7
0xa6
0xa5
0xa4
0xa3
0xa2
0xa1
0xa0
0x79
0x78

不知道为什么会打印这么多;知道的讲一下哦!

你可能感兴趣的:(STM32)