Microchip‘s MCP4821/MCP4822 is a low budget 12-bit digital-to-analog converter. MCP4821 is the single channel version whereas MCP4822 has two channels that can be latched simultaneously. Both chips have internal band gap references and can be controlled via SPI.
Since MCP4821/MCP4822 has only a single write command register, it is extremely easy to use with MCUs that support SPI communications. The following code shows how to use this chip in Arduino:
#include <SPI.h> const int PIN_CS = 10; const int GAIN_1 = 0x1; const int GAIN_2 = 0x0; void setup() { pinMode(PIN_CS, OUTPUT); SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV2); } //assuming single channel, gain=2 void setOutput(unsigned int val) { byte lowByte = val & 0xff; byte highByte = ((val >> 8) & 0xff) | 0x10; PORTB &= 0xfb; SPI.transfer(highByte); SPI.transfer(lowByte); PORTB |= 0x4; } void setOutput(byte channel, byte gain, byte shutdown, unsigned int val) { byte lowByte = val & 0xff; byte highByte = ((val >> 8) & 0xff) | channel << 7 | gain << 5 | shutdown << 4; PORTB &= 0xfb; SPI.transfer(highByte); SPI.transfer(lowByte); PORTB |= 0x4; } void loop() { //high-res triangular wave for (int i=0; i < 4096; i+=32) { //setOutput(0, GAIN_2, 1, i); setOutput(i); } }
There are two overloaded setOutput methods. Both methods can be used with either MCP4821 or MCP4822. The first method assumes the use of a single channel and a gain a 2. And the second method gives you more flexibility.
Note that the chip select pin (pin 10) is toggled using PORTB directly, this is to avoid the excessive overhead associated with the digitalWrite command, especially for high speed operations (e.g. 100kHz and above).