Budujemy „cyfrowy zasilacz” cz. 3 – przetwornik DAC oparty na R-2R

Lepiej późno niż wcale… Jak obiecałem, tak piszę. Tym razem rzecz będzie o przetworniku cyfrowo-analogowym opartym na drabince rezystorowej (DAC na R-2R). No to do roboty, bez zbędnych wstępów…

Na początek odrobina teorii…

Zacznijmy od odrobiny teorii. Czym jest drabinka R-2R? Drabinka R-2R, jak sama nazwa wskazuje, to takie połączenie wielu rezystorów tej samej wartości, aby tworzyły one „drabinkę”, w której każdy kolejny szczebel ma wartość 2xR w stosunku do każdego kolejnego pionowego elementu. Poniżej widzimy, jak taka drabinka wygląda teoretycznie.

Bity od A0 do An są sterowane z wyjść bramek logicznych (np. wyjścia mikrokontrolera lub rejestru przesuwnego). Czyli mogą na nich występować dwa stany – niski i wysoki, który będzie odpowiednio na potencjale GND lub na potencjale napięcia zasilania danego układu – Vcc. (Oczywiście stan wysoki może być na innym poziomie, jednak w większości przypadków, gdy drabinka będzie podłączona bezpośrednio do wyjść np. mikrokontrolera, to właśnie w stanie wysokim będzie się pojawiało na wyjściach napięcie zasilania).
Jak już pewnie zauważyłeś/łaś, w dużym uproszczeniu mamy tu do czynienia z rezystorowym dzielnikiem napięcia. Spróbujmy sobie zatem obliczyć, jakie napięcie wyjściowe będziemy mieli na wyjściu takiego DAC’a w przypadku, gdy nasza drabinka będzie miała 8 strzebli (8bitów), a poziom wysoki każdego z nich będzie równy 5V.

Najpierw ogólnie:

Vout = Vref x VAL / 2^N

Gdzie:
N – liczba bitów (w naszym przykładzie będzie to 8)

VAL – wartość podana na wejścia A0…An (dla N = 8, będzie to wartość z przedziału 00000000 do 11111111)
Vref – Napięcie referencyjne, czyli to, które reprezentuje stan wysoki układu. W naszym przykładzie będzie to 5V (dla typowej bramki CMOS będzie to 3.3V).

Weźmy teraz sobie konkretną wartość, np. 128, czyli binarnie będzie to 10000000 (2^8). Podstawiając do powyższego wzoru:

Vout = 5V x 128 / 2^8
Vout = 2.5V

To teraz policzmy sobie, jaka będzie rozdzielczość takiej drabinki…

Vout = 5V x 1 / 2^8
Vout ~= 0.02V

Czyli pojedynczy krok będzie zwiększał napięcie dokładnie o ok. 0.02V, co daje 255 kroków, aby osiągnąć napięcie 5V, czyli wszystko się zgadza! (Największa możliwa do zapisania wartość na 8bitach to właśnie 255, czyli mamy 255 bitowych kombinacji, czyli 255 kroków w naszym przetworniku).

Przejdźmy do praktyki…

Spróbuję teraz zademonstrować, jak w praktyce możemy wykorzystać taką drabinkę. W tym celu zbudujmy sobie prosty 16botowy DAC oparty na drabince R-2R.

Zbudujmy sobie układ jak z poniższego schematu…

U mnie to wyglądało m/w tak:

O tym, jak działa rejestr 74HC595, pisałem już w tym miejscu, więc nie będę przytaczał tego samego tekstu tutaj. Jedyna różnica między naszym układem a tym przedstawionym w linku powyżej to drabinka podłączona do wyjść Q0…Q7 układów U1 oraz U2, a także połączenie ich kaskadowo (z ang. daisy chaining), dzięki czemu możemy „wlać” w taką kaskadę wielokrotność liczby bitów każdej z nich. W tym przypadku dokładnie 16 bitów. Działa to w ten sposób, że gdy pierwszy z układów przepełni się, wówczas zaczyna „przelewać” kolejne bity do następnego układu.

Ok! Mamy już przetwornik, podłączmy go zatem do jakiegoś mikrokontrolera i spróbujmy wysłać na niego jakąś wartość. Żeby było prosto i przyjemnie, użyjmy do tego celu Arduino… które podłączymy jak na rysunku powyżej (wykorzystamy piny DIGITAL8, DIGITAL12, DIGITAL~11)

Jak już pewnie zauważyłeś/łaś, jest to takie same podłączenie jak w przypadku pozytywki z linku powyżej. Ba! Program sterujący będzie też bardzo podobny, z tą tylko różnicą, że będziemy wysyłać 16 bitów, a nie 8. Będzie to wyglądało m/w tak:


//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
//Pin connected to DS of 74HC595
int dataPin = 11;
//Pin connected to UP button
int btnA = 2;
//Pin connected to DOWN button
int btnB = 3;

//int in arduino are 16bit length
int dataToSend = 0;


void setData(int data)
{
  byte dataA = 0;
  byte dataB = 0;
  
  //split 16bit var into two 8bit
  dataA = data & 0xff; 
  dataB = data >> 8;
  
  //ground latchPin and hold low for as long as you are transmitting
  digitalWrite(latchPin, LOW);
  //move ‘em out
  shiftOut(dataPin, clockPin, MSBFIRST, dataA);
  shiftOut(dataPin, clockPin, MSBFIRST, dataB);
  //return the latch pin high to signal chip that it
  //no longer needs to listen for information
  digitalWrite(latchPin, HIGH);
}

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(btnA, INPUT);
  pinMode(btnB, INPUT);
}

void loop() {

  if(digitalRead(btnA)==HIGH && dataToSend<32768)
  {
    dataToSend++;
    setData(dataToSend);
  }
  else if(digitalRead(btnB)==HIGH && dataToSend>0)
  {
    dataToSend--;
    setData(dataToSend);
  }
    
}

No i mamy działający 16bitowy DAC za parę groszy 😉

Problemy, ograniczenia, wady…

Tak, tak… To wszystko było zbyt piękne i gdyby nie było jakiegoś haczyka, to pewnie producenci specjalizowanych układów DAC by zbankrutowali… I rzeczywiście haczykiem jest precyzja, a dokładniej precyzja, jaką muszą się charakteryzować rezystory, z których składamy taką drabinkę, aby napięcia wyjściowe na niej wygenerowane choć trochę odpowiadały tym, które sobie wyliczyliśmy i których oczekujemy na wyjściu. Przykładowo dla 8bitowej drabinki rezystory muszą mieć dokładność większą niż 0.4%, co już stanowi spory problem, zarówno finansowy, jak i w realizacji praktycznej układu. Można oczywiście taką drabinkę próbować kompensować programowo, jednak jest to rozwiązanie mało eleganckie, które osobiście odradzam jako rozwiązanie w poważnym projekcie. Nie mniej jednak zachęcam do eksperymentowania z R-2R, które może się przydać wszędzie tam, gdzie potrzebna jest mała rozdzielczość lub zadowalający jest nastaw z grubsza.

3 odpowiedzi na “Budujemy „cyfrowy zasilacz” cz. 3 – przetwornik DAC oparty na R-2R”

  1. msk pisze:

    A gdyby tak…

    Ustawiać napięcie z grubsza za pomocą R-2R bo jest szybko po czym dodać do tego PWM?

    “It is possible to combine the idea of the PWM and the R2R-ladder. In this design we will use a 7bit R2R-ladder combined with a 5bit PWM signal. With a 8MHz system clock and 5bit resolution we will get a 250KHz signal. 250KHz can even be converted with small capacitors into a DC signal.”

    http://tuxgraphics.org/electronics/201005/bench-power-supply-v3.shtml

    Pełny schemat pow. zasilacza jest dostępny chyba dopiero po zakupie całego kit-u. Szkoda.

  2. Borys pisze:

    Bardzo fajny artykuł. Dzięki!

  3. leniwiec pisze:

    @Borys dzięki 😉

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *