Fermion: I2C address shifter

简介

Fermion: I2C 地址转换器是一款直接硬件修改I2C传感器从机地址的模块。在控制器和传感器之间加入这个模块,主控就可以以新的地址来访问您的传感器。
通过板载拨钮的组合,至多可以将传感器修改为四个不同的新地址。通过焊接电阻,将另外获得至少20个新的从机地址

在I2C从机的研发过程中,开发者往往需要在一个I2C总线上集成多个相同的传感器。比如想要使用多个红外距离传感器组成阵列做避障小车,或者使用多个光照传感器测量多株植物收到不同光照的影响,亦或是想要使用多个加速度传感器捕捉人体动作来制作可穿戴设备。

以往,如果I2C传感器本身不支持地址修改的话,我们只能通过I2C级联器来实现这个效果。但是I2C级联器需要使用专门的驱动库,并且在代码中需要进行各个端口的切换,进一步拉长程序的时序,对于一个有高性能软件需求的开发者来说,想必这是不能忍受的。

而这款Fermion: I2C地址转换器提供了一个纯硬件的解决方案,无需使用任何软件库,也不会对I2C总线造成任何的时序影响,大大简化了开发流程,提升了软件性能。

虽然I2C地址转换器的功能强大,但是在使用前,您还需要注意以下两个问题:

  1. 这款转换器并不支持I2C时钟延长,所以它并不支持类似BNO055这类特殊的I2C传感器。
  2. I2C地址转换器仅负责硬件地址转换,您需要检查被转换的I2C传感器驱动库,以确保您知道如何在代码中将其改写为新的地址。

产品特性

  • 纯硬件解决方案,无需额外软件库
  • 板载拨钮,可以将I2C传感器变为四个不同的地址
  • 尺寸小巧,邮票孔设计,方便批量集成

规格参数

  • 供电电压:2.25V-5.5V
  • 工作温度:0~70℃
  • 工作电流:2mA @3.3V
  • 尺寸:19*19mm
  • 安装孔尺寸:φ2.0mm

引脚说明

Controller端引脚 功能描述
VCC DC2.25V-5.5V输入
GND 接地
SCL I2C时钟线(连接I2C主机)
SDA I2C数据线(连接I2C主机)
RDY I2C从机地址转换完成后输出高电平
I2C从机地址转换未完成输出低电平
Sensor端引脚 功能描述
VCC DC2.25-5.5V输出
GND 接地
SCL I2C时钟线(连接I2C从机)
SDA I2C数据线(连接I2C从机)
板载拨钮 功能描述
A5 控制I2C地址第五位是否翻转(1为翻转,0为不翻转)
A4 控制I2C地址第四位是否翻转(1为翻转,0为不翻转)

I2C地址计算

I2C地址具有7bit,我们定义A6为最高位,A0为最低位。
地址转换器默认将A6固定翻转(从0变为1,从1变为0)。您也可以通过板载拨钮控制A5或者A4位是否翻转。

假设传感器默认地址为0x69,换算为二进制则为0b1101001,将其接入地址转换器后:

原始地址(bin) A5拨钮 A4拨钮 新地址(bin) 新地址(hex)
1101001 0 0 0101001 0x29
1101001 1 0 0001001 0x09
1101001 0 1 0111001 0x39
1101001 1 1 0011001 0x19

同时,您需要注意以下几点,

  1. Fermion: I2C地址转换器在调整完板载拨钮后,需要重新上电才能设置新地址。
  2. 如果您使用Windows电脑,您可以使用电脑自带计算器的程序员功能来进行十六进制(HEX)到二进制(BIN)的转换
  3. 以上地址说明中:0b为二进制数的前缀,代表后面的数据为二进制;0x为十六进制数的前缀,代表后面数据为十六进制。

使用教程

软硬件准备

硬件准备

软件准备

接线图

示例代码

  • 确认Fermion: I2C地址转换器板载拨钮设置为A5=0,A4=0后,按照上述接线图进行连接。

  • 烧录以下示例程序

    /*
     @file accelGyroscope.ino
     @brief Obtain accelerometer data in both BMIs.
     @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
     @license The MIT License (MIT)
     @author [thdyyl](yuanlong.yu@dfrobot.com)
     @version V0.1
     @date 2024-08-05
    */
    #include "DFRobot_BMI160.h"
    DFRobot_BMI160 bmi160_1, bmi160_2;
    const int8_t i2c_addr_1 = 0x69, i2c_addr_2 = 0x29;
    
    void setup(){
      Serial.begin(115200);
      delay(100);
    
      //init the default bmi160
      if(bmi160_1.softReset() != BMI160_OK){
        Serial.println("bmi160_1 reset false");
        while(1);
      }
    
      if(bmi160_2.softReset() != BMI160_OK){
        Serial.println("bmi160_2 reset false");
        while(1);
      }
    
      //set and init the bmi160 i2c address
      if(bmi160_1.I2cInit(i2c_addr_1) != BMI160_OK){
        Serial.println("bmi160_1 init false");
        while(1);
      }
    
      if(bmi160_2.I2cInit(i2c_addr_2) != BMI160_OK){
        Serial.println("bmi160_2 init false");
        while(1);
      }
    }
    
    void showAccelGyroData(DFRobot_BMI160 bmi160){
      int i = 0;
      int rslt;
      int16_t accelGyro[6] = {0};
    
      //get both accel and gyro data from bmi160
      //parameter accelGyro is the pointer to store the data
      rslt = bmi160.getAccelGyroData(accelGyro);
    
      if(rslt == 0){
        for(i = 0; i < 6; ++i){
          if(i < 3){
            //the first three are gyro datas
            Serial.print(accelGyro[i] * 3.14 / 180);
            Serial.print("\t");
          }else{
            //the following three data accel datas
            Serial.print(accelGyro[i] / 16384.0);
            Serial.print("\t");
          }
        }
        Serial.println();
      }
      else{
        Serial.println("err");
      }
    }
    
    void loop(){
      Serial.print("bmi160_1:\t");
      showAccelGyroData(bmi160_1);
      Serial.print("bmi160_2:\t");
      showAccelGyroData(bmi160_2);
      Serial.println();
      delay(500);
    }
    

结果

串口监视器输出两个Gravity: BMI160 6轴惯性运动传感器的数据。


进阶教程

Fermion: I2C地址转换器可以通过板载拨钮切换,将传感器设置为四个不同的地址。

如果这还无法满足您的需求。我们在模块上预留出了一个0805电阻焊盘(R2),您可以参考本文档最下方的原理图,以及LTC4316的数据手册中第九页,自行焊接电阻来控制其余的I2C地址位是否翻转。

该焊盘直连XORL引脚,可控制I2C地址低四位是否翻转,我们将RLB(在我们原理图中为R1)固定为100kΩ,您可以自行计算RLT(在我们原理图中为R2)的阻值并焊接。
以下是我们确定一个R2的过程:

  1. 首先从数据手册可得,该模块是通过XORH或XORL引脚的电压,即VXORH或VORL相对于VCC的比值来确定I2C地址某一位是否翻转的。在数据手册的table 2和table 3中,bit下的1代表翻转,0代表不翻转。

  2. 假设我们现在给模块供电VCC为5V,我们想要将A3-A0设置为1 0 0 0的模式,即A3翻转,A2~A0不翻转。那就意味着VOXRL/VCC的比值应该为0.53125 ±0.015

  3. 为了帮助您快速计算电阻,我们的工程师团队总结了一个通用公式:

    [VCC/(R1+R2)]R1=VXORL

    其中VCC在我们假设中已经规定为5V,R1已知为100kΩ,目标VXORL应该为0.53125*5V=2.65625V
    将已知参数全部代入上述通用公式后,我们得出R2≈88.23529kΩ

  4. 鉴于算出的R2并不是个常见阻值,我们需要将其匹配到最接近的常见阻值,并且将这个常见阻值代回通用公式进行验证。
    在我们的样例中,最接近88.23529kΩ的常见阻值为86.6kΩ,代入计算后可得VXORL≈2.67953V,即VXORL/VCC≈0.53906。这个比值落在0.53125 ±0.015之间,所以我们可以使用86.6kΩ作为R2的阻值。

为了帮助您省去繁琐的计算,我们帮您列出了经过我们验证的几个R2阻值:

R2 A3 A2 A1 A0
91kΩ/86.6kΩ 1 0 0 0
68kΩ 1 0 0 1
51kΩ 1 0 1 0
39kΩ 1 0 1 1
27kΩ 1 1 0 0

如果您焊接电阻后不确定新的地址,我们推荐您使用Arduino或者ESP32,并且上传I2C scanner来确定您的新地址。

常见问题

Q1:在更改拨钮或者焊接电阻后,如何快速确认新的I2C从机地址

A1:您可以将传感器通过地址转换器连接到Arduino或者ESP32,上传下面的I2C Scanner代码。串口监视器会输出新的I2C地址。

/*
   @file i2cScanner.ino
   @brief The i2c_scanner see if a device did acknowledge to the address.
   @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
   @license The MIT License (MIT)
   @author [thdyyl](yuanlong.yu@dfrobot.com)
   @version V0.1
   @date 2024-08-05
*/
#include <Wire.h>
 
void setup(){
  Wire.begin();
  Serial.begin(115200);
  Serial.println();
  Serial.println("I2C Scanner");
}

void loop(){
  uint8_t error, address;
  int numDevices;
  Serial.println("Scanning...");
  numDevices = 0;
  for (address = 1; address < 127; address++ ){
    // The i2c_scanner uses the return value of the 
    // Write.endTransmisstion to see if a device 
    // did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0){
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println(" !");
      numDevices++;
    }else if (error == 4){
      Serial.print("Unknow error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (numDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(2000); // wait 2 seconds for next scan
}

更多资料