MCP4725 DAC Read Analog Voltage Value with Arduino Uno

Hello everyone,

I am currently working a MCP4725 tutorial project.

Link of the tutorial:

https://electronoobs.com/eng_arduino_tut173.php

The goal is to output analog voltage values through the MCP4725 and read it through one of the analog ports of the same arduino board.

I read threads about this topic, being stuck with 1023 readings.

Here's what I've tried so far to solve this issue.

I read about bad connections, so I poured more solder on some spots of the module which seemed to not have a very good connection.

I changed the spot the module was placed on the breadboard.

Changed the resolution from 9 to 12 in the code, did not work.

Tried uploading a different code with different analog signal.

Tried swapping the I2C connection spots on the arduino board.

I read the values with the multimeter and it's working perfectly with regards to the analog voltage. But for some reason the serial monitor keeps throwing 1023.

This is the code I used:

#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION    (9)

const int pinoAnalogo = A1;

void setup(void) {
  Serial.begin(9600);
  // MCP4725A1 address is 0x62 (default) 
  // MCP4725A1 address is 0x63 (ADDR pin tied to VCC) 
  // MCP4725A1 address is 0x60 (ADDR pin tied to GND) 
  dac.begin(0x60); //I have my ADDR pin connected to GND so address is 0x60
}

void loop(void) {      
  int valorAnalogico = analogRead(pinoAnalogo);
  dac.setVoltage((1*4095)/5, false);        //Set voltage to 1V
  Serial.println(valorAnalogico);
  delay(2000);
  dac.setVoltage((2*4095)/5, false);        //Set voltage to 2V
  Serial.println(valorAnalogico);
  delay(2000);
  dac.setVoltage((3*4095)/5, false);        //Set voltage to 3V
  Serial.println(valorAnalogico);
  delay(2000);
  dac.setVoltage((4*4095)/5, false);        //Set voltage to 4V
  Serial.println(valorAnalogico);
  delay(2000);
  dac.setVoltage(4095, false);              //Set voltage to 5V or (Vcc)
  Serial.println(valorAnalogico);
  delay(2000); 
}

Thank you if you've read this far.

Please post a wiring diagram (hand drawn with pencil and paper is preferred) and a closeup, focused photo of your soldering. Bad solder joints are likely to be a problem.

1 Like

Hi jremington,

Thanks for the reply.

Here are the photos.


I've tried with a second arduino but it disconnects after a while and the serial monitor blanks out. I tried different cables. Maybe the second board is faulty?

As the ADDR is not connected to GND I'm using it as 0x62 on the code. Is it correct?

To verify I2C addresses and communications, run the Arduino I2C address scanner program.

The schematic indicates that Arduino 2 has no common ground with the rest of the system, so the analog readings will be meaningless.

Hi @giovannelucas,

Your sketch tries to re-read the DAC data via analogRead()...

It reads the analog pin only once per loop(), exactly at the beginning of loop() ... Therefore the value of valorAnalogico stays the same all the time.

Either put a

 valorAnalogico = analogRead(pinoAnalogo);

in front of every Serial.println() in loop

or create a function like this

void setDAC(int v){
  int valorAnalogico = analogRead(pinoAnalogo);
  dac.setVoltage((v*4095)/5, false);        //Set voltage to 1V
  Serial.println(valorAnalogico);
  delay(2000);
}

and change loop to

void loop(){
  for (int i = 1;i <6;i++){
    setDAC(i);
  }
}

Not tested, just posted ...

P.S.: If you change the DAC resolution you will quite likely not see any change from analogRead() as this function provides only a resolution of 0 ... 1023 unless you use a controller with an ADC that has better resolution (e.g. ESP32 but then in the range of 0 ... 3.3VDC!).

So, I tried connecting the GND of Arduino 2 to GND of Arduino 1.

As well as updating the code @ec2021 suggested.

But I'm getting almost no change with regards to the readings. Here's a picture of the serial monitor.

image

Sorry, think it should work without the resistors. There must be another problem ...

Yes, you're right.

I'm having a hard time, with the IDE recognizing my second board.

It's probably faulty. Do you think I should be able to read the values with a spare ESP32 I have?

The easiest way to see the signal would be to test it with an osciloscope. I think I'll try to get acess to one.

But then you had to use some level shifter or a voltage divider to get from 5VDC to 3.3VDC ...

