
Resistor DACs
There are a several techniques that are used.
One consists of 8 resistors, with each resistor twice the resistance of the
previous one. You might for example connect them to port B on an AVR as
shown below. The lowest resistance goes on the most significant bit. The
highest resistance goes to the least significant bit. Connect each port
pin to the appropriate resistor. Then connect the other side of all 8
resistors together. This common line becomes your output:
PB7 ------ R ------+
PB6 ----- 2R ------+
PB5 ----- 4R ------+
PB4 ----- 8R ------+
PB3 ---- 16R ------+----- Vout
PB2 ---- 32R ------+
PB1 ---- 64R ------+
PB0 --- 128R ------+
The overall output resistance is about R/2 ohms. Vout = (N / 255) * Vcc,
where N is the number you output to port B. For the best accuracy the
lowest value resistors should be accurate. The higher values are not so
important.
You will have three constraints on your choice of R. First, the first few
values should maintain the 2:1 ratio as closely as possible. Second, start
with R low enough so that the 128R resistor isn't too big to find (less
that 10M for 128R). And third, start with R high enough so that the output
pins - particularly PB7 - are not loaded down too much.
For example you might choose the following series: 10.0K 1%, 20.0K 1%,
40.2K 1%, 80.6K 1%, 160K 5%, 330K 5%, 620K 5%, 1.3M 10%. For +/- 1 LSB
accuracy, you need to select the 10.0K and the 20.0K resistors to be better
than 1% tolerance.
A more common approach is to use 16 resistors in an R - 2R resistance
ladder. This uses twice as many resistors but it has the advantage of
using only two different resistor values instead of 8 different values.
Thanks to Paul Ostby for this.
R-2R ladder:
20k 10k 10k 10k 10k 10k 10k 10k
Gnd o-VVVV-+-VVVV-+-VVVV-+-VVVV-+-VVVV-+-VVVV-+-VVVV-+-VVVV-+---o Out
| | | | | | | |
> > > > > > > >
> 20k > 20k > 20k > 20k > 20k > 20k > 20k > 20k
> > > > > > > >
| | | | | | | |
D0 o D1 o D2 o D3 o D4 o D5 o D6 o D7 o
Output impedance is 10k.
The port you would like to use for the 8 DAC bits also happens to be the comparator
inputs. OK, let's just diddle a bit...
Let's use PORTB, 2 to 7 as the high six bits of the ADC, and PORTD 0
and 1 as the low two bits. I shall assume that those bits are set as
outputs, and PORTB 0 and 1 as inputs. PORTB,0 is the analogue input and
PORTB,1 is connected to the R-2R network.
.def adcval =r16
.macro ripple
; four instructions, five or six cycles
nop
sbis ACSR,ACO ; If lower,
cbi PORTB,#0 ; clear that bit
sbi PORTB,#1 ; set next anyway
.endmacro
clr adcval
out ACSR,adcval
ldi adcval,$80
out PORTB,adcval
cbi PORTD,0
cbi PORTD,1 ; Initialised.
ripple 7,6
ripple 6,5
ripple 5,4
ripple 4,3
ripple 3,2
nop
sbis ACSR,ACO
cbi PORTB,2
sbi PORTD,1
in adcval,PORTB
sbis ACSR,ACO
cbi PORTD,1
sbi PORTD,0
andi adcval,$FC ; Mask off low bits
sbic ACSR,ACO ; If higher,
inc adcval ; Add one
sbic PORTD,1 ; Add in
ori adcval,2 ; bit 1
I count 39 instructions, and between 48 and 55 cycles which is
more than I bargained for but ... it could be worse!
Thanks to Paul Webster for this.