ADS1115 – A/D-Wandler mit Verstärker

Über den Beitrag

Mit diesem Beitrag möchte ich den 16-Bit, 4-Kanal A/D-Wandler ADS1115 und meine zugehörige Bibliothek vorstellen. Ich gehe zunächst auf die technischen Eigenschaften ein, dann möchte ich anhand von Beispielsketchen zeigen, wie ihr den ADS1115 mit der Bibliothek nutzen könnt. Zum Schluss gibt es – für die Interessierten – noch einen tieferen Einblick in den ADS1115 und seine Register.

Genau betrachtet behandele ich in diesem Beitrag ADS1115 Module. Wenn ihr im Löten von SMDs fit seid, könnt ihr natürlich auch den „nackten“ ADS1115 verwenden. Meine Bibliothek sollte damit genauso funktionieren.

Wozu brauche ich den ADS1115?

„Mein Arduino bzw. mein Microcontroller hat doch schon einen eingebauten A/D-Wandler. Wieso soll ich mich also mit diesem externen A/D-Wandler beschäftigen?“

Hier ein paar Gründe. Der ADS1115

  • hat eine Auflösung von 16 Bit gegenüber den 10 Bit des Arduino.
  • besitzt einen internen Verstärker, sodass er auch kleine Spannungen messen kann.
  • verfügt über eine Alarmfunktion, die ihr zur effizienten Überwachung von Spannungen einsetzen könnt, denn:
    • wenn euer Microcontroller nichts anderes zu tun hat, könntet ihr ihn schlafen schicken und den genügsamen ADS1115 arbeiten lassen.
    • ausgelagerte Prozesse, die ihr über Interrupts einbindet, können euren Code vereinfachen.

Technische Eigenschaften des ADS1115

Verschiedene ADS1115 Module
Verschiedene ADS1115 Module

Ein- und Ausgänge des ADS1115

Der ADS1115 beziehungsweise die Module besitzen die folgenden Ein- und Ausgänge:

  • VCC / GND: Anschluss von 2 bis 5.5 Volt.
  • SDA / SCL: Kommunikation über I2C. Ich habe keine extra Pull-Up Widerstände benötigt, aber sie sind nicht unbedingt in jedem Modul implementiert.
  • ADDR: Adresspin – vier I2C Adressen sind gemäß der unten abgebildeten Tabelle einstellbar.
  • ALRT: der Alert Pin wird bei Über- oder Unterschreitung festlegbarer Limits oder bei Abschluss einer A/D-Wandlung („Conversion Ready“) aktiv. In der Voreinstellung ist der Pin funktionslos.
  • A0 – A3: Anschlüsse für die vier Kanäle. Die angelegte Spannung darf VCC um nicht mehr als 0.3 Volt überschreiten.

Wie ihr seht ist, besitzt das oben abgebildete, mittlere Modul keinen Adress- und Alarmpin. Ihr seid damit auf die Adresse 0x48 festgelegt und könnt keine Alarme programmieren. Wenn ihr das nicht braucht, habt ihr damit aber eine sehr platzsparende Lösung.

Einstellung der I2C Adressen des ADS1115
Einstellung der I2C Adressen des ADS1115

Wenn ihr die Adressen überprüfen wollt, dann könnt ihr diesen I2C Scanner benutzen.

Eigenschaften

Hier ein kurzer Überblick über die wichtigsten Eigenschaften:

  • 16 Bit Auflösung – vorzeichenbehaftet (+/- 215 Bit).
  • 4 Kanäle, die gegeneinander oder gegen GND gemessen werden können.
  • Multiplexverfahren, es kann also nur ein Kanal pro Zeit gewandelt werden.
  • 6 Spannungsbereiche (bzw. Verstärkungsbereiche) von +/- 256 mV bis +/- 6.144 V.
  • Alarmfunktion (Limitüberschreitung oder „Conversion ready“).
  • Wandlungsrate (Conversion Rate) von 8 s-1 bis 860 s-1 einstellbar.
  • Kontinuierlicher Modus oder Einfachmessungen („Single-Shot“).
  • Interne Spannungsreferenz.
  • Geringer Stromverbrauch: 150 µA im kontinuierlichen Modus, 2.5 µA im Power-Down Modus. Der ADS1115 geht nach einer Single-Shot Messung automatisch in den Power-Down Modus.

Weitere Informationen findet ihr im Datenblatt des ADS1115.

ADS1115 Module gibt es für wenige Euro in den meisten Online-Shops, z.B. hier bei Amazon.

Typische Schaltung

