Project with the DAC on the Arduino Due

Hello Everyone!

I am somewhat new to the DUE board and I am attempting to build and write code for a deceptively simple configuration.

I have 0.300 Volts running into A0 on the board. My goal is too

  1. Read the correct voltages on A0 on the serial.print screen.

  2. Write code in order to get 0.300 volts coming out of the DAC0 on the DUE.

It seems pointless but all i need to do is watch the voltage change on the output of the DAC0 as i change the voltage going into the A0 input.

I have attached the code i have so far. Two problems arise with this code

  1. I have it set to read 5.0V/1023.0 but the serial.print reads 0.40 volts. Not the desired 0.300 volts i am putting in A0.

  2. I am getting nothing out of the DAC0 port. I want it to read 0.300 volts.

Thank you for your time. Any help would be appreciated! Let me know if you cant open the code file.

Analog_read.ino (725 Bytes)

  1. You can't apply 5V to arduino DUE w/o damaging it
  2. DAC outputs in range 1/6 to 5/6 of Vcc, so 0.55 - 2.75V, you can't get 0.3V w/o additional hardware

Those are two very good points! So I should change my scale from 5.0/1023 to 3.3/1023 in order to fallow that rule. Also i will have to use an op amp to bump up my voltage going into the A0. But other than that my code should work just fine correct?

Thank you for your time!

Hi, NO you do not have to bump up the voltage going INTO A0. You have to lower it, the range on input volts to A0 is 0 to 3.3V , 0 to 4095. You have 0 to 5V.

The output will only be 0.55V to 2.75V, 0 to 4095.

So the output will have to be shifted and amplified to get 0 to 5V output.

What experience do you have with programming, arduino, electronic hardware?

Tom.... :)

I do not have an incredible amount of experience in those areas. :slight_smile: But i have changed my code and the serial print screen is reading off the right values. When I read my voltage coming out of the DAC1 it reads a constant 1.02 volts. I need it to read the voltage going into A0 as i change it. do i need to set the output to a scale? here is the code attached that i have now.

Analog_read.ino (720 Bytes)

Hi, is there any reason you need to reproduce the 0.3V, cant you just pass on the 0.3V you have at input of the due and use it to just measure the value. Don't worry about getting the DAC to produce what you already have.

Unless you need more, you need to explain to us the whole scope of what you are trying to do so we can give to the best advice. What is the application?

Tom..... :) If all you want to do is monitor the voltage, using a DUE is a waste of money and resourses.

Okay so here is the whole scope. I have an analog input coming from a transimpedance amplifier circuit with x voltage going into A0. I need to use the DAC because:

1) I am using the analog signal coming out of the DUE to control the Bias on a EOM. 2) the .55 too 2.75 analog output range i will use as MY range (max and min) for the bias.

It seems with the code above i am getting a constant 1.02 volts coming out. I need it to change as I change the A0 voltage.

I hope that is clear.

Thanks again for your help!

why did you not post the code so that everyone can see it?:-

/*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

 This example code is in the public domain.
 */

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(DAC1, OUTPUT);
  pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  // print out the value you read:
  Serial.println(voltage);
  analogWrite(DAC1, A0);
}

You will see a silly mistake, you are outputting to the DAC a value which is the pin number of the analogue input, not the value of the input.

Hello.

Okay I see the mistake I have attached my code after i made a lot of changes.

/*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

 This example code is in the public domain.
 */

// the setup routine runs once when you press reset:
int analogPin = 0;   // potentiometer connected to analog pin 3

int val = 0;
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(DAC1, OUTPUT);
  pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  // print out the value you read:
  Serial.println(voltage);
  val = analogRead(analogPin);
  analogWrite(DAC1, val);
}

Now i am getting a changing value for the DAC1 output but it is slightly offset less at about .2 of a volt.

Any further tips?

Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

Hope it's just a typo ... should be +3.3V.

Sorry there is no pot in this circuit just a voltage going into A0

Like this

int analogPin = 0;  

int val = 0;
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(DAC1, OUTPUT);
  pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  // print out the value you read:
  Serial.println(voltage);
  val = analogRead(analogPin);
  analogWrite(DAC1, val);
}

Why:-

int sensorValue = analogRead(A0);
and
val = analogRead(analogPin);

Why not just:-

analogWrite(DAC1, sensorValue);

Now i am getting a changing value for the DAC1 output but it is slightly offset less at about .2 of a volt.

That is because there is an offset on the DAC so when you read zero and put zero out you actually get 0.2. There is nothing you can do about this apart from not put anything out to the DAC when the input reading is less than 0.2V and then when you do put something out subtract 0.2V from it.

