Seeking Advice: Achieving Voltage Scaling with Arduino Uno R4 Minima's Built-in DAC

Greetings community members,

I hope this message finds you well. I'm currently engaged in a project that involves manipulating voltage levels using an Arduino Uno R4 Minima. Specifically, I'm aiming to read an input voltage within the range of 0-1V and subsequently scale it to fall between 0.45V and 0.525V. My intention is to accomplish this using the Arduino's built-in DAC, located on pin A0, for true analog output.

Despite having a decent grasp of Arduino programming fundamentals, I find myself seeking guidance on the most efficient approach to achieve this voltage scaling without resorting to PWM techniques. Here's a brief outline of my requirements:

  1. Input Voltage Range: 0-1V (to be sampled from analog pin A5).
  2. Output Voltage Range: 0.45V - 0.525V (to be generated using the built-in DAC on pin A0).

I'm reaching out to the community with a few specific queries:

  1. Optimal Methodology: What would be the most effective strategy to scale the input voltage to meet the desired output voltage range while utilizing the Arduino Uno R4 Minima's built-in DAC?
  2. DAC Considerations: Are there any key factors or nuances I should be mindful of when leveraging the built-in DAC for precise analog output?
  3. Coding Guidance: Would you recommend any particular coding techniques, libraries, or examples that could streamline the implementation of this voltage scaling functionality?

I genuinely appreciate any insights, advice, or experiences you can share on this matter. Your expertise would be immensely valuable in helping me navigate this aspect of my project successfully.

Thank you kindly for your time and assistance.

const int analogInPin = A5;  // Analog input pin A5
const float minOutputVoltage = 0.45;  // Minimum desired output voltage (in volts)
const float maxOutputVoltage = 0.525; // Maximum desired output voltage (in volts)

void setup() {
  Serial.begin(9600); // Initialize serial communication
}

void loop() {
  // Read the voltage on pin A5
  int sensorValue = analogRead(analogInPin);

  // Convert the ADC value to voltage (0-1V)
  float inputVoltage = sensorValue * (5.0 / 1023.0); // Convert to volts

  // Scale the input voltage to the desired output range (0.45V - 0.525V)
  float scaledVoltage = map(inputVoltage * 1000, 0, 1000, minOutputVoltage * 1000, maxOutputVoltage * 1000) / 1000.0; // Scale from mV to match the desired range

  // Output the scaled value to the DAC
  analogWrite(A0, scaledVoltage / 5.0 * 255); // Output scaled voltage to A0 (DAC pin)

  // Print input and output voltages to Serial Monitor
  Serial.print("Input Voltage: ");
  Serial.print(inputVoltage, 3); // Print with 3 decimal places
  Serial.print(" V, Output Voltage: ");
  Serial.print(scaledVoltage, 3); // Print with 3 decimal places
  Serial.println(" V");

  // Delay for stability
  delay(100); // Adjust as necessary
}

The Rev 4 is rather new to many helpers Y think. Nevertheless there might be experience out there.
While waiting for hands on tips, check the technical manual. Especially search for ADV ref voltage stuff.

Make like a map of the execution flow, like flow charts. That's, sadly, unknown to young people ending up with spegetti/birdnest code after hammering the keyboard for hours, days...

Serial.... Usually 115200 baud works well, giving all data without buffer overfill.

There's no need to convert to "volts" (except for 'readability').
But, yes, getting the ADC and mapping that for DAC'ing is about it.
It's going to be kind of choppy anyway.

14-Bit ADC Usage Guide in Arduino UNO R4 Minima (how2electronics.com)

runaway_pancake has given you a link to show you how to change the ADC resolution from 10-bit to 14-bit.

However, it is by changing the DAC resolution that you will get a bigger change in performance.

You are using the DAC with 8-bit resolution. (The Arduino Uno R4s default to 8-bit to maintain compatibility with the R3).

Each step in the output is approximately 19.5mV.
As your output voltage only varies between 450mV and 525mV, then you are only going to get a maximum of 5 distinct output voltages.

The Uno R4s have a 12-bit DAC. You can get 16 times as many steps in your output.

Here is a demonstration of your code on an oscilloscope:

  • Channel 1 (yellow trace) is a 1V pk-pk 100mHz sinewave, connected to A5.
  • Channel 3 (blue trace) is the 8-bit DAC output on A0

    The output only has 5 distinct values, even though you print the output voltage to 3 decimal places on the serial monitor.

I have modified your code to use the ADC in 14-bit mode, and the DAC in 12-bit mode.
Also I have printed the DAC count on the serial monitor as well as the voltages. (try that on the original 8-bit version).

const int analogInPin = A5;           // Analog input pin A5
const float minOutputVoltage = 0.45;  // Minimum desired output voltage (in volts)
const float maxOutputVoltage = 0.525; // Maximum desired output voltage (in volts)

void setup() {
  Serial.begin(115200);         // Initialize serial communication
  analogReadResolution(14);     // change ADC to 14-bit resolution
  analogWriteResolution(12);    // change ADC to 12-bit resolution
}

void loop() {
  // Read the voltage on pin A5
  int sensorValue = analogRead(analogInPin);

  // Convert the ADC value to voltage (0-1V)
  float inputVoltage = sensorValue * (5.0 / 16384.0); // Convert to volts

  // Scale the input voltage to the desired output range (0.45V - 0.525V)
  float scaledVoltage = map(inputVoltage * 1000, 0, 1000, minOutputVoltage * 1000, maxOutputVoltage * 1000) / 1000.0; // Scale from mV to match the desired range

  // Output the scaled value to the DAC
  analogWrite(A0, scaledVoltage / 5.0 * 4095);  // Output scaled voltage to A0 (DAC pin)
  int DACcount = (scaledVoltage / 5.0 * 4095);  // DAC count for printing

  // Print input and output voltages to Serial Monitor
  Serial.print("Input Voltage: ");
  Serial.print(inputVoltage, 3); // Print with 3 decimal places
  Serial.print(" V, Output Voltage: ");
  Serial.print(scaledVoltage, 3); // Print with 3 decimal places
  Serial.print(" V, DAC: ");
  Serial.print(DACcount);
  Serial.println("");

  // Delay for stability
  delay(100); // Adjust as necessary
}

See the difference that has made:

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