Die unten abgebildete Schaltung habe ich für alle Beispielsketche verwendet. Anstelle der Potentiometer könnt ihr natürlich irgendetwas anderes an die Eingänge hängen. Zum Prüfen der Ergebnisse könntet ihr ein Multimeter verwenden oder ihr messt parallel mit den analogen Eingängen des Arduino.

Auf Pull-Ups an den I2C Leitungen konnte ich, wie schon erwähnt, verzichten. Falls ihr Probleme habt, dann ergänzt sie.

Beschaltung des ADS1115 - verwendet für alle Beispielsketche
Beschaltung des ADS1115 – verwendet für alle Beispielsketche

Ansteuerung mit der ADS1115_WE Bibliothek

Ihr könnt die Bibliothek über die Arduino Bibliotheksverwaltung oder hier von Github herunterladen.

Anhand von Beispielsketchen lässt sich der Umgang mit der ADS1115_WE Bibliothek am besten erklären. Ich habe die Bibliothek mit sechs Beispielsketchen ausgestattet. Auf Single_Shot.ino gehe ich am intensivsten ein. Das meiste wiederholt sich dann in den anderen Sketchen.

Beispielsketch 1: Single_Shot.ino

Mit diesem Sketch messen wir die vier Eingänge im Single-Shot Modus (also auf Anfrage) nacheinander gegen GND. Die möglichen Parameter zu den Bibliotheksfunktionen sind in den Kommentaren im Sketch aufgelistet. Ein paar Anmerkungen zu den (hier relevanten) Funktionen:

  • init() setzt die Einstellungen des Konfigurationsregisters des ADS1115 auf die Standardwerte zurück. Das hat den Vorteil, dass ihr den ADS1115 nicht vom Strom trennen müsst, wenn ihr Änderungen an eurem Sketch vornehmt. Das müsstet ihr sonst nämlich tun, um einen definierten Zustand der Register zu haben. init() prüft außerdem die Verbindung zum Modul. Die Funktion liefert false zurück, wenn der ADS115 nicht antwortet.
  • setVoltageRange_mV() bestimmt den Spannungsbereich in Millivolt. Je kleiner der Bereich, desto größer die Verstärkung und die Auflösung (= +/-range / 215).
  • setCompareChannels() legt die zu vergleichenden Kanäle fest.
  • setConversionRate() setzt die Wandlungsrate in Wandlungen pro Sekunde (SPS = Samples per second).
  • setMeasureMode() legt den Modus fest, also kontinuierlich oder Single-Shot. Letzteres ist die Voreinstellung.
  • startSingleMeasurement() startet eine Wandlung für die zuvor mit setCompareChannels() gewählten Kanäle.
  • isBusy() liefert true, solange die Wandlung noch nicht abgeschlossen ist. Ohne die Zeile while(adc.isBusy()){} würde der Wert aus der letzten Wandlung gelesen werden – und der stammt aus einem anderen Kanal. Es gibt nur ein Wandlungsregister (Conversion Register)!
  • getResult_V() liefert die Spannung in Volt. Für kleine Werte könnt ihr getResult_mV() verwenden.

Die anderen Funktionen werden erst relevant, wenn wir den Alarm Pin benutzen.

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48

ADS1115_WE adc(I2C_ADDRESS);
// ADS1115_WE adc = ADS1115_WE(); // Alternative: sets default address 0x48

void setup() {
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }

  /* Set the voltage range of the ADC to adjust the gain
   * Please note that you must not apply more than VDD + 0.3V to the input pins!
   * 
   * ADS1115_RANGE_6144  ->  +/- 6144 mV
   * ADS1115_RANGE_4096  ->  +/- 4096 mV
   * ADS1115_RANGE_2048  ->  +/- 2048 mV (default)
   * ADS1115_RANGE_1024  ->  +/- 1024 mV
   * ADS1115_RANGE_0512  ->  +/- 512 mV
   * ADS1115_RANGE_0256  ->  +/- 256 mV
   */
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change paramater to change range

  /* Set the inputs to be compared
   *  
   *  ADS1115_COMP_0_1    ->  compares 0 with 1 (default)
   *  ADS1115_COMP_0_3    ->  compares 0 with 3
   *  ADS1115_COMP_1_3    ->  compares 1 with 3
   *  ADS1115_COMP_2_3    ->  compares 2 with 3
   *  ADS1115_COMP_0_GND  ->  compares 0 with GND
   *  ADS1115_COMP_1_GND  ->  compares 1 with GND
   *  ADS1115_COMP_2_GND  ->  compares 2 with GND
   *  ADS1115_COMP_3_GND  ->  compares 3 with GND
   */
  //adc.setCompareChannels(ADS1115_COMP_0_GND); //uncomment if you want to change the default

  /* Set number of conversions after which the alert pin will be active
   * - or you can disable the alert 
   *  
   *  ADS1115_ASSERT_AFTER_1  -> after 1 conversion
   *  ADS1115_ASSERT_AFTER_2  -> after 2 conversions
   *  ADS1115_ASSERT_AFTER_4  -> after 4 conversions
   *  ADS1115_DISABLE_ALERT   -> disable comparator / alert pin (default) 
   */
  //adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); //uncomment if you want to change the default

  /* Set the conversion rate in SPS (samples per second)
   * Options should be self-explaining: 
   * 
   *  ADS1115_8_SPS 
   *  ADS1115_16_SPS  
   *  ADS1115_32_SPS 
   *  ADS1115_64_SPS  
   *  ADS1115_128_SPS (default)
   *  ADS1115_250_SPS 
   *  ADS1115_475_SPS 
   *  ADS1115_860_SPS 
   */
  //adc.setConvRate(ADS1115_128_SPS); //uncomment if you want to change the default

  /* Set continuous or single shot mode:
   * 
   *  ADS1115_CONTINUOUS  ->  continuous mode
   *  ADS1115_SINGLE     ->  single shot mode (default)
   */
  //adc.setMeasureMode(ADS1115_CONTINUOUS); //uncomment if you want to change the default

   /* Choose maximum limit or maxium and minimum alert limit (window)in Volt - alert pin will 
   *  be active when measured values are beyond the maximum limit or outside the window 
   *  Upper limit first: setAlertLimit_V(MODE, maximum, minimum)
   *  In max limit mode the minimum value is the limit where the alert pin will be deactivated (if 
   *  not latched)  
   * 
   *  ADS1115_MAX_LIMIT
   *  ADS1115_WINDOW
   * 
   */
  //adc.setAlertModeAndLimit_V(ADS1115_MAX_LIMIT, 3.0, 1.5); //uncomment if you want to change the default
  
  /* Enable or disable latch. If latch is enabled the alarm pin will be active until the
   * conversion register is read (getResult functions). If disabled the alarm pin will be
   * deactivated with next value within limits. 
   *  
   *  ADS1115_LATCH_DISABLED (default)
   *  ADS1115_LATCH_ENABLED
   */
  //adc.setAlertLatch(ADS1115_LATCH_ENABLED); //uncomment if you want to change the default

  /* Sets the alert pin polarity if active:
   *  
   *  /* Enable or disable latch. If latch is enabled the alarm pin will be active until the
   * conversion register is read (getResult functions). If disabled the alarm pin will be
   * deactivated with next value within limits. 
   *  
   * ADS1115_ACT_LOW  ->  active low (default)   
   * ADS1115_ACT_HIGH ->  active high
   */
  //adc.setAlertPol(ADS1115_ACT_LOW); //uncomment if you want to change the default
 
  /* With this function the alert pin will be active, when a conversion is ready.
   * In order to deactivate, use the setAlertLimit_V function  
   */
  //adc.setAlertPinToConversionReady(); //uncomment if you want to change the default

  Serial.println("ADS1115 Example Sketch - Single Shot Mode");
  Serial.println();
}

void loop() {
  float voltage = 0.0;

  adc.setCompareChannels(ADS1115_COMP_0_GND);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 0 vs GND [V]: ");
  Serial.println(voltage);

  adc.setCompareChannels(ADS1115_COMP_1_GND);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 1 vs GND [V]: ");
  Serial.println(voltage);

  adc.setCompareChannels(ADS1115_COMP_2_GND);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 2 vs GND [V]: ");
  Serial.println(voltage);

  adc.setCompareChannels(ADS1115_COMP_3_GND);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 3 vs GND [V]: ");
  Serial.println(voltage);

  Serial.println("-------------------------------");
  delay(2000);
}

 

Beispielsketch 2: Continuous.ino

In diesem Beispiel misst der ADS1115 kontinuierlich. Um das Augenmerk auf das Wesentliche zu legen, beschränke ich mich auf das Auslesen nur eines Kanals. Hier abgebildet findet ihr nur die relevanten bzw. geänderten Zeilen. Die vollständigen Sketche ladet ihr mit der Bibliothek herunter.

  adc.setVoltageRange_mV(ADS1115_RANGE_6144); // wir nutzen wieder die ganze Range
  ....
  ....
  adc.setCompareChannels(ADS1115_COMP_0_GND); // wir beschränken uns auf den Kanal 0 vs. Ground
  ....
  ....
  adc.setMeasureMode(ADS1115_CONTINUOUS); // der kontinuierliche Modus wird aktiviert
  ....
 