The analog input (ADC) range is 0 to 3.3V. The analog output (DAC) range is 0.55 to 2.75V (1/6 to 5/6 VCC).

You'll need to use the map function so that 0-1023 range will convert to 170-852.

Then, at DAC1, 0.55V will represent 0.0V at A0. 2.75V will represent 3.3V at A0.

If you set the analog write resolution to 12, you could exploit the full DAC resolution of the Due. You would need to configure the map function accordingly.

There are two ways of doing this, one as I outlined above and the other as dlloyd says. They are both not what you asked for because what you asked for is impossible. You have to choose if you want the full range of inputs to map the full range of outputs, or for the output to match the input but only for the limited range avaliable on the output.

You can not have both.

He's already got one opamp in there. With another on the ouput, I'm sure he can achieve a full-range output.

"Nothing is impossible except skiing through a revolving door."

Those are good points. All i need to do is put in .55-2.75 voltage on A0 and put out the same voltage on DAC1. If the range is from .55 too 2.75 volts that is fine. I just cant understand why my code doesn't work for that.

Now i use the code.

int analogPin = 0;  

int val = 0;
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(DAC1, OUTPUT);
  pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  // print out the value you read:
  Serial.println(voltage);
  val = analogRead(analogPin);
  analogWrite(DAC1, val);
}

When i put in 1.6 volts in A0 i get .6 volts out the DAC1. When i put in .7 volts in the A0 i get 2.6 volts out the DAC1.

Whats going on here?

This code will take full advantage of the 12-bit resolution. It just uses a counter for the ADC codes and prints out voltages and writes them to DAC0 and DAC1.

Compare the numbers in the printout and notice the resolution. Also notice that the saw-tooth pattern for DAC1 has shorter duration (because its working from 1/6 to 5/6) but it covers the full range 0-3.3V on the input.

unsigned short mapDac1 = 0, count = 0, adc = 0;
float voltsIn = 0.0, voltsDac0 = 0.0, voltsDac1 = 0.0;

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
}

void loop() {
  analogWrite(DAC0, adc);
  analogWrite(DAC1, mapDac1);

  adc = count % 4096;
  voltsIn = adc * (3.3 / 4095);
  mapDac1 = map(adc, 0, 4095, 682, 3413);  // 1/6 => 682, 5/6 => 3413
//mapDac1 = adc;                           // not mapped

  voltsDac1 = mapDac1 * (3.3 / 4095);      // mapped for 1/6 - 5/6 range

  Serial.print("adc ");
  Serial.print(adc);
  Serial.print("  voltsIn ");
  Serial.print(voltsIn, 4);
  Serial.print("  mapDac1 ");
  Serial.print(mapDac1);
  Serial.print("  voltsDac1 ");
  Serial.println(voltsDac1, 4);

  count++;
  delay(1);
}

All i need to do is put in .55-2.75 voltage on A0 and put out the same voltage on DAC1.

In the code above, you'll find this on DAC0. Note that this code isn't taking any readings, its just showing calculations with the numbers.

bulls54: Whats going on here?

You are ignoring what you have been told. Not sure why anyone should bother telling you anything if you won't listen.

I understand what dlloyd was saying about using the mapping command to get the full 0.00 to 3.3 volts output. But I do not need to go that deep into this. When i put in dlloyd code is running calculation just like he said. On the DAC0 in that code i am reading the calculated series of voltages.

Note that this code isn’t taking any readings, its just showing calculations with the numbers

Although I just NEED it to take a reading of A0 and output that voltage on to DAC0 OR DAC1. The resolution is fine and I just need to do what Mike said which is

for the output to match the input but only for the limited range avaliable on the output.

This is all very good help but I don’t think i am being clear so it seems like i am not taking the advice. I think it is much simpler than I am making it sounds. So here is the basic (without all the fluff) code that I have after all of the info that you have given me. No mapping needed as far as I am concerned.

int analogPin = 0;  

int val = 0;
void setup() {

  Serial.begin(9600);
  pinMode(DAC1, OUTPUT);
  pinMode(A0, INPUT);
}

void loop() {
  
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  
  Serial.println(voltage);
  
  analogWrite(DAC1, sensorValue);
}

And with this code when I put .72 volts IN THE A0. I get 2.4 volts out the DAC1. When i put 1.28 volts in the A0. I get 1.75 volts out the DAC1. When i put 1.91 volts in the A0. I get 2.5 volts out the DAC1.

As you can see this is not right. When i put .72 volts in the A0 i just need to read .72 volts coming out the DAC1. As so on…

Does this require i need to use the mapping command?

Thanks again.