Gängige Verfahren zur Digital-Analog-Wandlung
Seite 4: DAC-ICs
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.
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.
Umwandlung in analoges Signal
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.
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.
Ansteuerung
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 }
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 }