【问题标题】:Read values from i2c sensors with the same address从具有相同地址的 i2c 传感器读取值
【发布时间】:2017-02-09 01:19:45
【问题描述】:

我有 4 个 SingleTact 电容传感器,每个传感器的 i2c 地址为 0x04。我想找到传感器的平均值,以便制作操纵杆。但是我不确定如何为每个传感器分配它自己的地址,因为它们都具有相同的地址,因为它们是同一个传感器。我有一个初始代码,但这仅适用于一个传感器,因为它只有一个 i2c 地址字节。我使用在线教程将所有 SDA 和 SCL 线连接在一起,并且包括上拉电阻。

#include <Wire.h>
#define initializetime 4
byte serialToPCBuffer[77];
byte serialToPCBufferIndex = 0;

int data[4];
int databuffer[4][initializetime] = {0,0,0,0,0,0,0,0,0,0,0,0};
int base[4] = {0,0,0,0};
int ArduinoToPCBuffer[4] = {1000,2000,3000,4000};
byte outgoingI2CBuffer[32];
unsigned long timeStamp_;

void setup() {
  int i;
  Wire.begin();
  //TWBR = 12;
  Serial.begin(57600);
  Serial.flush();
  initializeSensors();

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("PPS UK: SingleTact sensor value in PSI. \n(resembles PC executable display)");
  Serial.println("Refer manual for any other calculation.");
  Serial.println("----------------------------------------");  
}    

void loop(){
  byte i2cAddress = 0x04; // Slave address (SingleTact), default 0x04
  int data = readDataFromSensor(i2cAddress);
  Serial.print("I2C Sensor Data:");
  Serial.print(data);    
  Serial.print("\n");
  delay(100); // Change this if you are getting values too quickly 
}

int readDataFromSensor(int address)
{
  byte i = 0;
  byte i2cPacketLength = 6;
  byte outgoingI2CBuffer[3];
  byte incomingI2CBuffer[6];

  outgoingI2CBuffer[0] = 0x01;
  outgoingI2CBuffer[1] = 128;
  outgoingI2CBuffer[2] = i2cPacketLength;

  Wire.beginTransmission(address);
  Wire.write(outgoingI2CBuffer,3);
  byte error = Wire.endTransmission();
  if (error != 0) return -1;
  Wire.requestFrom(address,i2cPacketLength);

  int incomeCount =0;
  while(incomeCount < i2cPacketLength)
  {
    if(Wire.available())
    {
    incomingI2CBuffer[incomeCount] = Wire.read();
    incomeCount++;
    }
    else
    {
    delay(1);
    }
  }
  if(serialToPCBuffer[4] == 0x00 && serialToPCBuffer[5] == 0xFE)
  {
    serialToPCBuffer[5] = 0xFF;
  }

  int datafromi2c = serialToPCBuffer[4]*256+serialToPCBuffer[5]-base[address-5];

  if(datafromi2c<21)
    datafromi2c = 0;

  return datafromi2c;
}

void initializeSensors()
{
  for(int k = 0;k<4;k++)
  {
    databuffer[k][0] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][1] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][2] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][3] = readDataFromSensor(k+5);
    delay(10);
    base[k] = (databuffer[k][0] + databuffer[k][1] + databuffer[k][2] +     databuffer[k][3])/3;
  }
}

感谢您的建议。

【问题讨论】:

标签: arduino i2c


【解决方案1】:

您应该阅读此设备的手册,可在here 获取。它在界面描述中说,

多个传感器接口可以连接到单个 I2C 总线。这 各个传感器接口的总线地址可以通过以下方式配置 通过 I2C 接口将所需的地址值(4 至 127)写入 使用 I2C 写操作注册地址 0。个人变化 PC 和 Arduino 示例支持传感器 I2C 地址。

所以你只需要

  1. 插入第一个传感器
  2. 向此设备的寄存器 0 写入地址(例如 0x41)
  3. 拔下传感器
  4. 对使用不同地址的所有传感器重复 1-2-3

然后每个传感器都会回复你设置的地址。

请注意

因为接口板总是响应地址 0x04 那么这个 地址必须被认为是为 SingleTact 保留的。哪里多 SingleTact 接口将连接到相同的 I2C 总线,然后 地址 0x04 必须被视为无效