How about testing you Arduino board(s) and the MCP first?

  • Use a multimeter to check the output of the DAC.
  • Use a potentiometer with A0 to check if it behaves correctly.

Here is the sketch as I think it should work. To make sure that the address is correct I use the return value of dac.begin():

#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION    (9)

const int pinoAnalogo = A1;

void setup(void) {
  Serial.begin(9600);
  // MCP4725A1 address is 0x62 (default) 
  // MCP4725A1 address is 0x63 (ADDR pin tied to VCC) 
  // MCP4725A1 address is 0x60 (ADDR pin tied to GND) 
  if (!dac.begin(0x60)){  // (ADDR pin tied to GND) 
    Serial.println("DAC not found!");
    while(1);
  }
}

void loop(){
  for (int i = 1;i <6;i++){
    setDAC(i);
  }
}

void setDAC(int v){
  dac.setVoltage((v*4095)/5, false);        //Set voltage to v V
  delay(50);
  int valorAnalogico = 4*analogRead(pinoAnalogo);
  Serial.println(valorAnalogico);
  delay(2000);
}

So if you get the message "DAC not found!" you should check the address ...

OOPs there was a mistake in the code ... the dac voltage has to be set first and then - after a certain delay - we read the analog pin ....

So @ec2021, it works correctly with the multimeter. I can see voltage rise up and down along with the 2 seconds.

I should be able to connect the MCP level to 3V3 with the arduino, right?

Should that do with the level shift?

I had to make a change to the setDAC() function; we must set the voltage first of course, before we read the analog value ... May not make a big change but now it is correct.

Do you have a level shifter board? Like these
https://www.amazon.co.uk/SparkFun-Logic-Level-Converter-Bi-Directional/dp/B088FYQJYZ/ref=sr_1_12?keywords=3.3v+5v+logic+level+converter&qid=1705355022&sr=8-12

Just to read the DAC you can of course use a voltage divider
https://randomnerdtutorials.com/how-to-level-shift-5v-to-3-3v/

Thanks a lot @ec2021.

I see different numbers now. But trying to calculate I see some of them exceed 5V.

I'm doing Vout * 5 / 1023 to convert the received value back to the output analog voltage. is it correct?

This is the output I'm getting:

image

Did you use the code from post 10?

If yes: I did this change which you might have overlooked:

 int valorAnalogico = 4*analogRead(pinoAnalogo);

You can assume that 2048 relates to the 5VDC output. This is what LibreOffice Spreadsheet makes from it:

image

Not too bad, isn't it :wink:

So the formula is

  float voltage = 5.0/2048* valorAnalogico ;

I must admit that I have not idea at the moment how you received the value of 2048 now. Maybe you can post how you got these data, from the Arduino or from the the ESP32? Did you use level shifiting or resistors? Or ... ?

Thanks a lot @ec2021.

I'm taking it to the next level by building an ECG simulator.

However, there are negative voltage values. How can I translate negative voltage values to the DAC?

Please correct me if i'm wrong but there is the need for a dual power supply right?

This is the voltage list for 1s.

0,
0.00001023,
0.000019995,
0.00003627,
0.0000744,
0.000093,
0.0001116,
0.0001209,
0.0001023,
0.0000744,
0.0000372,
0,
-0.0000186,
-0.0000279,
-0.0000279,
-0.0000372,
-0.0000465,
-0.0000558,
-0.0000651,
-0.0000744,
-0.0000837,
-0.000093,
-0.0001116,
-0.0001302,
-0.0001488,
-0.0001767,
-0.0002232,
-0.0002604,
-0.000279,
-0.0002511,
-0.000093,
0.000465,
0.00186,
0.002046,
0.0016275,
0,
-0.000186,
-0.000372,
-0.0004185,
-0.0003255,
-0.000186,
-0.0001395,
-0.000093,
-0.0000465,
-0.0000186,
-0.0000093,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0.000009207,
0.0000186,
0.0000372,
0.0000465,
0.0000651,
0.0000837,
0.0001023,
0.0001209,
0.0001488,
0.0001953,
0.0002325,
0.0002511,
0.0002604,
0.0002418,
0.000186,
0.0001395,
0.000093,
0.0000558,
0.0000279,
0.0000186,
0.0000093,
0.0000093,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0

I was thinking of using something like this code, but there are only positive values.

Would the solution be to shift the voltage levels in equal quantities to bring it to the positive rail but keeping the curve shape?

I'll also need to multiply the csv file values by at least 1000 to bring it to volt range so the arduino can actually send it to the DAC. Right?

PS: I guess I'm not able to post the entire file. I showed just a few values.
I've simulated this csv file on LTSpice and the wave shape is goog but the voltage is too low for an arduino I think.

I tried a different code, but the serial plotter is very different from an ECG though.

Code:

#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION    (9)

const int pinoAnalogo = A0;

void setup(void) {
  Serial.begin(9600);
  // MCP4725A1 address is 0x62 (default) 
  // MCP4725A1 address is 0x63 (ADDR pin tied to VCC) 
  // MCP4725A1 address is 0x60 (ADDR pin tied to GND) 
  if (!dac.begin(0x60)){  // (ADDR pin tied to GND) 
    Serial.println("DAC not found!");
    while(1);
  }
}

const short  y_data[] = {
939, 940, 941, 942, 944, 945, 946, 947, 951, 956, 
962, 967, 973, 978, 983, 989, 994, 1000, 1005, 1015, 
1024, 1034, 1043, 1053, 1062, 1075, 1087, 1100, 1112, 1121, 
1126, 1131, 1136, 1141, 1146, 1151, 1156, 1164, 1172, 1179, 
1187, 1194, 1202, 1209, 1216, 1222, 1229, 1235, 1241, 1248, 
1254, 1260, 1264, 1268, 1271, 1275, 1279, 1283, 1287, 1286, 
1284, 1281, 1279, 1276, 1274, 1271, 1268, 1266, 1263, 1261, 
1258, 1256, 1253, 1251, 1246, 1242, 1237, 1232, 1227, 1222, 
1218, 1215, 1211, 1207, 1203, 1199, 1195, 1191, 1184, 1178, 
1171, 1165, 1159, 1152, 1146, 1141, 1136, 1130, 1125, 1120, 
1115, 1110, 1103, 1096, 1088, 1080, 1073, 1065, 1057, 1049, 
1040, 1030, 1021, 1012, 1004, 995, 987, 982, 978, 974, 
970, 966, 963, 959, 955, 952, 949, 945, 942, 939, 
938, 939, 940, 941, 943, 944, 945, 946, 946, 946, 
946, 946, 946, 946, 946, 947, 950, 952, 954, 956, 
958, 960, 962, 964, 965, 965, 965, 965, 965, 965, 
963, 960, 957, 954, 951, 947, 944, 941, 938, 932, 
926, 920, 913, 907, 901, 894, 885, 865, 820, 733, 
606, 555, 507, 632, 697, 752, 807, 896, 977, 1023, 
1069, 1127, 1237, 1347, 1457, 2085, 2246, 2474, 2549, 2595, 
2641, 2695, 3083, 3135, 3187, 3217, 3315, 3403, 3492, 3581, 
3804, 3847, 3890, 3798, 3443, 3453, 3297, 3053, 2819, 2810, 
2225, 2258, 1892, 1734, 1625, 998, 903, 355, 376, 203, 
30, 33, 61, 90, 119, 160, 238, 275, 292, 309, 
325, 343, 371, 399, 429, 484, 542, 602, 652, 703, 
758, 802, 838, 856, 875, 895, 917, 938, 967, 1016, 
1035, 1041, 1047, 1054, 1060, 1066, 1066, 1064, 1061, 1058, 
1056, 1053, 1051, 1048, 1046, 1043, 1041, 1038, 1035, 1033, 
1030, 1028, 1025, 1022, 1019, 1017, 1014, 1011, 1008, 1006, 
1003, 1001, 999, 998, 996, 994, 993, 991, 990, 988, 
986, 985, 983, 981, 978, 976, 973, 971, 968, 966, 
963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
964, 965, 966, 967, 968, 969, 970, 971, 972, 974, 
976, 978, 980, 983, 985, 987, 989, 991, 993, 995, 
997, 999, 1002, 1006, 1011, 1015, 1019, 1023, 1028, 1032, 
1036, 1040, 1045, 1050, 1055, 1059, 1064, 1069, 1076, 1082, 
1088, 1095, 1101, 1107, 1114, 1120, 1126, 1132, 1141, 1149, 
1158, 1166, 1173, 1178, 1183, 1188, 1193, 1198, 1203, 1208, 
1214, 1221, 1227, 1233, 1240, 1246, 1250, 1254, 1259, 1263, 
1269, 1278, 1286, 1294, 1303, 1309, 1315, 1322, 1328, 1334, 
1341, 1343, 1345, 1347, 1349, 1351, 1353, 1355, 1357, 1359, 
1359, 1359, 1359, 1359, 1358, 1356, 1354, 1352, 1350, 1347, 
1345, 1343, 1341, 1339, 1336, 1334, 1332, 1329, 1327, 1324, 
1322, 1320, 1317, 1315, 1312, 1307, 1301, 1294, 1288, 1281, 
1275, 1270, 1265, 1260, 1256, 1251, 1246, 1240, 1233, 1227, 
1221, 1214, 1208, 1201, 1194, 1186, 1178, 1170, 1162, 1154, 
1148, 1144, 1140, 1136, 1131, 1127, 1123, 1118, 1114, 1107, 
1099, 1090, 1082, 1074, 1069, 1064, 1058, 1053, 1048, 1043, 
1038, 1034, 1029, 1025, 1021, 1017, 1013, 1009, 1005, 1001, 
997, 994, 990, 991, 992, 994, 996, 997, 999, 998, 
997, 996, 995, 994, 993, 991, 990, 989, 989, 989, 
989, 989, 989, 989, 988, 986, 984, 983, 981, 980, 
982, 984, 986, 988, 990, 993, 995, 997, 999, 1002, 
1005, 1008, 1012};

