MCP4725 DAC Modul (Teil 1)

DAC Module

Eine der Grenzen des Arduino Uno ist, dass er keinen DAC hat. Das externe MCP4725-Modul ist daher eine interessante Ergänzung.

MCP4725 DAC Modul

Der MCP4725 ist ein 12-Bit-DAC von Microchip, der über I2C mit dem Arduino verbunden werden kann. Ein Digital-Analog-Wandler (DAC) ermöglicht die Ausgabe eines analogen Signals mit einem Mikrocontroller. Er macht im Grunde das Gegenteil des Analog-Digital-Wandlers, der es ermöglich eine analoge Spannung zu messen und in einen digitalen Wert umzuwandeln. Der MCP4725 verfügt über einen einzigen analogen Ausgang. Sein großer Bruder, der MCP4728, hat dagegen vier Stück.

Es gibt verschiedene Methoden, um einen digitalen Wert in eine analoge Spannung umzuwandeln. Der MCP4725 nutzt ein direktes Umsetzungsverfahren. Er enthält eine Kette von 4096 identischen Widerständen, die einen riesigen Spannungsteiler bilden. Dieser DAC Typ wird im englischen deshalb auch als String-DAC bezeichnet. Der Spannungsteiler erzeugt permanent alle 4096 möglichen Ausgangsspannungen. Mithilfe einer digital steuerbaren Schaltmatrix können wir einen der 4096 Spannungsausgänge des Spannungsteilers auswählen und mit der Ausgangsstufe des DACs verbinden. Bei 5V Versorgungsspannung können so Ausgangsspannungen zwischen 0 V und 4,9988 V in 0,0012 V Schritten gewählt werden. Im Arduino-Programm wird die Ausgangsspannung durch eine Ganzzahl zwischen 0 und 4095 dargestellt. Die Umrechnung zwischen diesem Wert und der tatsächlichen Spannung ist mit der folgenden Formel möglich:
\(V_{DAC} = {{value \cdot V_{cc}} \over 4096}\)

Das direkte Umsetzungsverfahren ermöglicht schnelle Spannungsänderungen und bietet ein sauberes Ausgangssignal mit geringem Rauschen.
Allerdings haben DACs, die diese Technik verwenden, in der Regel eine relativ geringe Auflösung. Um die Auflösung zu erhöhen, z.B. auf 16 Bit (65536 Schritte), wäre eine riesige Menge an Widerständen und Schaltern notwendig und die Kosten für einen solchen DAC würden explodieren.

Der MCP4725 bietet die folgenden Funktionen:

  • 12-Bit-Auflösung (0,0012 V @ 5V)
  • I2C-Schnittstelle
  • 2,7 - 5,5 V Versorgungsspannungsbereich
  • 6 us Einstellzeit
  • EEPROM zum Speichern eines Einschaltwertes

Die eigentlich interessantere Frage ist aber, was kann man damit machen? Was sind die möglichen Anwendungen für einen solchen DAC?

Die häufigste Anwendung für DACs ist die Erzeugung von analogen Signalen wie beispielsweise Audiosignalen. Der MCP4725 kann zwar durchaus zur Signalerzeugung eingesetzt werden, ist aber nicht für klassische Audioanwendungen konzipiert. Für Audioanwendungen ist eine Auflösung von 16 Bit de facto der Standard und einige Audio-DACs bieten sogar eine Auflösung von 24 Bit. Für diese Art von Anwendungen werden andere Typen von DACs verwendet. Außerdem wäre der Arduino Uno ohnehin nicht in der Lage, die Audio-Samples schnell genug auszugeben, da er den I2C-Bus nur mit einer maximalen Geschwindigkeit von 400 kHz ansteuern kann. Da wir mindestens 2 Bytes (16 Bit) übertragen müssen, um den 12-Bit-Ausgangswert zu setzen, können wir nur eine Abtastrate von 25 kHz erreichen. In der Praxis ist die Abtastrate viel niedriger, da wir die Zeit berücksichtigen müssen, die der Arduino benötigt, um das I2C-Paket vorzubereiten und die Geräteadresse über den Bus zu senden. Wir bräuchten aber mindestens 40 kHz, um Musik oder Sprache ohne Verzerrungen wiederzugeben.

Audio-DACs verwenden typischerweise I2S anstelle von I2C. I2S verwendet standardmäßig schnellere Datenraten. Es wird jedoch vom Arduino Uno nicht unterstützt. Der Arduino Uno ist für eine solche Anwendung ohnehin nicht geeignet, da er nicht genügend Speicherplatz hat, um die Audiodaten zu speichern. Das einzige, was wir mit dem Arduino Uno selbst machen können, ist das Erzeugen einfacher Töne. Für Projekte mit komplizierteren Soundeffekten oder Musik müssen wir externe Module verwenden, die Audiodateien speichern und abspielen können. Diese können dann durch den Arduino getriggert werden.

