UNO R4 vs R3 analogRead() differences

I am working on a simple circuit that contains an IR sensor break beam (IR transmitter and IR receiver). I am reading the IR receiver values through an analog pin using the analogRead() function. I initially created this circuit on my arduino Uno R3, and everything works perfectly. When the IR beam is broken (or when the IR transmitter is removed), the analogRead returns a value of 0.

However, I recently swapped to the new Uno R4 wifi (all other wiring is the same), and I am getting different and unstable values on my analog pin. Even when the IR receiver is getting no IR signal, it still reads at a value of ~12 (it doesn't go down to zero). It also fluctuates much more than on the R3. I read on a similar post about adding a .1uf capacitor to the circuit, which I tried. This brought the value of the analogRead signal down closer to zero, but there is still fluctuation. Sometimes the values will bounce around from 0 up to 15 or 20. This was never the case for the R3, it was always rock steady on outputting a value of 0 when no IR signal was detected.

Any thoughts on why the difference in analogRead behaviors between the two boards, and how I can make the R4 analogRead values more robust and consistent?

Why are you using analogRead for what is essentially a digital signal?

Post an annotated schematic showing how it is wired and your code. Also post a llink to the sensor and associated parts.

It doesn't work if I use digitalRead attached to a digital pin. With analogRead, my values change as a function of how much IR signal is being received.

What type of IR sensor are you using ?

Detecting "how much IR signal is being received" is a strange concept.

Usually you're looking for a HIGH or LOW to tell whether the beam is broken or not. I've not seen anyone treat a break-beam as an analog signal.

It sounds like you need to:

Can't you just change your code to a different value for what a 0 is? Even in the digital realm there is leeway for what a LOW is. For example the 328P which is in the Uno R3 is a CMOS 5V logic level. A low is between 0 and 1.5V

Ok, did my best to draw up a basic schematic. Sorry for its crudeness.

For the IR emitter and receiver, here are the following specs as listed on Amazon. Chanzon 940nm IR Infrared LED Diode 5mm Emitter + Receiver Sender Reciver Kit

Following is the sketch that I test to show that if the beam is broken, it turns on the builtin LED.



void setup()
{
  pinMode(A0, INPUT);
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{

  
  Serial.println(analogRead(A0));
  delay(500);
  if analogRead(A0) < 10 {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
  
}

Yes, in my code, I'm looking for a value below 10 (for example) on the analogRead(). I can change 10 to whatever based on how the analogRead is sensing the value. I'm partly curious to know why the R3 and R4 would read different values of the IR receiver.

The R4 has a 12bit ADC...

But it defaults to 10 bit, unless you specifically change it.
This is to maintain compatibility with R3 code

My bad, I haven't actually used mine yet, lol. Still it could be related to the ADC. How is the linearity of the R4 ADC around 0?

I'll do a little test on the ADC at low voltages

I threw together a test on my bench last night.
I made a quick sketch and setup a potentiometer on A0.
First thing I noticed is that Vcc on the R4 and the R3 was different, makes sense, but mine was off by quite a lot. Vcc on the R3 was 5.015V and on the R4 it was 4.75V.
I recorded the adc value, voltage from my sketch and voltage from my DMM. I didn't measure the whole range, just a few measurements below 300mV. I had both boards hooked up at the same time and switched the ports in the IDE to switch back and forth so I could keep the exact same pot values.

Interesting to note, the R3 doesn't start reading values at lower voltages as fast as the R4. My results have the same trend as the OP.

Here are my results:

Uno R3		
DMM	ADC	Voltage
0.9mV	0	0
4.8mV	0	0
21.5mV	0	0
51mV	7	0.06
82mV	13	0.06
267mV	51	0.25
		
		
		
		
Uno R4		
0.9 mV	1	0
4.8mV	2	0.01
21.5mV	4	0.02
51mV	12	0.06
82mV	17	0.08
267mV	58	0.27
		

And here is the sketch I used

#define READ A0

float vcc = 4.75; // 5.015 for R3
float voltage = 0.00;
float averageADC = 0;
unsigned long currentTime = 0;
unsigned long prevTime = 0;
const int DEL = 1000;

int getAverage(int pin, int samples) {
  int average = 0;
  int averageV = 0;
  for (int i = 0; i < samples; i++) {
    average = analogRead(pin);
    averageV += average;
  }
  return averageV / samples;
}




void setup() {
  Serial.begin(115200);
  pinMode(READ, INPUT);
  prevTime = millis();
}

void loop() {
  averageADC = getAverage(READ, 10);
  currentTime = millis();
  voltage = (averageADC * vcc) / 1024;
  if (currentTime >= prevTime + DEL) {
    prevTime = currentTime;
    serialData();
  }
}

void serialData() {
  Serial.print("ADC Out");
  Serial.println(averageADC);
  Serial.print("Voltage");
  Serial.println(voltage);
}

Hey trilerian,

I did a similar exercise to you last night / this morning, in order to test the ADC at low voltages.

I did not use a potentiometer, but used the DC output of my function generator to supply the test voltage.

I hadn't realised that the output of the function generator changed in 10mV steps, even though the resolution of the setting knob/buttons and display goes down to 1mV. So I made an attenuator to get lower voltage steps / better resolution.

I used my multimeter to measure the voltage, and recorded the corresponding ADC output count. I did not attempt to convert the count to voltage.

Rather than manually take readings, I decided to automate the process.

I programmed the Arduino under test to send SCPI commands to the function generator to set the output voltage, and to the multimeter to read the attenuated voltage that went to the Arduino analogue input.

I tested the two Unos sequentially, transferring the ethernet shield and connections between the two Unos. All connections made using BNC leads.

Here are the results plotted in Excel.
Uno R3:


Uno R4:

It can be seen that the Uno R3 ADC count didn't change from zero until the input voltage was around 20mV, rather than the expected 4mV to 5mV.

Here is the code I used:

#include <SPI.h>
#include <Ethernet.h>

int dy = 500 ;

// Enter a MAC address and IP address for the Arduino
byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x0B, 0xB5 };
IPAddress ip(192, 168, 0, 10);                            // desired Arduino IP address
IPAddress server1(192, 168, 0, 7);                        // IP addresses of the Instruments
IPAddress server2(192, 168, 0, 8);                        // IP addresses of the Instruments

EthernetClient client1;
EthernetClient client2;

void setup() {
  // Start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.println("\n");

  // Give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println(" connecting...");
  Serial.println("");

  // Connect to Instrument 1;
  if (client1.connect(server1, 5025)) {       // Port 5025 is commonly used for SCPI
    Serial.print(" Instrument 1 connected : ");
    // Send a SCPI command to the DMM:
    client1.println("*IDN?");
  }  else {
    // If you didn't get a connection to the server:
    Serial.println("1 connection failed");
  }

  delay(dy);

  while (client1.available() > 0) {
    char c = client1.read();
    Serial.print(c);
  }

  // Connect to Instrument 2:
  if (client2.connect(server2, 5025)) {       // Port 5025 is commonly used for SCPI
    Serial.print(" Instrument 2 connected : ");
    // Send an SCPI command to the DMM:
    client2.println("*IDN?");
  } else {
    // If you didn't get a connection to the server:
    Serial.println("2 connection failed");
  }

  delay(dy);

  while (client2.available() > 0) {
    char c = client2.read();
    Serial.print(c);
  }
  Serial.println("\n"); 
  Serial.println("Test: ADC count:  voltage:\n");
  delay(3000);
}

void loop() {

  // If the server disconnected, stop the client:
  if (!client1.connected()) {
    Serial.println();
    Serial.println("disconnecting 1.");
    client1.stop();
    // Do nothing more:
    while (true);
  }


  // If the server disconnected, stop the client:
  if (!client2.connected()) {
    Serial.println();
    Serial.println("disconnecting 2.");
    client2.stop();
    // Do nothing more:
    while (true);
  }

  for (int i = 0; i <= 500; i++) {

    float voltage = i / 100.0 ;
    Serial.print(i);
    client1.print("C1:BSWV OFST,");       // set function generator  output voltage
    client1.println(voltage);

    delay(dy);

    int reading = analogRead(A0);         // read adc count
    Serial.print(",    ");
    Serial.print(reading);
    Serial.print(",    ");

    client2.println("READ?");             // read multimeter
    delay(dy);
    // If there are incoming bytes available from Instrument 2:
    while (client2.available() > 0) {
      char c = client2.read();
      Serial.print(c);
    }
  }
}

Here is a typical output from the serial monitor for uno R4:

The Uno R4 changes from zero to non zero around 4mV-5mV as expected.

1 Like

I like your test better than mine, lol. I like that you automated the test so it didn't take forever to measure the entire range.

But, looks like we both came to the same conclusion and answered the OPs question. The R3 isn't outputting an ADC value at the lower end where the R4 is.

It is nice to see the full range of the R4 you did, I was going to do that later, but now I don't need to. Looks pretty linear to me, which is good to know.

EDIT: Guess I should read graphs a bit better, you just went to 0.12V

I've just started a test to measure over the full range 0V - 5V.

I'll post the results when I've got them.

Yes, it's good that we both got the same results / conclusions.

The output of the function generator did go from 0V - 5V, but because I had my custom attenuator in place the Arduino only saw 0V - 125mV.

I had the attenuator in place to get steps of around 0.3mV - I've removed it now.

I've recently bought an Ethernet Shield R2 so that I can control my test equipment - I'm just learning how to use it.

Here are the results over the full range, 0V - 5V.
Uno R3:

Uno R4:

Both look very linear.

You can't tell on this scale that there is the 'issue' that spidarx started this topic for.

1 Like

IIRC, there was previous discussion where we noticed that the ADC input impedance of the R4 ADC is much lower than an AVR...

R4 chip:

ATmega328p:

1 Like

I appreciate everyone's sleuthing to provide some clarity for me. I played around with my IR beam break circuit, and I was able to get it to work when treating the IR receiver as a digital pin and reading HIGH or LOW. The problem with this approach for me is that the signal is so weak, that I basically have to have the IR emitter and the IR receiver touching to ever get the pin to go HIGH. Instead, I have the circuit working fine when treating the IR receiver as an analog input, but I'm just working with low values of signal strength ~30s (on a scale from 0-1023). It's enough to work as intended, however. While the UNO R3, would drop to a value of 0 when the beam is broken, the R4 will only drop to a value of 10 or so.