MCP4725 12 bit DAC and SZBK07 DC-DC converter
In this video I show you how I utilize the MCP4725 12 bit digital to analog converter. This is a very nice circuit which allows me to control the SZBK07 DC-DC converter on a very fine scale. In this demonstration I use the DAC to change the output voltage of the SZBK07 between ~0-20 V. The device behaves linear on the full scale. I am glad about this circuit because it allows me to replace the 8 bit MCP41100 and have a more precise temperature control in my digital thermostat for Peltier coolers.
Wiring diagram
Both the 16x2 LCD and the MCP4725 are connected to the microcontroller via i2C. One of the pins of the rotary encoder is connected to an interrupt pin (this is more important for Arduinos). The MCP4725 is connected to +5 V which also serves as a reference voltage, so it is a good idea to measure the real voltage of the +5 V rail if you want to calculate the output voltage precisely. The output of the MCP4725 is connected to a 10 kOhm resistor which then goes to the pin 2-3 of the CV potentiometer.
Arduino/STM32 source code
//Arduino SDA: A4, SCL: A5 //STM32 SDA: PB7, SCL: PB6 #include <Wire.h> //i2C #define MCP4725 0x60 //address of device after finding it with the i2C scanner //16x2 LCD #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); bool writeValueToDAC = false; // can we update the DAC? float outputVoltage; // calculated value of the Vout float VREF = 4.869; // The measured 5 V rail voltage value byte buffer[3]; //buffer for the values to be written on the DAC int bitValue = 0; //value of the DAC bit; [0-4095] //Defining pins //For Arduino, you can choose pin 2 or pin 3 for interrupts const int RotaryCLK = PB3; //CLK pin on the rotary encoder const int RotaryDT = PB4; //DT pin on the rotary encoder //Statuses int CLKNow; int CLKPrevious; int DTNow; int DTPrevious; // Time float TimeNow1; float TimeNow2; void setup() { Serial.begin(9600); //Start the serial Wire.begin(); //Start the i2C //------------------------------------------------------ lcd.begin(); // initialize the lcd lcd.backlight(); //------------------------------------------------------ lcd.setCursor(0,0); //Defining positon to write from first row,first column . lcd.print("MCP4725 DAC"); lcd.setCursor(0,1); //Second row, first column lcd.print("Rotary encoder"); //You can write 16 Characters per line . delay(3000); //wait 3 sec //------------------------------------------------------ //Rotary encoder pins (CLK, DT) pinMode(RotaryCLK, INPUT_PULLUP); pinMode(RotaryDT, INPUT_PULLUP); //Store states CLKPrevious = digitalRead(RotaryCLK); DTPrevious = digitalRead(RotaryDT); attachInterrupt(digitalPinToInterrupt(RotaryCLK), rotate, CHANGE); TimeNow1 = millis(); //Start time lcd.clear(); //Clean startup message writeValueToDAC = true; //Allow the value to be refreshed bitValue = 0; // Initial value (0: max voltage is the starting value, 4095: min voltage is the starting value) } void loop() { TimeNow2 = millis(); if(TimeNow2 - TimeNow1 > 200) //update the LCD at each 200 ms { printLCD(); TimeNow1 = millis(); } writeDAC(); } void rotate() { CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin // If last and current state of CLK are different, then a pulse occurred if (CLKNow != CLKPrevious && CLKNow == 1) { // If the DT state is different than the CLK state then if (digitalRead(RotaryDT) != CLKNow) { if(bitValue < 4095) { bitValue++; } else { // Don't go beyond the value } writeValueToDAC = true; } else { if(bitValue > 0) { bitValue--; } else { // Don't go below the value } writeValueToDAC = true; } } CLKPrevious = CLKNow; // Store last CLK state outputVoltage = (VREF * bitValue)/4096; // updating the calculated voltage value } void printLCD() { lcd.setCursor(0,0); // 1st line, 1st block lcd.print("Value: "); lcd.setCursor(7,0); // 1st line, 8th block lcd.print(" "); lcd.setCursor(7,0); lcd.print(bitValue); //Print the value of the rotary encoder lcd.setCursor(0,1); // 2nd line, 1st block lcd.print("Voltage: "); lcd.setCursor(10,1); // 2nd line, 11th block lcd.print(" "); lcd.setCursor(10,1); lcd.print(outputVoltage,4); //Print the nominal voltage; 4 decimals } void writeDAC() { if(writeValueToDAC == true) { //This function sends the value to the DAC Serial.println(outputVoltage,4); //print the calculated voltage up to 4 digits. buffer[0] = 0b01000000; //Sets the buffer0 with control byte (010-Sets in Write mode) /* The buffer is filled up from the left to the right: * [D0 | ] - [D1D0 | ] - [D2D1D0 | ] ... [D7D6D5D4|D3D2D1D0] * This is not OK, so we shit to the right by four bits ( >> 4), so the buffer becomes: * [D11D10D9D8|D7D6D5D4] - This is OK. * * Then we do similar with the buffer[2]. We have the following array in the beginning: * [D7D6D5D4|D3D2D1D0] - but in buffer[2] we have to store the last 4 digits of the binary number * Therefore, we shift the number to the left (<< 4). The result is the following: * [D3D2D1D0|xxxx] * Final result: [D11D10D9D8|D7D6D5D4][D3D2D1D0|xxxx] * See the datasheet Figure 6-2 and the last subfigure in it. */ buffer[1] = bitValue >> 4; // D4 - D11 part buffer[2] = bitValue << 4; // D3 - D0 part Wire.beginTransmission(MCP4725); //We can write MCP4725 because of the definition in the beginning of the code Wire.write(buffer[0]); //C2 = 0, C1 = 1, C0 = 0, rest: 00000. Wire.write(buffer[1]); //Sends the first byte Wire.write(buffer[2]); //Sends the second byte Wire.endTransmission(); //actually sending the data to the DAC } writeValueToDAC = false; }
Voltage vs. bit value chart
This chart shows the measured output voltage of the SZBK07 as a function of the bit value applied to the MCP4725 DAC (red dots). The black dots show the measured voltage on the output of the MCP4725 DAC vs the applied but value. Both graphs are fitted with a linear function (dashed lines) and they show a very nice fit which suggests that the behavior of both devices is reasonably linear.