Ein Beispiel dafür, was wir mit dem MCP4725 und dem Arduino Uno machen können, ist die Erzeugung einfacher Signale wie Sinus- oder Dreieckswellen. Mit dem Arduino Uno selbst können wir nur Rechteckwellen erzeugen, z.B. PWM-Signale. Der DAC erweitert also unsere bisherigen Möglichkeiten.

Im Regelfall sind DACs nicht dafür ausgelegt, als variable Spannungsquelle zur Versorgung anderer Komponenten verwendet zu werden. Der MCP4725 ist für einen maximalen Kurzschlussstrom von 25 mA ausgelegt, das bedeutet jedoch nicht, dass wir ihn mit 25 mA belasten können. Selbst bei nur wenigen Mikroampere ist der DAC nicht in der Lage, die Ausgangsspannung stabil zu halten. Für eine stabile Ausgangsspannung sollte der Strom unterhalb von 1 mA liegen. Wir können den DAC also nicht direkt an eine LED anschließen. Die Helligkeit der LED ließe sich wegen ihrer stark nichtlinearen I-U-Kennlinie ohnehin nicht richtig über eine Änderung der Spannung regeln.

DACs werden fast immer in Verbindung mit externen Schaltungen verwendet. Im Falle der Audio- oder Signalerzeugung könnte dies eine Verstärkerschaltung sein, die leistungsfähig genug ist, um z.B. einen Lautsprecher zu versorgen. Es gibt jedoch noch weitere Anwendungen für DACs.

Der MCP4725 kann z.B. verwendet werden, um Schwell- oder Offsetwerte für andere analoge Schaltungen einzustellen. Ein gutes Beispiel dafür sind die Schwellwertmodule, die ich in früheren Tutorials vorgestellt habe. Sie verfügten alle über ein Potentiometer, mit dem man einen Schwellenwert einstellen kann. Diese Module verfügen auch über einen LM393-Komparator, der dann den Sensorwert mit dem Schwellwert vergleicht und den digitalen Ausgang des Schwellwertmoduls entsprechend umschaltet. Als Alternative zum Potentiometer könnte man auch einen DAC verwenden, um diesen Schwellwert programmatisch einzustellen.

In diesem Teil des Tutorials werden wir einen kurzen Blick auf die Signalerzeugung werfen. Im nächsten Teil des Tutorials möchte ich eine komplexere Schaltung zeigen, in der wir den MCP4725 verwenden, um eine per Arduino geregelte Stromquelle zu realisieren.

MCP4725 Arduino Bibliothek

Um den MCP4725 mit dem Arduino zu verwenden, benötigen wir eine Bibliothek. Für den Zweck dieses Tutorials werden wir die von Adafruit bereitgestellte verwenden. Du kannst sie mithilfe des Bibliotheksmanagers unter Werkzeuge > Bibliotheken verwalten ... installieren. Installation der Adafruit MCP4725 Bibliothek mithilfe des Bibliotheksverwalters

Die Bibliothek ermöglicht uns, die Ausgangsspannung mit der Methode setVoltage(int value, bool writeEEPROM) zu setzen. Um sie zu verwenden, müssen wir eine Instanz von Adafruit_MCP4725 erstellen und die Adresse des DACs in setup konfigurieren. Die Adresse des MCP4725 ist normalerweise entweder 0x60 oder 0x61. Wenn du jedoch das Adafruit MCP4725 Modul verwendest, ist die Adresse entweder 0x62 oder 0x63.

Hier ist ein kurzes Beispiel, das zeigt, wie eine DAC-Instanz im Code erzeugt und konfiguriert werden kann:

#include <Adafruit_MCP4725.h>

const int I2C_ADDR = 0x60;
Adafruit_MCP4725 dac;

void setup() {
  dac.begin(I2C_ADDR);
}

Danach können wir die setVoltage Methode unseres dac-Objekts aufrufen, um den gewünschten Ausgangswert an den MCP4725 zu senden:

dac.setVoltage(value, false);

Um den Wert als Einschaltwert zu speichern, kann man den Parameter writeEEPROM auf true setzen. Das Setzen des Einschaltwerts ist langsamer als das reine Setzen des Ausgangswerts. Da der EEPROM nur eine begrenzte Anzahl von Schreibvorgängen unterstützt, empfiehlt es sich, den Einschaltwert nur zu aktualisieren, wenn dies wirklich notwendig ist.

Hinweis
Die Methode setVoltage ändert für die Dauer des Aufrufs die I2C-Busgeschwindigkeit von 100 kHz auf 400 kHz, um die Datenübertragung zu beschleunigen. Wenn das Modul am gleichen I2C-Bus mit Geräten verwendet wird, die dies nicht unterstützen, kann über den optionalen dritten Parameter der Methode setVoltage eine Busgeschwindigkeit von 100 kHz erzwungen werden:
dac.setVoltage(value, writeEEPROM, 100000)

Signalerzeugung

Als einfaches Beispiel zur Signalerzeugung werden wir eine Sägezahnwelle, wie sie in der Abbildung unten gezeigt wird, erzeugen. Der Einfachheit halber werden wir keine Ausgabefrequenz festlegen. Sägezahnsignal

Unser erster Schritt besteht darin, das MCP4725-Modul mit dem Arduino zu verbinden. Die Verkabelung ist sehr einfach. Verbinde VCC und GND mit 5V und GND am Arduino Uno und schließe die I2C-Daten- und Taktleitungen SDA und SCL an die entsprechend beschrifteten Pins des Arduino an. Das erzeugte Signal steht auf dem OUT-Pin zur Verfügung. Dieses Modul verfügt außerdem über einen zusätzlichen GND-Pin, der die Verdrahtung vereinfacht. Um das ausgegebene Signal zu visualisieren, können wir einfach OUT und GND an ein Oszilloskop anschließen. Nicht alle MCP4725-Module haben diesen zusätzlichen GND-Pin. Wenn deins ihn nicht hat, kannst du stattdessen einen der GND-Pins des Arduino verwenden. Wenn du kein Oszilloskop hast, kannst du stattdessen den Ausgang mit einem Multimeter verbinden und die Frequenz des Sägezahnsignals reduzieren, indem du eine Verzögerung nach dem setVoltage-Aufruf hinzufügst. Eine ausreichend lange Verzögerung ermöglicht es dir, die Spannungsänderungen mit einem Multimeter zu verfolgen. Verbinden des MCP4725 mit dem Arduino

Der Code ist recht einfach, da wir nur die Spannung erhöhen müssen, bis wir das Maximum erreichen, um dann wieder bei 0 V zu beginnen. Dazu verwenden wir einfach eine for-Schleife mit einem Zähler, in der wir bei jeder Iteration den Zählerwert an den DAC senden. Der Zähler wird um eins erhöht, bis wir den Maximalwert des DACs von 4095 erreichen.

Im Code sieht das Ganze dann folgendermaßen aus:

#include <Adafruit_MCP4725.h>

const int I2C_ADDR = 0x60;

Adafruit_MCP4725 dac;

void setup() {
  dac.begin(I2C_ADDR);
}

void loop() {
  // Generate a sawtooth wave
  for(int i = 0; i < 4096; i++) {
    dac.setVoltage(i, false);
  }
}

Sobald der Code auf den Arduino hochgeladen ist, beginnt dieser, eine Sägezahnwelle zu erzeugen. Es dauert eine ganze Weile, um alle 4096 Schritte zu durchlaufen und jeden Wert an den DAC zu senden. Ein voller Zyklus dauert etwa 650 ms oder anders ausgedrückt, wir erhalten ein Signal mit einer Frequenz von etwa 1,5 Hz. Wenn wir eine höhere Frequenz verwenden wollten, müssten wir einige Ausgabewerte überspringen. Für 3 Hz könnten wir z. B. den Zähler in jeder Iteration um 2 inkrementieren.

Es gäbe noch viel mehr über das Thema Signalerzeugung zu sagen. Insbesondere, wenn das Ziel ist, ein Signal mit einer bestimmten Frequenz zu erzeugen. Für den Rahmen dieses Tutorials möchte ich das Beispiel aber so einfach wie möglich halten.

Hinweis
Wenn du ein fortgeschritteneres Beispiel zur Signalerzeugung sehen möchtest, kannst du einen Blick auf ein Beispiel zur Erzeugung von Tönen mit dem MCP4725 werfen, das ich auf GitHub veröffentlicht habe. Es verwendet den MCP4725, um eine kleine Melodie zu spielen. Dazu werden Sinuswellen mit den gewünschten Frequenzen erzeugt. Der Beispielcode passt dabei automatisch die Anzahl der Schritte pro Periode an die gewählte Frequenz an.

Vorheriger Beitrag Nächster Beitrag