因此,即使在这种情况下,RTFM 建议也是最重要的...

【讨论】:

    【解决方案2】:

    您还可以使用 I2C 多路复用器。它们有自己的 I2C 地址,可以枚举自己总线(广播域)上的四个传感器,以便在它们之间进行切换。您的编程将需要依次明确选择每个传感器并跟踪它正在读取哪个传感器。切换后,I2C 流量仅通过所选设备。当您运行额外的接线时,这最适用于星型拓扑中的传感器集群。

    我要更进一步,说您甚至可以使用继电器来切换这些输入和输出,或 OR/NAND 门。

    【讨论】:

      【解决方案3】:

      您需要使用卡尔曼滤波器

          #include "Wire.h"                      // i2c library
          #include "BMP085.h"                   // bmp085 library, download from url link (1)
          #include "Tone.h"                      // tone library, download from url link (3)
          #include "stdlib.h"                    // we need that to use dtostrf() and convert float to string
          #include "stdarg.h"
      
          #define UART_SPEED  9600
          short SPEAKER_PIN1 = 11;               // Speaker output -
          short SPEAKER_PIN2 = 12;               // Speaker output +
          short LED_PIN = 13;
      
          Tone speaker1, speaker2;
          BMP085   bmp085 = BMP085();            // BMP085 sensor
      
          const float SEA_LEVEL_PRESSURE = 101325;    // Pressure at sea level (Pa)
          const float KF_VAR_MEASUREMENT = 0.1;       // Variance of pressure measurement noise.
          const float KF_VAR_ACCEL = 0.75;             // Variance of pressure acceleration noise input.
      
          float CLIMB_TONE2_MULT;
          float SINK_TONE2_MULT;
      
          float   kf_x_abs,
                  kf_x_vel,
                  kf_p_abs_abs,
                  kf_p_abs_vel,
                  kf_p_vel_vel,
                  kf_var_accel;
      
          #define VARIOS_LEN  5
          int varios[VARIOS_LEN];
          int varios_pos = 0, varios_sum = 0;
      
          void p(char *fmt, ... ){
              char tmp[128]; // resulting string limited to 128 chars
              va_list args;
              va_start (args, fmt );
              vsnprintf(tmp, 128, fmt, args);
              va_end (args);
              Serial.print(tmp);
          }
      
          void kf_reset(float abs_value, float vel_value) {
              kf_x_abs = abs_value;
              kf_x_vel = vel_value;
              kf_p_abs_abs = 1000000000;
              kf_p_abs_vel = 0;
              kf_p_vel_vel = KF_VAR_ACCEL;
              kf_var_accel = KF_VAR_ACCEL;
      
              varios_sum = 0;
              for (int i = 0; i < VARIOS_LEN; i++) varios[i] = 0;
              varios_pos = 0;
          }
      
          void setup() {
              Serial.begin(UART_SPEED);            // set up arduino serial port
              Wire.begin();                        // lets init i2c protocol
              speaker1.begin(SPEAKER_PIN1);        // piezo speaker output -
              speaker2.begin(SPEAKER_PIN2);        // piezo speaker output +
              digitalWrite(SPEAKER_PIN2, LOW);
      
              bmp085.init(MODE_ULTRA_HIGHRES, SEA_LEVEL_PRESSURE, false);
      
              kf_reset(SEA_LEVEL_PRESSURE, 0);
      
              CLIMB_TONE2_MULT = pow(2, 9/12);
              SINK_TONE2_MULT = pow(2, 1/12);
      
              welcome();      //everything is ready, play "welcome" sound
          }
      
          void welcome() {
              speaker1.play(300, 50);     // (note, duration)
              delay(100);
              speaker2.play(300, 50);     // (note, duration)
              delay(100);
              Serial.println("Vario is ready");
          }
      
          float pressure2altitude(float pressure) {
              return (float)44330 * (1 - pow(((float)(pressure)/SEA_LEVEL_PRESSURE), 0.190295));
          }
      
          float last_time = 0;
          void update_pressure() {
              long pressure;
              bmp085.calcTruePressure(&pressure);
      
              float time = millis();
              float dt = (time - last_time) / 1000;
              last_time = time;
      
              /* Kalman Filter code */
              kf_x_abs += kf_x_vel * dt;
      
              kf_p_abs_abs += (float)2 * dt * kf_p_abs_vel  +  dt * dt * kf_p_vel_vel  +  kf_var_accel * dt * dt * dt * dt / (float)4;
              kf_p_abs_vel +=                                       dt * kf_p_vel_vel  +  kf_var_accel * dt * dt * dt / (float)2;
              kf_p_vel_vel +=                                                          +  kf_var_accel * dt * dt;
      
              // Update state covariance. The last term mixes in acceleration noise.
              float y = pressure - kf_x_abs;                              // Innovation.
              float s_inv = 1.0 / (kf_p_abs_abs + KF_VAR_MEASUREMENT);    // Innovation precision.
              float k_abs = kf_p_abs_abs * s_inv;                         // Kalman gain
              float k_vel = kf_p_abs_vel * s_inv;
      
              // Update state estimate.
              kf_x_abs += k_abs * y;
              kf_x_vel += k_vel * y;
      
              // Update state covariance.
              kf_p_vel_vel -= kf_p_abs_vel * k_vel;
              kf_p_abs_vel -= kf_p_abs_vel * k_abs;
              kf_p_abs_abs -= kf_p_abs_abs * k_abs;
          }
      
          int avg_vario() {
              float altitude = pressure2altitude(kf_x_abs);
              int vario = (int)((altitude - pressure2altitude(kf_x_abs - kf_x_vel)) * 100);
      
              varios_sum += vario;
              varios_sum -= varios[varios_pos];
              varios[varios_pos] = vario;
      
              if (++varios_pos == VARIOS_LEN) varios_pos = 0;
              return varios_sum / VARIOS_LEN;
          }
      
      
          int CLIMB_RATE_START = 25,
              SINK_RATE_START  = -80;
      
          int loop_id = 0;
          unsigned long next_signal_time = 0;
          void loop() {
              update_pressure();
              int vario = avg_vario();
      
              unsigned long time = millis();
              if (time >= next_signal_time) {
                  if (vario > CLIMB_RATE_START) {
                      long beep_period = 350 - vario / 2;
                      if (beep_period < 20) beep_period = 20;
      
                      int silence_period = beep_period / 16;
                      int tone = 1300 + vario;
                      if (tone > 2300) tone = 2300;
      
                      next_signal_time = time + beep_period + silence_period;
                      speaker1.play(tone, beep_period);
      
                      Serial.print("CLIMB  beep:");
                      Serial.print(beep_period);
                      Serial.print("    silence:");
                      Serial.print(silence_period);
                      Serial.print("    vario: ");
                      Serial.println(vario);
                  } else if (vario < SINK_RATE_START) {
          //            int beep_period = 350 * 50 / (-vario);
          //            int silence_period = beep_period / 5;
                      int beep_period = 350 + vario / 2;
                      if (beep_period < 20) beep_period = 20;
                      int silence_period = beep_period / 16;
                      int tone = 1000 + vario;
                      if (tone < 300) tone = 300;
      
                      next_signal_time = time + beep_period + silence_period;
                      speaker1.play(tone, beep_period);     // (note, duration)
      
                      Serial.print("SINK  beep:");
                      Serial.print(beep_period);
                      Serial.print("    silence:");
                      Serial.print(silence_period);
                      Serial.print("    vario: ");
                      Serial.println(vario);
                  }
              }
      
              loop_id++;
              if ((loop_id % 10) == 0) {
                  Serial.print("vario: ");
                  Serial.println(vario);
              }
      
              if ((loop_id % 10) == 0) {
                  digitalWrite(LED_PIN, LOW);
              }
              if ((loop_id % 10) == 5) {
                  digitalWrite(LED_PIN, HIGH);
              }
          }
      

      【讨论】:

      • 对不起,但是这个答案如何回答 OP 问题?他问的是如何从具有相同地址的 4 个传感器读取数据,而不是如何从一个传感器读取数据..
      • 对我来说,这看起来像是一个“不合时宜”的答案,也许是为了另一个问题?
      猜你喜欢
      • 2013-09-29
      • 2022-06-10
      • 1970-01-01
      • 2018-06-26
      • 2018-12-06
      • 2018-04-08
      • 2020-06-29
      • 2019-06-26
      • 2019-02-27
      相关资源
      最近更新 更多