const int data_size = sizeof(y_data);

void loop(){
  for (int i = 1;i < data_size;i++){
    setDAC(i);
    delay(10);
  }
}

void setDAC(int v){
  dac.setVoltage((v*4095)/5, false);        //Set voltage to v V
  int valorAnalogico = 4*analogRead(pinoAnalogo);
  Serial.println(valorAnalogico);
}

Here some information you might be interested in:

  • In the MCP4725 lib from Adafruit
    https://github.com/adafruit/Adafruit_MCP4725/blob/master/Adafruit_MCP4725.cpp
    there is no use of the #define DAC_RESOLUTION. That means that the MCP always works with 12 bit resolution (which explains why DAC_RESOLUTION (9) does not have any influence and the DAC works always with the values 0 ... 4095 = 2^12. The #define in the tutorial is completely misleading as it refers to the sinewave example of the adafruit MCP lib:
    image
    and is used there to select one of the lookup tables ...
  • To create symmetrical signals from positive DAC output you could use an OpAmp circuit with symmetrical power supply. This would be required if you have to stimulate a device that expects symmetrical input data ... Is this your intention? Or do you just want to create signals that look like an ECG for humans?
  • The reason why the output does not look like an ECG is that you try(!) to feed the plotter with a y_data signal
    but you are not setting the DAC to those values but to (i*4095)/5) .... which leads to a sawtooth signal:
    image

Try this:

#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
const int pinoAnalogo = A0;

void setup(void) {
  Serial.begin(9600);
  // MCP4725A1 address is 0x62 (default) 
  // MCP4725A1 address is 0x63 (ADDR pin tied to VCC) 
  // MCP4725A1 address is 0x60 (ADDR pin tied to GND) 
  if (!dac.begin(0x60)){  // (ADDR pin tied to GND) 
    Serial.println("DAC not found!");
    //while(1);
  }
}

const short  y_data[] = {
939, 940, 941, 942, 944, 945, 946, 947, 951, 956, 
962, 967, 973, 978, 983, 989, 994, 1000, 1005, 1015, 
1024, 1034, 1043, 1053, 1062, 1075, 1087, 1100, 1112, 1121, 
1126, 1131, 1136, 1141, 1146, 1151, 1156, 1164, 1172, 1179, 
1187, 1194, 1202, 1209, 1216, 1222, 1229, 1235, 1241, 1248, 
1254, 1260, 1264, 1268, 1271, 1275, 1279, 1283, 1287, 1286, 
1284, 1281, 1279, 1276, 1274, 1271, 1268, 1266, 1263, 1261, 
1258, 1256, 1253, 1251, 1246, 1242, 1237, 1232, 1227, 1222, 
1218, 1215, 1211, 1207, 1203, 1199, 1195, 1191, 1184, 1178, 
1171, 1165, 1159, 1152, 1146, 1141, 1136, 1130, 1125, 1120, 
1115, 1110, 1103, 1096, 1088, 1080, 1073, 1065, 1057, 1049, 
1040, 1030, 1021, 1012, 1004, 995, 987, 982, 978, 974, 
970, 966, 963, 959, 955, 952, 949, 945, 942, 939, 
938, 939, 940, 941, 943, 944, 945, 946, 946, 946, 
946, 946, 946, 946, 946, 947, 950, 952, 954, 956, 
958, 960, 962, 964, 965, 965, 965, 965, 965, 965, 
963, 960, 957, 954, 951, 947, 944, 941, 938, 932, 
926, 920, 913, 907, 901, 894, 885, 865, 820, 733, 
606, 555, 507, 632, 697, 752, 807, 896, 977, 1023, 
1069, 1127, 1237, 1347, 1457, 2085, 2246, 2474, 2549, 2595, 
2641, 2695, 3083, 3135, 3187, 3217, 3315, 3403, 3492, 3581, 
3804, 3847, 3890, 3798, 3443, 3453, 3297, 3053, 2819, 2810, 
2225, 2258, 1892, 1734, 1625, 998, 903, 355, 376, 203, 
30, 33, 61, 90, 119, 160, 238, 275, 292, 309, 
325, 343, 371, 399, 429, 484, 542, 602, 652, 703, 
758, 802, 838, 856, 875, 895, 917, 938, 967, 1016, 
1035, 1041, 1047, 1054, 1060, 1066, 1066, 1064, 1061, 1058, 
1056, 1053, 1051, 1048, 1046, 1043, 1041, 1038, 1035, 1033, 
1030, 1028, 1025, 1022, 1019, 1017, 1014, 1011, 1008, 1006, 
1003, 1001, 999, 998, 996, 994, 993, 991, 990, 988, 
986, 985, 983, 981, 978, 976, 973, 971, 968, 966, 
963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
964, 965, 966, 967, 968, 969, 970, 971, 972, 974, 
976, 978, 980, 983, 985, 987, 989, 991, 993, 995, 
997, 999, 1002, 1006, 1011, 1015, 1019, 1023, 1028, 1032, 
1036, 1040, 1045, 1050, 1055, 1059, 1064, 1069, 1076, 1082, 
1088, 1095, 1101, 1107, 1114, 1120, 1126, 1132, 1141, 1149, 
1158, 1166, 1173, 1178, 1183, 1188, 1193, 1198, 1203, 1208, 
1214, 1221, 1227, 1233, 1240, 1246, 1250, 1254, 1259, 1263, 
1269, 1278, 1286, 1294, 1303, 1309, 1315, 1322, 1328, 1334, 
1341, 1343, 1345, 1347, 1349, 1351, 1353, 1355, 1357, 1359, 
1359, 1359, 1359, 1359, 1358, 1356, 1354, 1352, 1350, 1347, 
1345, 1343, 1341, 1339, 1336, 1334, 1332, 1329, 1327, 1324, 
1322, 1320, 1317, 1315, 1312, 1307, 1301, 1294, 1288, 1281, 
1275, 1270, 1265, 1260, 1256, 1251, 1246, 1240, 1233, 1227, 
1221, 1214, 1208, 1201, 1194, 1186, 1178, 1170, 1162, 1154, 
1148, 1144, 1140, 1136, 1131, 1127, 1123, 1118, 1114, 1107, 
1099, 1090, 1082, 1074, 1069, 1064, 1058, 1053, 1048, 1043, 
1038, 1034, 1029, 1025, 1021, 1017, 1013, 1009, 1005, 1001, 
997, 994, 990, 991, 992, 994, 996, 997, 999, 998, 
997, 996, 995, 994, 993, 991, 990, 989, 989, 989, 
989, 989, 989, 989, 988, 986, 984, 983, 981, 980, 
982, 984, 986, 988, 990, 993, 995, 997, 999, 1002, 
1005, 1008, 1012};

const int data_size = sizeof(y_data);

void loop(){
  for (int i = 1;i < data_size;i++){
    setDAC(y_data[i]);
    delay(10);
  }
}

void setDAC(int v){
  dac.setVoltage(v, false);        //Set voltage to v V
  int valorAnalogico = 4*analogRead(pinoAnalogo);
  Serial.println(valorAnalogico);
}

Good luck!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.