Math's issue MCP4725

I’m trying to get an MCP4725 to set the voltage on a power supply which as an 0-20.00V output and at the moment it uses potentiometer’s to set the voltage and current, My idea is just to use one rotary encoder to set both and have a few memory buttons. Only working on the voltage side at the moment, Current will be looked at later once I’ve done the voltage side. The MCP4725 and the ADS1115 are working correctly.

The potentiometer gives a voltage reading of 1.255V (0V) to 4.985V (20.00V)to set the output voltage from 0-20.00V.

Example1 Dac value of 1893 gives a voltage of 2.1118 setting the output of the power supply to 5.013V and then I press the output on button to give the 5.01V output.

Example2 Dac value of 2632 gives a voltage of 2.942 setting the output of the power supply to 10.02V and then I press the output on button to give the 10.02V output.

What I’m trying to achieve is so when I turn the Rotary encoder instead of showing the dac value of 1893 (5.01V out)I’m trying to get the set value to display 5.00V so I know what the output voltage will be before I turn it on.

I’ve tried so many ways by using the Dac value, using the second channel on the ADC to read the dac output voltage I’ve got a little lost and may be over thinking it.

Is there away I could work this out ?
Here’s the code

#include <Wire.h>
#include <TimedAction.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7); //0x27 is the default address of the LCD with I2C bus module
#include <SPI.h>
#include <Encoder.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
Adafruit_MCP4725 dacB; // constructor
#include <Adafruit_ADS1015.h> //Include the libarary for 16Bit A/D converter
#define  VOLTS_CHAN0 0 //channel 1 value
#define  VOLTS_CHAN1 1 //chanel2 value
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
uint16_t err1; //ADC0 variable
uint16_t err2; //ADC1 variable
float Vmultiplier = 0.0001875F;  // used to convet readings this is calculated
float Vmultiplier1 = 0.0001875F; // used to convet readings this is calculated
float Vresults0; // Holds raw battery voltage value
float Vresults1; // Holds raw battery current value
float Voltage1 = 0.0;
float Voltage2 = 0.0;
const int pinBtnEncV = 8;
const int pinBtnEncC = 7;
int DAC8574_Ch2_Val = 0;
const int pinEncV1 = 2;
const int pinEncV2 = 3;
const int pinEncI1 = 6;
const int pinEncI2 = 9;
float r1 = 47000.0;
float r2 = 6200.0;
const int pinCSV = 10;
const int pinCSI = 18;
float Actual_volt = 0;
float Set_volt = 0;

int buttonPins[] = {
  pinBtnEncV, pinBtnEncC
int buttonReadings[1];
int lastButtonStates[] = {
int currentButtonStates[] = {
long lastDebounceTime[1];
long oldEncPositions[] = {
  -999, -999
long curEncPositions[] = {
  0, 0
long encoderValues[] = {
  0, 0
int DACSetSteps[] = {
  1, 1
int loopCounter = 0;

Encoder VEnc(pinEncV1, pinEncV2);
Encoder IEnc(pinEncI1, pinEncI2);
void TimerService01();
TimedAction Timedact01 = TimedAction(80, TimerService01); // mS
void TimerService02();
TimedAction Timedact02 = TimedAction(250, TimerService02); // mS
void getCurrentEncPositions()
  curEncPositions[0] =;
  curEncPositions[1] =;

  for (int i = 0 ; i < 2 ; i++) {
    if (curEncPositions[i] != oldEncPositions[i])
      if (curEncPositions[i] > oldEncPositions[i]) {
        encoderValues[i] += DACSetSteps[i];

        if (encoderValues[i] > 4095) encoderValues[i] = 4095;
      else {
        encoderValues[i] -= DACSetSteps[i];

        if (encoderValues[i] < 0) encoderValues[i] = 0;


      oldEncPositions[i] = curEncPositions[i];

void setup() {
  for (int V = 0 ; V < 2 ; V++) {
    pinMode(buttonPins[V], INPUT);
    digitalWrite(buttonPins[V], HIGH);
  dacB.begin(0x62); // The I2C Address: Run the I2C Scanner if you're not sure
  DAC8574_Ch2_Val = 1763;
  dacB.setVoltage(DAC8574_Ch2_Val, false);
  lcd.begin(20, 4);
  lcd.setBacklightPin(3, POSITIVE);                        // BL, BL_POL
  lcd.setBacklight(HIGH);                                  //set LCD backlight on
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  ads.begin();  //start the 16bit A/D converter
  pinMode(pinCSV, OUTPUT);
  digitalWrite(pinCSV, HIGH);
  pinMode(pinCSI, OUTPUT);
  digitalWrite(pinCSI, HIGH);

void loop() {
  // check the dac button with debonce and double the gain
  for (int i = 0; i < 2; i++) {
    buttonReadings[i] = digitalRead(buttonPins[i]);
    if (buttonReadings[i] != lastButtonStates[i]) lastDebounceTime[i] = millis();
    if (millis() - lastDebounceTime[i] > 50) {
      if (currentButtonStates[i] != buttonReadings[i]) {
        currentButtonStates[i] = buttonReadings[i];
        if (currentButtonStates[i] == LOW) {
          DACSetSteps[i] *= 10;
          if (DACSetSteps[i] > 100) DACSetSteps[i] = 1;

    lastButtonStates[i] = buttonReadings[i];
  DAC8574_Ch2_Val =  encoderValues[0];
  dacB.setVoltage(DAC8574_Ch2_Val, false);
void TimerService01() {
  //#  Read both ADC channels                                       #

  //Read BAttery volatage
  err1 = ads.readADC_SingleEnded(VOLTS_CHAN0)  ;   // Ch.0 (3) 16bit
  Voltage1 = err1 * Vmultiplier ; //conert to float
  Actual_volt = Voltage1 / (r2 / (r1 + r2)); //convert to real time reading
  err2 = ads.readADC_SingleEnded(VOLTS_CHAN1)  ;   // Ch.1 (3) 16bit
  Voltage2 = err2 * Vmultiplier1 ;// Convert to actual input v
  Voltage2 -= 0.811; //set the reading to zero but show a minius
  Set_volt = Voltage2 * 4.096; ///this is wherer I've tried differtn methods to set voltage to read saem as actual voltage

void TimerService02() {
  lcd.setCursor(0, 0);
  lcd.print("V Set = ");
  lcd.print(Set_volt, 2);
  lcd.print(" V");
  lcd.setCursor(0, 1);
  lcd.print("V ACT = ");
  if ( Actual_volt >= 6.5) {
    lcd.print(Actual_volt, 2);//DAC8574_Ch2_Val
  } else {
    lcd.print(Actual_volt, 3);//DAC8574_Ch2_Val
  lcd.setCursor(0, 2);
  lcd.print("D VAL = ");
  lcd.print("          ");
  lcd.setCursor(0, 3);
  lcd.print(Voltage2);//DAC8574_Ch2_Val DACSetSteps[i]
  lcd.print(" : ");
  lcd.print(err2);//display channel 1 raw value
  lcd.print("   ");

did you check if the encoder itself works like it should?

me personal made the experience that rotary-encoders with mechanical switches do not work properly with most of the encoder-libraries because detecting the values is done too "cheap".

You describe in detail what happens if you run your code.

Does the output-voltage value that gets displayed jump around

You could write a testprogram that does the following:

setting your DAC-variable that will be written to the MCP to a certain value
press a button so this value gets written to the DAC

measure the voltage of the DAC-output and measure the voltage of your power-supply
write down all three values in a line

press a button and this will increase the DAC-variable in a certain step
measure the voltage of the DAC-output and measure the voltage of your power-supply
write down all three values in a line

So you got a table that shows all relations
c++ has a function named map() which can transform almost any value-range to any other value-range.

This could be used for this.
Another idea is using a ADC and another relay. Your DAC is connected to the power-supply directly
and a ADC is connected to the direct output of your power-supply.
the relay connects the power-supply and can switch on/off a socket where your supplying wire is plugged in

This would enable to read the real voltage and still beeing able to adjust the value and if value is adjusted to
connect the voltage to the supplying-wire.

best regards Stefan

Thanks Stefan,
Yeah the encoder works really well, I used a test program first and no matter how fast I turned it, The value incremented by 1 and I did not see any miss counts.

The output voltage from the DAC and the Actual real voltage are stable reading on the display and multi-meter.

I did look at using another relay so that I could use the output set voltage set mode and show but the only trouble that way the set voltage will drop when reading the actual voltage.

I will add some serial output and button press to capture all the values, I have tried the map function using the dac value and adc value but the reading never matched the actual voltage compared to the set voltage

I did look at using another relay so that I could use the output set voltage set mode and show
but the only trouble that way the set voltage will drop when reading the actual voltage.

I'm not sure if a understand this right. setvoltage means the outüutvoltage of the DAC or the voltage-output of your power-supply?

If the voltage-output of your power-supply drops when you measure the voltage with an ADC of the microcontroller there would be something badly wrong with the measuring circuit or your adjustable power-supply is very very bad.

Please describe very precise which voltages did you measure in which way. If the correlation between DAC-outputvoltage
and power-supply-outputvoltage is linear two measureing points one at the lower end one at the upper end would be enough.

best regards Stefan

I will try and explain better,
The set voltage is what I'd like to display before the actual output voltage will be once the set voltage is set to the desired voltage required then I can turn the output relay on to give the output voltage at the terminals.
So say I want 13.84V output voltage on the terminals before any voltage gets there I'd like it to display the set voltage on the display so once I can see that the voltage will be 13.84V then turn the output relay on and see the actual voltage is 13.84V.

What I meant by using a channel on the ADS1115 to measure the set voltage before I turn the output relay on if the voltage dropped on the output so would the set point voltage would drop which is what I don't want to happen, I want this to remain set until I adjust the output voltage. I mean by the output voltage dropping like it does when you set the output to 13.84V to charge a battery then turn the output to start charging the battery(at constant current limited) and it drops to what the battery voltage is until it's fully charged and reaches 13.84V, So I if I used this method the set voltage would read the real time voltage.

The dac part is working perfectly and readings are stable from the Dac so is the output from the power supply. The trouble I'm facing is working out how to get the set voltage to display what the actual voltage will be.

I've tried many ways to get them to match, I do at one set point but then when I adjust the set voltage higher than the maths that I thought I'd worked out are different to the actual output voltage is

Hopefully you will understand more