Raspberry-Pi-Projekt: Analog-Digital-Wandler ADS1115/ADS1015

Prof. Jürgen Plate

Raspberry Pi: Analog-Digital-Wandler ADS1115/ADS1015

Allgemeines

Der Raspberry Pi hat ja keine Schnittstelle zum Erfassen analoger Daten. Der Analog-Digital-Wandler (ADC) ADS1115 von texas Instruments stellt ein perfektes Frontend für relativ langsame (weniger als 1 kHz) aber präzise Datenerfassungssysteme dar. Der ADS1115 bietet 16-Bit-Genauigkeit bei maxmal 860 Abtastungen pro Sekunde (Der ADS1015 hat 12 Bit Auflösung). Er wird über I2C angebunden. Der Chip besitzt vier Single-Ended-Eingangskanäle, die auch als zwei Differenzkanäle konfiguriert werden können. Der recht komplexe Baustein enthält sogar einen programmierbaren Verstärker, um kleinere Einzel- oder Differential-Signale auf die volle Bandbreite zu bringen. Der ADS1115 kann mit Versorgungsspannungungen zwischen 2 V und 5 V betrieben werden, passt also gut zum Raspberry Pi.

Technische Daten

Im Single-Ended-Modus beträgt der maximale Spannungsbereich 0 bis VDD. Im Differential-Modus ist der Spannungsbereich -VDD bis +VDD. Der tatsächlich verwendbare Bereich ist aber von der programmierbaren Verstärkung (PGA) abhängig. Für den ADS1115 liegt der Ausgabebereich zwischen 0 und 32767 (single-ended) bzw. -32768 bis +32767 (differential).

ADC-Hardware

Der Chip ist ziemlich klein, daher ist es besser ein fertiges Breakout-Board zu kaufen. Der ADC erzeugt beim Messzyklus Stromspitzen, die über die Versorgungsleitungen auf andere Systemkomonenten rückwirken können. Das Board blockt daher die Stromversorgung mit einem größerer Kondensator und Drosselspulen an den Versorgungsanschlüssen.

Die Schnittstellen-Adresse kann auf vier unterschiedliche Werte geändert werden. Beim ADC wird das über nur einen einzigen Eingang recht trickreich bewerkstelligt:

Per Default ist auf den meisten Breakout-Boards die Adresse 0x48 eingestellt, wie der folgende Schaltplan zeigt.

Wenn Sie die Platine mit 5 V speisen, so müssen Sie die beide Pullup-Widerstände R1 und R2 (direkt über den SDA- und SCL-Anschlüssen) entfernen. Wenn Sie das Modul mit 3,3 V versorgen oder einen Pegelwandler verwenden, ist keine Anpassung notwendig. Wenn Sie den ALRT-Pin auch verwenden, so muss bei 5V-Speisung auch der Pullup-Widerstand R4 (auch wieder direkt über dem Anschusspin) entfernt werden. Die Verdrahtung des Moduls ist ganz einfach:

Bleibt noch die Beschaltung der analogen Eingänge. Das Datenblatt enthält dazu einen Schaltplan des Eingangsmultiplexers:

Wie man sieht, sind die Eingänge mit Dioden geklammert, so dass Spannungen die größer als VDD+0,3 V bzw. kleiner als -0,3 V sind, nach VDD bzw. GND abgeleitet werden (Schottky-Dioden). Es fehlen jedoch Schutzwiderstände. Wenn die angeschlossene Messspannungsquelle genügend Strom liefert, werden die Dioden und als Folge weitere interne Komponenten zerstört. Insofern sollte man einen genügend großen Vorwiderstand zwischen Messpunkt und ADC-Eingang schalten. Mit 330 bis 470 Ohm sollte man bei Spannungen bis 5 V auf der sicheren Seite sein. Bei einem Vorwiderstand von etwa 10kΩ verträgt der Chip auch eine höhere Überspannung, ohne dass die Messung im Sollbereich beeinträchtigt wird. Sinnvole Ergebniswerte erhält man außerhalb des Sollbereichs natürlich nicht.

