With microcontrollers, it is often a good idea to use a 595 Shift Register instead of direct ports not only to save ports but also because the 595 does a good job .
595 shift register can both source current when on a HIGH state and sink current when LOW. This is essential to create a more linear response and achieve monotonicity of output.
uC's like the ATMega328/Arduino Uno .do a good job at using a whole 8 bit port, as they can sink current as well, but that is reduced with the 3.3 V generation of chips ( average 20 mA, as opposed to 40 mA (milliamps) of current with an Arduino Uno).
The simplest textbook example of a Resistor-ladder DAC is a R/2nR DAC, also known as Binary Weighted DAC. This architecture is the most limited as well, and not inherently monotonic. Also to note that fact that impedance changes with input.
The method uses a sequence of ratios R, 2R, 4R, 8R. 16R , etc (R/16, R/8, R/4, R/2 and R for 5 bits is the usual way to refer to it).
And the difficulty of matching the ratios with resistors is one of the main reasons why its used mainly for small count bit solutions .
In theory, it looks to keep its monotonicity, but in reality tends to be somewhat different.
So the theoretical schematic would be as in the next example ( check live interactive simulator circuit on link; Circuit starts representing decimal 35 / binary 100011- Use the switches, most significant bit is on the left)
A good point to understand how it all works as far as circuit goes, would be TTL Logic basics( where each pin is the equivalent of two transistors and can both sink and source current..
*during some tests, i was able to derive 24 values out of 3 bits, with a log-like response using a theoretical tristate circuit. While this worked on paper, im still to try its concept :) Maybe i just rediscovered someone else's wheel !
Let this be a taster, while i build a 16 bit DAC ( a bit oversized if we compare it with a 12 bit MCP4725, for example :)
I now know the real meaning behind the expression " Resistor's graveyard" eh eh