void loop() {
  float voltage = 0.0;
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 0 vs GND [V]: ");
  Serial.println(voltage);
  Serial.println("-------------------------------");
  delay(2000);
}

Der Sketch sollte ohne weitere Erklärungen verständlich sein.

Beispielsketch 3: Single_Shot_Conv_Ready_Controlled.ino

Ich habe für den Sketch einen etwas sperrigen Namen gewählt. Übersetzt will ich damit sagen: der ADS1115 misst im Single-Shot Modus und steuert die Frequenz der Werteausgabe über die Anzahl der abgeschlossenen Messungen und die Wandlungsrate. Die Wandlungsrate (Conversion Rate) habe ich auf 8 SPS festgelegt. Alle 32 Messungen gibt der Sketch einen Wert aus, sprich alle 4 Sekunden.

  adc.setVoltageRange_mV(ADS1115_RANGE_6144); 
  ....
  ....
  adc.setCompareChannels(ADS1115_COMP_0_GND); 
  ....
  ....
  adc.setConvRate(ADS1115_8_SPS); // 8 Wandlungen pro Sekunde
  ....
  ....
  //adc.setMeasureMode(ADS1115_CONTINUOUS); // auskommentiert, also greift der Standard (Single-Shot)
  ....
  ....
void loop() {
  float voltage = 0.0;
  for(int i=0; i<32; i++){ // warten bis 32 Messungen durchgeführt wurden
    adc.startSingleMeasurement();
    while(adc.isBusy()){}
  }
  voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
  Serial.print("Channel 0 vs GND [V]: ");
  Serial.println(voltage);
  Serial.println("-------------------------------");
}

 

Beispielsketch 4: Single_Shot_Conv_Ready_Alert_Controlled.ino

Ein noch sperrigerer Name. Auch dieser Sketch steuert die Ausgabefrequenz über die Anzahl der abgeschlossenen Wandlungen. Im Gegensatz zum letzten Beispiel fragt der Arduino die Vollendung einer Wandlung aber nicht über isBusy() ab, sondern der ADS1115 teilt dieses Ereignis über den Alarm Pin mit. Geht dieser auf LOW, wird ein Interrupt ausgelöst, der die Variable counter inkrementiert.

Als neue Funktionen benutzt der Sketch:

  • setAlertPinMode() legt normalerweise fest, nach wie vielen Limitüberschreitungen der Alarm aktiv wird (1, 2 oder 4). Eigentlich ist das hier nicht relevant. Wenn ihr die Funktion aber nicht aufruft, greift die Voreinstellung (ADS1115_DISABLE_ALERT). Bedeutet: die Funktion muss für diesen Sketch mit einem beliebigen Parameter außer ADS1115_DISABLE_ALERT aufgerufen werden.
  • setAlertPol() bestimmt, ob der Alarm Pin im Alarmfall LOW oder HIGH ist. Die Voreinstellung ist LOW (ADS1115_ACT_LOW).
  • setAlertPinToConversionReady() teilt dem ADS1115 mit, dass der Alarm bei einer vollendeten Wandlung ausgelöst werden soll.

Der Conversion Ready Alarm funktioniert übrigens nicht im kontinuierlichen Modus.

....
....
int interruptPin = 2;
volatile bool convReady = false;
....
....
void setup() {
  ....
  ....
  pinMode(interruptPin, INPUT_PULLUP);
  ....
  ....
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); 
  ....
  ....
  adc.setCompareChannels(ADS1115_COMP_0_GND); 
  ....
  ....
  adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); // siehe Erklärung
  ....
  ....
  adc.setConvRate(ADS1115_8_SPS); //comment line/change paramater to change SPS
  .... 
  ....
  //adc.setMeasureMode(ADS1115_CONTINUOUS); // auskommentiert, also Single-Shot
  ....
  ....
  //adc.setAlertPol(ADS1115_ACT_LOW); // Der Alarm Pin geht LOW, wenn er aktiv ist
  ....
  ....
  adc.setAlertPinToConversionReady(); // der Alarm Pin wird auf Conversion Ready eingestellt
  ....
  ....
  attachInterrupt(digitalPinToInterrupt(interruptPin), convReadyAlert, FALLING); // Interrupt, wenn Alarm Pin auf Low geht, ISR = convReadyAlert
  adc.startSingleMeasurement(); // Messung wird gestartet 
}

void loop() {
  float voltage = 0.0;
  static int counter = 0;
  if(convReady){
    counter++;
    convReady = false;
    if(counter==32){  // counter ist 32, Wandlungsrate ist 8 SPS --> 4s
      voltage = adc.getResult_V(); 
      Serial.print("Channel 0 vs GND [V]: ");
      Serial.println(voltage);
      Serial.println("-------------------------------");
      counter = 0;
    }
    adc.startSingleMeasurement();   
  }
}

void convReadyAlert(){  // Interrupt Service Routine (ISR)
   convReady = true;
}

 

Beispielsketch 5: Alert_Window_Mode.ino

Jetzt kommen wir zu einer sehr hilfreichen Funktion des ADS1115 und zwar dem Alarm bei einer Limitüberschreitung. Damit könnt ihr sehr bequem Spannungen überwachen.

Der Alarm Pin wird dabei aktiv, wenn von euch festgelegte Limits über- bzw. unterschritten werden. Unter welchen Bedingungen der ADS1115 den Alarm Pin wieder deaktiviert, hängt von weiteren Einstellungen ab.

Folgende neue Funktion ist relevant:

  • setAlertModeAndLimit() :
    • Legt den Modus fest:
      • Mit ADS1115_WINDOW definiert ihr ein Fenster mit Maximum und Minimum. Bei Werten außerhalb des Limits wird der Alarm Pin aktiv. Ermittelt der ADS1115 danach Werte innerhalb des Limits, wird der Alarm Pin wieder inaktiv – es sei denn die Verriegelung (latch) ist aktiv.
      • Mit ADS1115_MAX_LIMIT wird der Alarm Pin nur dann aktiv, wenn das Maximum überschritten wird. Das Minimum ist der Wert, bei dem der Pin wieder inaktiv wird – es sei denn die Verriegelung ist aktiv.
    • Neben dem Modus übergibt die Funktion auch die Grenzwerte in Volt.

Was es mit der Verriegelung (latch) auf sich hat, erfahrt ihr in Beispielsketch 6. Im aktuellen Beispiel geht der Alarm Pin automatisch auf inaktiv, wenn die o.a. Bedingungen eintreten.

Hinweis: mit aktiviert und deaktiviert beziehe ich mich auf „Alarm an“ / Alarm aus“. Deaktiviert heißt nicht, dass der Alarm Pin funktionslos ist. Im englischen kann man das klarer mit „asserted / not asserted“ ausdrücken.

....
....
int ledPin = 10; // eine LED, die einen Alarm anzeigt
volatile bool outOfLimit = false;
....
....

void setup() {
  ....  
  pinMode(interruptPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  ....
  ....
  adc.setCompareChannels(ADS1115_COMP_0_GND); 
  ....
  ....
  adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); // Alarm bei einer Überschreitung
  ....
  ....  
  adc.setMeasureMode(ADS1115_CONTINUOUS); // es macht Sinn eine Überwachung im Continous Modus laufen zu lassen
  ....
  ....
  adc.setAlertModeAndLimit_V(ADS1115_WINDOW, 3.0, 1.5); //you can change modes / limits
  ....
  ....
  //adc.setAlertPinToConversionReady(); //muss in diesem Beispiel auskommentiert werden
  ....
  attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
}

void loop() {
  float voltage = 0.0;
  if(outOfLimit){
    voltage = adc.getResult_V();
    Serial.print("Voltage [V]: ");
    Serial.println(voltage);  
    digitalWrite(ledPin,HIGH);
    delay(1000);
    digitalWrite(ledPin,LOW);
    outOfLimit = false;
    attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING); 
  } 
}

void outOfLimitAlert(){
  detachInterrupt(2);
  outOfLimit = true;
}

 

Beispielsketch 6: Alert_Window_Mode_with_Latch.ino

Dieser Sketch macht im Prinzip dasselbe wie Alert_Window_Mode.ino, nur dass hier die Verriegelung hinzukommt. Die Verriegelung verhindert, dass der Alarm Pin automatisch wieder deaktiviert wird.

Folgende neue Funktionen sind relevant:

  • setAlertLatch() aktiviert oder deaktiviert die automatische Verriegelung
  • clearAlert() deaktiviert den Alarm Pin. Die Verriegelung rastet beim nächsten Messwert außerhalb der Limits wieder ein. Alternativ zu clearAlert() könnt ihr getResult_V() oder getResult_mV() verwenden.
....
volatile int interruptPin = 2;
int ledPin = 10;
volatile bool outOfLimit = false;
....
....
void setup() {
  ....
  ....
  adc.setCompareChannels(ADS1115_COMP_0_GND);
  ....
  ....
  adc.setAlertPinMode(ADS1115_ASSERT_AFTER_1); // ...AFTER_2 oder ...4 ginge auch
  ....
  ....
  adc.setMeasureMode(ADS1115_CONTINUOUS); 
  ....
  ....
  adc.setAlertModeAndLimit_V(ADS1115_WINDOW, 3.0, 1.5); //ihr könnt auch die Max Limit Methode nehmen
  ....
  ....
  adc.setAlertLatch(ADS1115_LATCH_ENABLED); // Verriegelung wird aktiviert
  ....
  ....
  attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING);
}