Das Gerücht, dass man den Chip zerstört, wenn die Eingangsspannung multipliziert mit dem Verstärkungsfaktor den Sollbereich überschreitet stimmt jedoch nicht. Der interne Verstärker kann maximal VDD an seinem Ausgang liefern. Wird rein rechnerisch Uin * Verstärkung > VDD, gibt der ADC den Maximalwert aus. Der Chip wird dabei keinesfalls beschädigt - man misst halt Mist.

Programmierung

Der ADS1115 ist bei der Programmierung etwas komplexer als andere Chips, da er per Software konfiguriert wird. Es gibt aber eine umfangreiche Python-Klassenbibliothek ADS1x15 von Tony DiCola von Adafruit Industries, die public domain zur Verfügung steht.

Der ADS1115 besitzt drei Register:

Der erste ist ein 8-Bit-Register, das lediglich festlegt, auf welches der anderen Register zugegriffen werden soll - entweder auf das 16-Bit-Nur-Lese-Datenregister (00) oder auf das 16-Bit-Lese-/Schreib-Register für die Konfiguration (01). Im Datenregister (Conversion Register) befindet sich jeweils das Ergebnis der A/D-Umwandlung. Im Configuration Register wird der Arbeitsmodus eingestellt, siehe folgende Tabelle. Weitere Register sind das Lo_thresh-Register (10) und das Hi_thresh Register (11).

Configuration Register
BitBeschreibung
15 Betriebszustand/Single-Shot-Konvertierung starten
Dieses Bit bestimmt den Betriebszustand des ADC, es kann nur im Power-Down-Modus geschrieben werden. Wird eine "1" hineingeschrieben, startet eine einzelne Konvertierung (im Power-Down-Mode). Beim Lesen des Bits zeigt eine "0" eine gerade eine Konvertierung an, eine "1" den Idle-Modus.
14-12 Eingangsmultiplexer-Konfiguration:
000: AINP = AIN0 and AINN = AIN1 (default)   100: AINP = AIN0 and AINN = GND
001: AINP = AIN0 and AINN = AIN3             101: AINP = AIN1 and AINN = GND
010: AINP = AIN1 and AINN = AIN3             110: AINP = AIN2 and AINN = GND
011: AINP = AIN2 and AINN = AIN3             111: AINP = AIN3 and AINN = GND
11-9 Verstärkungsfaktor-Konfiguration (PGA Programmable Gain Amplifier):
PGA-Wert     FS (V)
  2/3       ± 6,144 V
   1        ± 4,096 V
   2        ± 2,048 V
   4        ± 1,024 V
   8        ± 0,512 V
  16        ± 0,256 V
8 Dieses Bit steuert den aktuellen Betriebsmodus des ADS1115.
0: Kontinuierlicher Konvertierungsmodus
1: Power-Down-Single-Shot-Modus (Default)
4 Dieses Bit steuert den Komparator-Betriebsmodus. Der interne Komparator des ADC arbeitet entweder al traditioneller Komparator mit Hysterese ('0') oder als Fensterkomparator ('1'). Für die Einstellung der Komparator-Ober- und Untergrenze besitzt der ADS1115 zwei weitere 16-Bit-Register, die lesbar- und schreibbar sind (Lo_thresh and Hi_thresh Registers, siehe Datenblatt).
3 Dieses Bit steuert die Polarität des ALERT/RDY-Pins. Ist es '0', ist der Komparatorausgang aktiv low, hat es den Wert '1', ist der ALERT/RDY-Pin aktiv high.
2 Dieses Bit legt fest, ob der ALERT/RDY-Pin seinen Zustand behält, wenn er einmal aktiviert wurde oder ob er bei jeder Konvertierungen neu gesetzt wird. Ist das Bit '0', wird der ALERT/RDY-Pin bei jeder Konversion neu gesetzt/rückgesetzt. Ist es '1' bleibt der aktivierte ALERT/RDY-Pin gesetzt, bis die Konvertierungsdaten gelesen wurden.
1-0 Diese Bits haben zwei Aufgaben. Sind sie auf "11" gesetzt, schalten sie die Komparatorfunktion aus und setzen die ALERT/RDY-Leitung auf High-Pegel. Sind sie auf einen anderen Wert eingestellt, steuern sie die Anzahl der aufeinanderfolgenden Konvertierungen, die beim Überschreiten der oberen oder unteren Schwellenwerte zur Aktivierung des ALERT/RDY-Pins erforderlich ist:
00: nach einer Konvertierung
01: nach zwei Konvertierungen
10: nach vier Konvertierungen
11: Komparator deaktivieren (default)

Der Verstärkungsfaktor des analogen Signals kann also per Konfiguration eingestellt werden. Die Verstärkung steuert auch den Bereich der möglichen Eingangsspannungen. Bei einem Verstärkungsfaktor von 1 kann der Chip Eingangswerte von -4,096 V bis +4,096 V verarbeiten (bei 5 V Versorgung). Um schwächere Signale mit höherer Genauigkeit zu lesen, wählt man höhere Verstärkungen aus. Die Wahl des richtigen Faktors für ein bestimmtes Eingangssignal ist sehr wichtig für die Genauigkeit der Messung. Es lohnt sich also, über die maximal auftretenden Eingangsspannungen nachzudenken. Eine zu hohe Verstärkung bewirkt eventuell die Kappung der Werte bei höheren Eingangssignalen und damit fehlerhafte Ergebnisse. Bei einer zu geringen Verstärkung versinkt das Signal im Rauschen und ist ebenfalls ungenau.

Ein einfache C-Programm

Das folgende Programm demonstriert den Zugriff auf den Baustein mit der Programmiersprache C. Es gibt hier keine Bibliothek oder Funktionen, sondern nur ein einfaches Programm. Auch die Konfiguration wurde vorab ermittelt und wird als Hexzahl übergeben. Eine Erweiterung oder Modifikation sollte nicht allzu schwer sein - auch weil man die folgenden Pythonprogramme als Inspiration verwenden kann:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/i2c-dev.h>

#define ADS_ADDR 0x48

int main()
  {
  int fd;                 /* Device-Handle */
  uint8_t buf[10];        /* I/O buffer */
  int16_t val;            /* Result (int) */

  /* open device on /dev/i2c-1 */
  if ((fd = open("/dev/i2c-1", O_RDWR)) < 0)
    {
    printf("Error: Couldn't open device! %d\n", fd);
    return 1;
    }
  /* connect to ads1115 as i2c slave */
  if (ioctl(fd, I2C_SLAVE, ADS_ADDR) < 0)
    {
    printf("Error: Couldn't find device on address!\n");
    return 1;
    }


  for (;;) // loop forever
    {
    /* set config register (reg. 1) and start conversion
     * AIN0 and GND, 4.096 V, 128 samples/s
     */
    buf[0] = 1;
    buf[1] = 0xc3;
    buf[2] = 0x85;
    if (write(fd, buf, 3) != 3)
      {
      perror("Write to register 1");
      exit(-1);
      }

    /* wait for conversion complete (msb == 0) */
    do {
      if (read(fd, buf, 2) != 2)
        {
        perror("Read conversion");
        exit(-1);
        }
      } while (!(buf[0] & 0x80));

    /* read conversion register (reg. 0) */
    buf[0] = 0;
    if (write(fd, buf, 1) != 1)
      {
      perror("Write register select");
      exit(-1);
      }
    if (read(fd, buf, 2) != 2)
      {
      perror("Read conversion");
      exit(-1);
      }

    /* convert buffer to int value */
    val = (int16_t)buf[0]*256 + (uint16_t)buf[1];

    /* display results */
    printf("Hex: 0x%02x%02x - Int: %d - Float, converted: %f V\n",
           buf[0], buf[1], val, (float)val*4.096/32768.0);

    /* pause 0.5 s */
    usleep(500000);
    }

  close(fd);
  return 0;
  }

