analogRead after disconnecting ADC module

I don't understand. Namely. I connect 2V and 4V DC to the pins on the Arduino Uno, A0 and A1, respectively. Then in Setup(), I disconnected the ADC module, as I connected the Arduino's internal comparator to A0. Nevertheless, when I start reading the A0 or A1 pin in the loop() section by use of analogRead Im reading the correct voltages. Why ??? After all, I have disconnected the ADC, so analogRead should not be able to read the voltages on these pins.
The code:

float fl;
int yel;

void setup() 
{
   Serial.begin(9600);
   
  pinMode(A0,INPUT);pinMode(A1,INPUT);
 
//conect A0:
  ADCSRB |= (1 << ACME);  // MUX selects comparator negative input AIN1 and then 
  ADCSRB &= ~(1 << ADEN); // Disable the ADC module because                    
  ADMUX = 0;               // connects to A0.   
}

void loop() {
  
yel= analogRead(A0);
  fl= (float)yel*5./1023.;
  Serial.print("A0= ");
  Serial.println(fl);  
  
   yel= analogRead(A1);
  fl= (float)yel*5./1023.;
  Serial.print("A1= ");
  Serial.println(fl);  
  
  delay(2000);
}

Why would you want to turn off the ADC module and them try and use it?

My guess is that attempting to use it ensures that is is turned on.

1 Like

The analogRead() turns it on for an Arduino Uno: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_analog.c#L38

1 Like

I have moved your Topic to Programming Questions ....Please try not to post in Uncategorized again, If you are unsure about the categories refer to this guide or to the stickies for each category.

Thank You.

Go look at the source code for analogRead. It doesn't matter how you set the ADC, when you call analogRead it sets it to what is necessary for that function.

int analogRead(uint8_t pin)
{

#if defined(analogPinToChannel)
#if defined(__AVR_ATmega32U4__)
	if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#endif
	pin = analogPinToChannel(pin);
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
	if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
	if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
	if (pin >= 24) pin -= 24; // allow for channel or pin numbers
#else
	if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

#if defined(ADCSRB) && defined(MUX5)
	// the MUX5 bit of ADCSRB selects whether we're reading from channels
	// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
	ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
  
	// set the analog reference (high two bits of ADMUX) and select the
	// channel (low 4 bits).  this also sets ADLAR (left-adjust result)
	// to 0 (the default).
#if defined(ADMUX)
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
	ADMUX = (analog_reference << 4) | (pin & 0x07);
#else
	ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif
#endif

	// without a delay, we seem to read from the wrong channel
	//delay(1);

#if defined(ADCSRA) && defined(ADC)
	// start the conversion
	sbi(ADCSRA, ADSC);

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));

	// ADC macro takes care of reading ADC register.
	// avr-gcc implements the proper reading order: ADCL is read first.
	return ADC;
#else
	// we dont have an ADC, return 0
	return 0;
#endif
}

When analogRead(A0) instruction is executed, the following actions are carried out:
1. ADC Module is enabled.
2. 5V (default) is connected at the VREF-pin of the ADC.
3. Channel A0 is selected.
4. ADC is started.
5. End-of-Conversion signal is polled to see that conversion is done.
6. ADC value enters into <ADCH, ADCL> registers.
7. The contents of <ADCH, ADCL> registers enter into user variable yel.

Thank you all for the quick help.

Yes.

Hopefully I've fixed your code for you and I put the explanation of every fix at the bottom for ya.

float voltageA0 = 0.0;
float voltageA1 = 0.0;

void setup() {
  Serial.begin(9600);

  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  
  // Disable the digital input buffer for A0 and A1
  DIDR0 = (1 << ADC0D) | (1 << ADC1D);
  
  // Configure the comparator for A0
  ACSR = (1 << ACBG) | (1 << ACIE);
}

void loop() {
  // Read voltage on A0
  voltageA0 = analogRead(A0) * (5.0 / 1023.0);
  Serial.print("A0 voltage: ");
  Serial.println(voltageA0, 2);  // Print with 2 decimal places

  // Read voltage on A1
  voltageA1 = analogRead(A1) * (5.0 / 1023.0);
  Serial.print("A1 voltage: ");
  Serial.println(voltageA1, 2);  // Print with 2 decimal places

  delay(2000);
}

Here's an explanation of the changes made:

  1. Removed the global yel and fl variables to reduce memory usage and improve code clarity.

  2. Set the DIDR0 register to disable the digital input buffer for A0 and A1. This ensures that the pins are in analog mode and reduces power consumption.

  3. Configured the Analog Comparator Control and Status Register (ACSR) to connect the internal comparator to A0. The ACBG bit is set to connect the internal bandgap reference to the positive input of the comparator, and the ACIE bit is set to enable the analog comparator interrupt.

  4. In the loop() section, read the voltage using analogRead() for A0 and A1, and calculate the voltage directly in volts using the formula (5.0 / 1023.0). This formula scales the ADC reading to a voltage between 0 and 5V.

  5. Used Serial.println() to print the voltage values with two decimal places for better readability.

These changes optimize the code, make it more efficient, and improve clarity by removing unnecessary global variables and explicitly configuring the comparator and pin modes.

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