void loop() {
  float voltage = 0.0;
  if(outOfLimit){
    voltage = adc.getResult_V();
    Serial.print("Voltage [V]: ");
    Serial.println(voltage);  
    digitalWrite(ledPin,HIGH);
    delay(1000);
    digitalWrite(ledPin,LOW);
    outOfLimit = false;
    attachInterrupt(digitalPinToInterrupt(interruptPin), outOfLimitAlert, FALLING); 
    adc.clearAlert(); // der Alarm wird gelöscht; alternativ könnt getResult_V() / getResult_mV aufrufen
  } 
}

void outOfLimitAlert(){
  detachInterrupt(2);
  outOfLimit = true;
}

 

Nach der Ausgabe des out-of-limit Wertes und dem Warnleuchten der LED wird zunächst der Interrupt wieder scharfgeschaltet. Dann wird der Alarm mit clearAlert() deaktiviert, d.h. der Pin geht HIGH. Sofern die Out-of-Limit Bedingungen noch bestehen, wird sofort der nächste Interrupt ausgelöst. Als Folge leuchtet die LED fast durchgehend. 

Die Verriegelung gibt mehr Kontrolle, ihr müsst aber beim zeitlichen Ablauf aufpassen. Wenn ihr die Interruptfunktion einschaltet, nachdem ihr den Alarm deaktiviert habt, dann ist der Alarm Pin u. U. schon wieder Low und ein „Falling“ tritt entsprechend nicht mehr ein.

Nachtrag 08.08.20

Ich habe in der aktuellsten Version der Bibliothek nachträglich noch ein paar Funktionen hinzugefügt, die das Ergebnis der Konversion in anderen Formaten bzw. Skalen liefern. So könnt ihr euch das Ergebnis z.B. wie bei einem Arduino als 10 Bit Wert mit 0 = 0 Volt und 1023 = 5 Volt ausgeben lassen. Ihr könnt auch die Rohdaten abrufen. In einem weiteren Beispielsketch (Result_Format_Options) wird das alles erklärt. Den findet ihr auf Github oder ihr aktualisiert über die Bibliotheksverwaltung.

Alle Funktionen auf einen Blick

Hier habe ich noch einmal alle Funktionen zusammengefasst. Die Tabelle ist in englisch, da sie Teil meiner Dokumentation auf Github ist.

Eine Funktion habe ich noch nicht erwähnt, und zwar reset(). Sie benutzt den globalen I2C Reset (0x06). Alle I2C Geräte, die sich auf derselben Kommunikationsleitung befinden und auch auf die globalen Befehle (general calls) hören, führen bei Aufruf der Funktion einen Reset aus. 

Liste der Funktionen der ADS1115 Bibliothek
Liste der (öffentlichen) Funktionen der ADS1115 Bibliothek

Tiefere Einblicke in den ADS1115

Registerüberblick

Register des ADS1115
Register des ADS1115

Der ADS1115 hat eine sehr übersichtliche Registerstruktur. Alle Einstellungen – mit einer Ausnahme – nehmt ihr im Konfigurationsregister (Config Register) vor. Darauf gehe ich gleich noch näher ein.

Die Ergebnisse der Wandlungen ruft ihr im Wandlungsregister (Conversion Register) ab. Es gibt nur eines davon für alle vier Kanäle. Deswegen müsst ihr immer erst den Kanal wählen und dann warten, bis ein Ergebnis für diesen Kanal vorliegt. Das LSB für das Wandlungsregister ist:

LSB = \frac{Range}{2^{15}}

Wenn ihr die Range, so wie ich, in Millivolt definiert habt, rechnet ihr die Spannung in Volt dann folgendermaßen aus:

U \text{[V]} = \frac{LSB \cdot ConvRegister}{1000}

Da das Wandlungsregister vorzeichenbehaftet ist, kann es Werte von +215 bis -215 annehmen.

Das Lesen des Wandlungsregisters löscht einen Limitalarm, sofern der Alarm nicht „verriegelt“ (latch enabled) ist.

In die beiden Limitregister (Lo_thresh und Hi_thesh Register) tragt ihr die Grenzwerte ein, sofern ihr die Alarmfunktion nutzen möchtet. Die Inhalte der Limitregister vergleicht der ADS1115 mit dem Inhalt des Wandlungsregisters. Ändert ihr die Range, müsst ihr auch den Inhalt der Limitregister umrechnen. Meine Bibliothek macht das automatisch. Dadurch ist meine Funktion setVoltageRange() etwas komplex geworden.

Die einzige Einstellung, die ihr außerhalb des Konfigurationsregisters vornehmt (die Limits natürlich ausgenommen), ist die Festlegung des Alarms als „Conversion Ready Alarm“. Um diese Funktion zu aktivieren, müsst ihr in das MSB des Hi_thresh Registers eine „1“ und in das MSB des Lo_Thresh Registers eine „0“ schreiben. Da die Limitregister vorzeichenbehaftet sind, ist das obere Limit damit negativ und das untere positiv. Diese an sich sinnlose Bedingung sagt dem ADS1115, dass er den Alarmpin aktiv schalten soll, wenn eine Wandlung abgeschlossen ist. Die Bibliothek bietet dafür die Funktion setAlertPinToConversionReady().

Das Konfigurationsregister

Konfigurationsregister des ADS1115
Konfigurationsregister

Das Konfigurationsregister enthält die folgenden Bits:

  • COMP_QUE[1:0]: legt fest, nach wie vielen „out-of-range“ Messungen der ADS1115 den Alarmpin aktiviert. Alternativ schalten die Bits die Alarmfunktion aus. Die zugehörige Funktion lautet setAlertPinMode().
  • COMP_LAT aktiviert oder deaktiviert die Verriegelung des Alarms. Bei Verriegelung müsst ihr den Alarm manuell deaktivieren. Das COMP_LAT Bit wird mit setAlertLatch() gesetzt oder gelöscht.
  • COMP_POL legt die Polarität des Alarmpins fest -> setAlertPol().
  • COMP_MODE bestimmt den Alarmmodus. Entweder definiert ihr ein oberes Limit oder ein Fenster. Die zugehörige Funktion setAlertModeAndLimit() bestimmt den Modus und setzt die Limits.
  • DR[2:0] bestimmt die Wandlungsrate -> setConvRate().
  • MODE: legt den kontinuierlichen oder Single-Shot Modus fest -> setMeasureMode().
  • PGA[2:0] legt die Range fest -> setVoltageRange_mV();
  • MUX[2:0] wählt den Kanal bzw. die zu vergleichenden Kanäle -> setCompareChannels().
  • OS hat eine Doppelbedeutung. Beim Schreiben löst eine „1“ im Single-Shot Modus eine Messung aus -> startSingleMeasurement(). Beim Lesen bedeutet eine „0“, dass derzeit eine Wandlung stattfindet und eine „1“ das Gegenteil. Die Funktion dazu laut isBusy().

10 thoughts on “ADS1115 – A/D-Wandler mit Verstärker

  1. Wolle, Du bist ein Ass! Aus irgendeiner kosmologischen Fügung behandelst Du immer Themen die ich auch gerade aufs Auge gedrückt bekomme- Danke dafür!

    Meine Frage zum ADS1115: Ich möchte mit einem Mikro OHNE AutoGain die digitalisierten Musikdaten über I2C direkt dem Modem auf dem Arduino MKR 1400 übergeben. (Der Code soll ab einem gewissen Lärmpegel ein SMS senden und einen Rückruf auf den uController erlauben.

    Andere Leser interessiert ja ev. die Sounddigitalisierung und weiterverarbeitung über I2C auch noch.

    Hättest Du was für mich (uns)

    Andächtig lauschend und dankbar für Deinen Blog

    Roman

    1. Hallo Roman, vielen Dank. Mit Musikdigitalisierung habe ich mich noch gar nicht beschäftigt. Aber ich denke für wirklich guten Sound dürfte die Rechenleistung eines Arduino nicht ausreichen. Einfach nur einen Lärmpegel zu messen wäre wiederum sehr einfach. Da gibt es ja Module für. Zum Autogain: das habe ich nicht ganz verstanden. Eigentlich macht der ads1115 bzw. meine Bibliothek kein Autogain, sondern du bestimmst das Gain. VG, Wolfgang

      1. Hallo Wolfgang
        Es geht um einen Telefonanruf, die Rechenleistung des Arduinos wird da nicht gross beansprucht, ich will ja den bereits digitalsierten Datenstrom über I2C direkt ans Modem weiterleiten.
        Ich glaub das ist keine grosse Sache. Mit diesem Hardwaresetup will ich auch gleich den Pegel messen und daher kann ich kein Autogain beim A/D Wandler brauchen weil sonst immer der gleiche Pegel beim Arduino ankommt. Das mit der integrierten Pegelmessung in diesem Setup wird vermutlich nicht einfach, resp. Dein Hinweis auf ein eigenes Modul ist sicher bequemer aber ich hab keine Pins mehr übrig und und und….jetzt erstmal ein Bier….
        Ich probier das mal mit einem I2S MEMS Microphone und dann noch mit dem ads1115 mit einem „normalen“ Mikro und Deiner Library.
        Beste Grüsse & nochmals Danke für Deinen Blog
        Roman

        1. Hallo, das mit dem Bier ist eine gute Idee – ich schließe mich an. Wie gesagt, ich habe mich bisher nicht mit dem Thema beschäftigt und bevor ich noch Blödsinn schreibe…ach ja, ich wollte ja ein Bier trinken…

  2. Guten Morgen Wolle

    Noch eine Frage, Du hast Dich da ja schon eingearbeitet, ev hast Du einen Denkanstoss…
    Ich habe einen Wassersensor der normalerweise an einem Analog In (10Bit) angeschlossen wird.
    Dann wird gelesen und mit einer ziemlich seltsamen Formel (Copyright Seed) die TDS (Anzahl gelöster Teilchen im Wasser) ausgerechnet:

    sensorValue = analogRead(sensorPin);
    //Convert analog reading to Voltage
    Voltage = sensorValue*5/1024.0;
    //Convert voltage value to TDS value
    tdsValue=(133.42*Voltage*Voltage*Voltage – 255.86*Voltage*Voltage + 857.39*Voltage)*0.5;

    Jetzt will ich diesen Sensor mit dem ADS1115 auslesen der ja 16 Bit macht….klappt ja auch aber die Werte sind natürlich irgendwo anders.
    – Kann man einen Kanal des ADS1115 einfach mit 10 bit Auflösung betreiben?
    – Sollte die Formel Voltage = sensorValue*5/1024.0; angepasst werden? (Das *5 check ich nicht)

    Dankbar für einen Hinweis oder eine Idee

    Gruss

    Roman

    PS: Zum obigen Post : Das Modem auf dem MKR 1400 spricht nur I2S
    (Habs nach 8 Stunden geschafft, I2S ist eine Nummer…)

  3. Zitat:
    – Sollte die Formel Voltage = sensorValue*5/1024.0; angepasst werden? (Das *5 check ich nicht)

    Da wurde wohl ein 10 Bit ADC mit 5 Volt Messbereich verwendet.
    Klar, die Formel musst Du anpassen. Nimm einfach die Formel für U[V] aus dem Beitrag.
    Gruß
    Erich

    1. Genau, vielen Dank Erich. Der Arduino A/D Wandler z.B. hat 10 Bit und 5 V Referenz (wenn man nichts anderes einstellt). D. h. der A/D Wandlerwert „sensorValue“ muss in Volt umgerechnet werden. Die ADS1115 Bibliothek liefert dir direkt die Spannung in Volt.

      Ich bin von verschiedenen Seiten gefragt worden, ob ich nicht auch den Rohwert ausgeben kann. Das wäre von -32767 bis +32767. Ist nur für viele vielleicht missverständlich, weil die Zahl nur in Zusammenhang mit der Voltage Range eine Bedeutung bekommt. Aber es wird ein update in den nächsten Tagen kommen. Auch wird es dann eine Möglichkeit geben, die Ausgabe zu skalieren mit einer Funktion namens getResultWithRange(unteres Limit, oberes Limit, maximale Spannung). Mit getResultWith Range(0,1023,5000) würde man dann eine Arduino Ausgabe simulieren.

      Was ich bis heute nicht ganz verstanden habe ist, warum (fast) alle Welt immer 5/1024 als Faktor nimmt und nicht 5/1023. Eigentlich muss der Maximalwert 1023 eine Spannung von 5 Volt bedeuten. Das passt aber nicht zum Faktor 5/1024.

  4. Danke Erich & Wolle, ich war faul und hab alles wieder nur überflogen…Lesekultur am Computer 2020…
    Falls weitere Faule mitlesen: tds_voltage = (adc1 * 0.1875)/1000;

  5. Hola, quisiera saber para el cambio de direccionamiento que trae por defecto (yo tengo la placa aads1115 de color azul), que hace referencia la tabla 5 de la hoja de datos, si consiste en una simple conexión externa de los pines de la plaqueta o además hay que cortar alguna pista interna de la plaqueta. gracias.

    1. Hola,
      hay diferentes módulos azules. Su módulo tiene un pin „ADDR“? Puede conectar este pin a GND, VCC, SDA o SCL. También hay módulos sin el pin „ADDR“. Entonces es difícil, pero no imposible. Si puede soldar bien, puede crear un puente de cable desde el Pin1 a GND, VCC, SDA o SCL. Espero que esta traducción de Google tenga sentido. Yo no hablo español.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.