Programmierung in Python

Installieren Sie die Adafruit-Bibliothek mittels pip oder laden Sie die Bibliothek mit Beispielen (.ZIP) herunter und speichern Sie das Python-Modul ADS1x15.py im gleichen Verzeichnis, in dem sich Ihr Programm befindet. Die Datei ist auch ausführlich kommentiert, so dass der Quellcode auch gleichzeitig Dokumentation sein kann. Diese Bibliothek ist auch derart angepaßt, als dass es nur die Python-Standardbibliotheken verwendet. Im Web findet man auch Versionen der ADS1x15-Software, die ihrerseits weitere Adafruit-Module benötigen. Hinweis: Wenn Sie die Bibliothek mit dem Befehl pip aus dem Python-Paket-Index installiert haben, sind die vier Beispieldateien nicht dabei und Sie müssen diese manuell herunterladen.

Im Folgenden finden Sie eine kurze Liste der von der Bibliothek bereitgestellten Funktionen:

readADC(channel, gain=1, data_rate=None)
Diese Funktion liest einen einzigen Messwert vom angegebenen Kanal mit den angegebenen Parametern (gain = programmierbarer Verstärkungsverstärker, data_rate = Abtastwerte pro Sekunde). Für gain können die Werte 2/3, 1, 2, 4, 8 oder 16 angegeben werden. Bei der Datenrate gibt es Unterschiede zwischen AD1015 und ADS1115:
ADS1015: 128, 250, 490, 920, 1600(default), 2400, 3300
ADS1115: 8, 16, 32, 64, 128 (default), 250, 475, 860
Wird für die Datenrate 'None' angegeben, nimmt die Funktion den globalen Default.

read_adc_difference(differential, gain=1, data_rate=None)
Einlesen der Differenz zwischen zwei ADC-Kanälen als vorzeichenbehaftetes ganzzahliges Ergebnis. differential muss einer der folgenden Werte sein:

start_adc (channel, gain = 1, data_rate = None)
Starten der kontinuierlichen Konvertierungen auf dem angegebenen Kanal (0-3). Es wird ein erstes Konvertierungsergebnis zurückgeben. Ab da können weitere Messungen durch den Aufruf von get_last_result() erfolgen. Beendet wird dieser Modus durch den Aufruf von stop_adc(). Auch hier können wieder Verstärkung und Abtastrate eingestellt werden.

start_adc_difference (differential, gain = 1, data_rate = None)
Starten des kontinuierlichen Modus für die Differenzmessung. Für differential und weitere Parameter siehe oben read_adc_difference(). Die Funktion gibt ein erstes Konvertierungsergebnis zurück. Ab da können weitere Messungen durch den Aufruf von get_last_result() erfolgen. Beendet wird dieser Modus durch den Aufruf von stop_adc().

start_adc_comparator (channel, high_threshold, low_threshold, gain=1,
data_rate=None, active_low=True, traditional=True,
latching=False, num_readings=1)

Starten des kontinuierlichen Modus auf dem angegebenen Kanal (0-3) mit aktiviertem Komparator. Der Komparator prüft nun, ob der ADC-Wert innerhalb des Bereichs von "high_threshold" und "low_threshold" liegt (beide Werte müssen 16-Bit-Integer-Werte sein) und löst gegebenenfalls den ALERT-Pin aus. Das Verhalten kann durch folgende Parameter gesteuert werden:

Die Funktion gibt ein erstes Konvertierungsergebnis zurück. Ab da können weitere Messungen durch den Aufruf von get_last_result() erfolgen. Beendet wird dieser Modus durch den Aufruf von stop_adc().

