- Audio (2)
- Codes Scratches (4)
- Elektronika (23)
- Inteligentny dom (1)
- IT (9)
- Mikrokontrolery / Arduino (6)
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.
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.
Bardzo fajny artykuł. Dzięki!
@Borys dzięki 😉