Gängige Verfahren zur Digital-Analog-Wandlung

Seite 4: DAC-ICs

Inhaltsverzeichnis

Wem der Aufwand mit den vielen Widerständen zu viel ist, kann aus einem reichhaltigen Angebot an DAC-ICs auswählen.

Im Inneren von DAC-ICs verbirgt sich wiederum nichts anderes als ein R2R-Netzwerk, das allerdings hochpräzise, lasergetrimmte Widerstände (durch laserstrahlinduzierte Materialveränderungen) aufweist. Je nach Wunsch gibt es ICs mit 8 Bit, 10 Bit oder 12 Bit Auflösung, sowie mit einem oder mehreren Kanälen. Ebenso enthalten die meisten ICs bereits einen Operationsverstärker.

Der entscheidende Unterschied bei modernen ICs liegt in der Ansteuerung der ICs: Je nach AusfĂĽhrung erfolgt diese entweder parallel ĂĽber eine Schaltlogik, seriell ĂĽber integrierte Schieberegister oder ĂĽber serielle Busse wie I2C oder SPI.

Parallel angesteuerte ICs wie der TLC7524 oder der DAC0800 punkten durch ein sehr genaues R2R-Netzwerk und sehr hohe Geschwindigkeit. Je nachdem wie sie beschaltet werden, können sie sowohl zur Spannungs- als auch zur Stromsteuerung eingesetzt werden. Sie belegen jedoch immer noch sehr viele Pins des Mikrocontrollers respektive des Arduinos.

Der TLC7524 wird parallel mit Daten versorgt. An der grĂĽnen Leitung rechts unten im Bild liegt das analoge Ausgangssignal an.

Serielle ICs wie der MCP4921 oder der TLV5618 benötigen hingegen nur noch 3 Pins (SPI), der über I2C angesteuerte PCF8591 sogar nur 2 Pins.

Der 2-Kanal-12-Bit-DAC MCP4922

Damit ein digitaler Wert in ein analoges Signal umgewandelt wird, erwarten die meisten seriellen ICs die Ăśbermittlung von 2 Bytes, die den digitalen Stellwert und das Kommando fĂĽr den Chip enthalten.

Beim MCP4922 teilen sich die 2 Bytes in 12 Bits fĂĽr den Wert und 4 Bits fĂĽr Chip-Anweisungen auf. Dabei entscheidet Bit 15 (A/B), welcher DAC-Kanal (Ausgang) den Wert ausgeben soll, Bit 14 (BUF) ob der Wert in den Zwischenspeicher geschrieben werden soll, Bit 13 (Output Gain Selection), ob die volle oder die halbe Spannung als Referenzspannung dient und Bit 12 (SHDN), ob der Ausgang nun aktiv oder inaktiv sein soll.

Der DAC MCP4921 an einem Arduino Nano. Er besitzt einen DAC-Kanal mit einer Auflösung von 12 Bit. Die Ansteuerung auf dem Bild erfolgt per Hardware SPI. Die gelbe Leitung rechts unten im Bild ist der analoge Ausgang.

Zur Übertragung wird zuerst der CS-Pin auf LOW gesetzt (CS, Chip Select; schaltet den IC quasi an), anschließend werden die 16 Bit seriell von links nach rechts (MSBFIRST) übertragen und anschließend der CS-Pin wieder auf HIGH gesetzt. Listing MCP4921-ShiftOut.ino zeigt, wie das funktioniert. Zum Übersetzen muss man zusätzlich SPI.ino in die Arduino-IDE laden, da dort weitere Funktionen definiert sind. Übrigens sind alle Codebeispiele zu diesem Artikel (Download) verfügbar.

MCP-4921-Hardware-SPI.ino

 1 #define SLAVESELECT 10 // CS
 2 #define DATAOUT     11 // DIN
 3 #define SPICLOCK    13 // SCLK 
 4 
 5 
 6 void setup() {
 7   pinMode(DATAOUT, OUTPUT);
 8   pinMode(SPICLOCK,OUTPUT);
 9   pinMode(SLAVESELECT,OUTPUT);
10   setup_hardware_spi();
11 }
12 
13 void loop() { 
14   for (int i = 0 ; i < 4096 ; i += 16)
15   {
16     SetVoltage(i);
17   }
18 }

SPI.ino

 1 void setup_hardware_spi(void)
 2 {
 3      byte clr;
 4   digitalWrite(SLAVESELECT,HIGH); //disable device
 5   SPCR = (1<SPE)|(1<MSTR)|(1<CPHA);
 6   clr=SPSR;
 7   clr=SPDR;
 8   SPSR |= _BV(SPI2X);               // Letztes Byte zuerst senden 
 9 }
10 
11 char spi_transfer(volatile char data)
12 {
13   SPDR = data; // Start the transmission
14   while (!(SPSR & (1<SPIF))) {};// Wait the end of the transmission
15 }
16 
17 void SetVoltage(short Voltage)
18 {
19   Voltage = 24576 + 2*Voltage ;  //24576 = '0110000000000000'
20   digitalWrite(SLAVESELECT,LOW);
21     spi_transfer( highByte(Voltage) );
22     spi_transfer( lowByte(Voltage) );
23   digitalWrite(SLAVESELECT,HIGH);
24 }

Der Vorteil von DAC-ICs liegt in ihrer hohen Genauigkeit und dies sogar bei einer Auflösung von 12 Bit (Wertebereich von 0 bis 4096). Außerdem belegen DAC-Chips lediglich 3 Mikrocontrollerpins, I2C Konverter sogar nur 2 Pins.

Der DAC MCP4922 an einem Arduino Nano. Er besitzt 2 DAC-Kanäle mit je 12 Bit Auflösung. Die Ansteuerung auf dem Bild erfolgt per ShiftOut. In Listing MCP4922-ShiftOut.ino ist die grundsätzliche Funktion zu sehen. An der grünen und der gelben Leitung (im Bild unten) liegt jeweils ein analoges Signal an.

Zur Ansteuerung muss jedoch ein etwas höherer Programmieraufwand betrieben werden. Durch die bitweise serielle Datenübertragung ist die Geschwindigkeit jedoch um ein Vielfaches langsamer als bei einem reinen R2R-Netzwerk.

MCP4922-ShiftOut.ino

 1 #define SLAVESELECT 9 // CS
 2 uint8_t dataPin =   8; // DIN
 3 #define clockPin    7 // SCLK 
 4 
 5 #define pause 5
 6 
 7 
 8 void setup() {
 9   pinMode(dataPin, OUTPUT);
10   pinMode(clockPin,OUTPUT);
11   pinMode(SLAVESELECT,OUTPUT);
12 }
13 
14 void loop() { 
15   for (int i = 0 ; i < 4096 ; i += 16)
16   {
17     SetVoltage(i);
18   }
19 }
20 
21 void SetVoltage(short Voltage)
22 {
23   Voltage = 28672 + Voltage ;  //24576 = '0110000000000000'
24   digitalWrite(SLAVESELECT,LOW);
25     shiftOut(dataPin, clockPin, MSBFIRST, (Voltage > 8)); 
26     shiftOut(dataPin, clockPin, MSBFIRST, Voltage); 
27 
28   digitalWrite(SLAVESELECT,HIGH);
29 }

Ein SMD vom Type PCF8591, der vier Analog-zu-digital-Kanäle und einen Digital-zu-analog-Kanal besitzt. Angesteuert wird er über das I2C-Protokoll. Ein Beispielprogramm ist in Listing PCF8591.ino zu finden. Zum Experimentieren sind auf diesem Bord bereits ein lichtempfindlicher Widerstand (LDR), ein temperaturabhängiger Widerstand (PTC) und ein Potentiometer aufgelötet. Wir kauften es bei Ebay für 3,50 Euro.

Den PCF8591 gibt es auch einzeln in einem DIP-16-Gehäuse.

Der PCF8591P wird mit I2C angesteuert. Die gelbe Leitung rechts unten ist der analoge Ausgang.

PCF8591-I2C.ino

 1 #include "Wire.h"
 2 #define PCF8591 (0x90 > 1) // I2C bus address
 3 
 4 void setup()
 5 {
 6  Wire.begin();
 7 }
 8 
 9 void loop()
10 {
11  for (int i = 0 ; i < 256 ; i++)
12  {
13   Wire.beginTransmission(PCF8591); // PCF8591 aufwecken
14   Wire.write(0x40);                // DAC einschalten (bin�r 1000000)
15   Wire.write(i);                   // Wert senden
16   Wire.endTransmission();          // end tranmission
17  }
18 }