start_adc_difference_comparator(differential, high_threshold, low_threshold,
gain=1, data_rate=None, active_low=True,
traditional=True, latching=False, num_readings=1)

Wie oben, jedoch für Differenzmessungen.

stop_adc()
Stoppt alle kontinuierlichen ADC-Operationen (siehe auch oben).

get_last_result()
Die Funktion gibt im kontinuierlichen Modus das nächste Konvertierungsergebnis zurück.

Für einen ersten Test eignet sich simpletest.py, das ein grundlegendes Beispiel für das Lesen und Anzeigen der ADC-Kanalwerte darstellt. Nach dem Start werden fortlaufend alle vier Kanäle gelesen und angezeigt, bis das Programm mittels Strg-C beendet wird. Um das Programm laufen zu lassen, muss zunächst eingestellt werden, ob der ADS1015 (12 Bit) oder ADS1115 (16 Bit) verwendet werden soll. Dann kann man noch einen Verstärkungsfaktor (GAIN) festlegen.

#!/usr/bin/env python

import time

# Import the ADS1115 module.
# Create an ADS1115 ADC (16-bit) instance.
from ADS1x15 import ADS1115
adc = ADS1115()

# Import the ADS1015 module.
# Create an ADS1015 ADC (12-bit) instance.
#from ADS1x15 import ADS1015
#adc = ADS1015()

# Note you can change the I2C address from its default (0x48)
# bus by passing in these optional parameters:
#adc = ADS1115(address=0x49, busnum=1)

# Choose a gain of 1 for reading voltages from 0 to 4.09V.
GAIN = 1

print('+---------+---------+---------+---------+')
print('|    0    |    1    |    2    |    3    |')
print('+---------+---------+---------+---------+')

# Main loop.
while True:
    # Read all the ADC channel values in a list.
    values = [0]*4
    for i in range(4):
      # Read the specified ADC channel using the previously set gain value.
      values[i] = adc.read_adc(i, gain=GAIN, data_rate=128)

    # Print the ADC values.
    print('| {0:>7} | {1:>7} | {2:>7} | {3:>7} |'.format(*values))

    # Pause for half a second.
    time.sleep(0.5)

Das folgende Beispiel continuous.py zeigt, wie der kontinuierliche Lesemodus aktiviert und ein Strom von ADC-Werten gelesen wird. Dies ist nützlich, wenn Sie nur Werte vom Chip lesen und nicht die Funktion read_adc() wiederholt aufrufen wollen. Der Kanal ist dabei fest. Sobald Sie versuchen, von einem anderen Kanal zu lesen, wird der kontinuierliche Modus beendet. Dazu ein Beispiel:

#!/usr/bin/env python

import time

# Import the ADS1115 module.
from ADS1x15 import ADS1115
adc = ADS1115()

# Start continuous ADC conversions on channel 0
adc.start_adc(0, gain=1)

# 10 Sekunden lang Daten lesen
start = time.time()
while (time.time() - start) <= 10.0:
  # Read the last ADC conversion value and print it out.
  value = adc.get_last_result()
  print('%d - %.5f V'% (value, float(value)*4.096/32768.0))
  # Sleep for half a second.
  time.sleep(0.5)
adc.stop_adc()

Das Beispielprogramm differential.py arbeitet genauso wie simpletest.py. Es ruft die Funktion read_adc_difference() auf und liest damit die Spannungsdifferenz zwischen Kanal 0 und 1 des Chips. Siehe Links unten.

Das letzte Beispiel, comparator.py demonstriert einen Modus des Chips, bei dem man einen ALERT-Ausgangspin aktivieren kann, wenn der ADC-Wert in einen bestimmten Bereich fällt. Siehe Links unten.

Links


Copyright © Hochschule München, FK 04, Prof. Jürgen Plate und die Autoren
Letzte Aktualisierung: