problem with analogReference INTERNAL and DEFAULT in the same loop

i have a problem if i run this code dont work good …

i have a LM35 temp sensor in A1 and one variable Resistor in A0 for FAN speed control
if i run alone A1 works great…
if i run alone A0 works great
but together have a problem
if i run in state_loop(); the state = 1 for sensorValue = analogRead(analogInPin); to control fun speed and at the same time i have look in the temp there is the problem…

any idea?

void state_loop()
{
  analogarefdefault();
  if (state == 1){
    sensorValue = analogRead(analogInPin);
  }
  else if (state == 0){
    sensorValue = 0;
  }
  else if (state == 3 && sensorValue < 1023){
    sensorValue = sensorValue + 51.15;
    state = 10; 
  }
  else if (state == 4 && sensorValue > 0 ){
    sensorValue = sensorValue - 51.15;
    state = 10;  
  }
  else if (state == 5){
    sensorValue = 255.75;
    state = 10;
  }
  else if (state == 6){
    sensorValue = 511.50;
    state = 10;
  }
  else if (state == 7){
    sensorValue = 767.25;
    state = 10;
  }
  else if (state == 8){
    sensorValue = 1023.0;
    state = 10;
  }
  outputValue = map(sensorValue, 0, 1023, 0, 255);
  analogWrite(analogOutPin, outputValue);
  return;
}
void read_temperature(){
  analogarefinternal();
  LM35arrayout[0] = LM35arrayout[1];
  LM35arrayout[1] = LM35arrayout[2];
  LM35arrayout[2] = LM35arrayout[3];
  LM35arrayout[3] = LM35arrayout[4];
  LM35arrayout[4] = analogRead(LM35out); 
  readValueLM35out = (LM35arrayout[0] + LM35arrayout[1] + LM35arrayout[2] + LM35arrayout[3] + LM35arrayout[4]) / 5;
  temperatureCout = readValueLM35out / 9.31;
  LM35arrayin[0] = LM35arrayin[1];
  LM35arrayin[1] = LM35arrayin[2];
  LM35arrayin[2] = LM35arrayin[3];
  LM35arrayin[3] = LM35arrayin[4];
  LM35arrayin[4] = analogRead(LM35in); 
  readValueLM35in = (LM35arrayin[0] + LM35arrayin[1] + LM35arrayin[2] + LM35arrayin[3] + LM35arrayin[4]) / 5;
  temperatureCin = readValueLM35in / 9.31;
}
void temperature_F_loop(){
  lcd.clear();
  while (1){
    read_temperature(); 
    temperatureFout = (temperatureCout * 1.8) + 32;
    temperatureFin = (temperatureCin * 1.8) + 32;
    lcd.setCursor(0, 0);
    lcd.print(F("IN: |Temp| OUT:")); 
    lcd.setCursor(0, 1);
    lcd.print(temperatureFin); 
    lcd.write(1);
    lcd.print(F("F "));
    lcd.setCursor(8, 1);
    lcd.print(temperatureFout); 
    lcd.write(1);
    lcd.print(F("F "));
    delay(500);
    ir_reciver();
    reading_loop();
    state_loop(); 
  }
}
void temperature_C_loop(){
  lcd.clear();
  while (1){
    read_temperature();
    lcd.setCursor(0, 0);
    lcd.print(F("IN: |Temp| OUT:")); 
    lcd.setCursor(0, 1);
    lcd.print(temperatureCin); 
    lcd.write(1);
    lcd.print(F("C "));
    lcd.setCursor(8, 1);
    lcd.print(temperatureCout); 
    lcd.write(1);
    lcd.print(F("C "));
    delay(500);
    ir_reciver();
    reading_loop();
    state_loop(); 
  }
}
void analogarefinternal()
{
  analogReference(INTERNAL);
  delay(100);
}
void analogarefdefault()
{
  analogReference(DEFAULT);
  delay(100);
}

It's a mistake and a hardware fault if you wire an external voltage to the arduino Aref pin and then switch between internal and external references in the same sketch. It creates a short circuit condition between the internal and external voltages and the resulting current flow can damage the chip. The Reference section has a caution about this:

Warning

Don't use anything less than 0V or more than 5V for external reference voltage on the AREF pin! If you're using an external reference on the AREF pin, you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board. Alternatively, you can connect the external reference voltage to the AREF pin through a 5K resistor, allowing you to switch between external and internal reference voltages. Note that the resistor will alter the voltage that gets used as the reference because there is an internal 32K resistor on the AREF pin. The two act as a voltage divider, so, for example, 2.5V applied through the resistor will yield 2.5 * 32 / (32 + 5) = ~2.2V at the AREF pin.

He's not changing it to an external voltage though, he's changing it between the 5V and the 1.1V internal references.

I had this exact problem before. After changing the analog reference, I got garbage data back from the first read. My solution was to do an analogRead() right after the reference was changed and just ignore the return value. Then I didn't need delays.

I made a topic about changing the reference section, but it looks like nothing was done about that.

void analogarefinternal()
{
  analogReference(INTERNAL);
  analogRead(A0);
}
void analogarefdefault()
{
  analogReference(DEFAULT);
  analogRead(A0);
}

EDIT: Or maybe it was. The Reference page for the analogReference function says this:

After changing the analog reference, the first few readings from analogRead() may not be accurate.

In my experience, it was only the first reading that had a problem, the rest were fine.

i have chage from 1,1 to 5 v not external aref :)

peiperakos:
i have chage from 1,1 to 5 v not external aref :slight_smile:

Yes, my mistake, reading too quick. Sorry

ok no problem :grin:

Jiggy-Ninja how ignore return value ?

peiperakos: ok no problem :grin:

Jiggy-Ninja how ignore return value ?

Just like a showed you in the code I posted. Just call the function without assigning it to anything.

if (state == 1){
    sensorValue = analogRead(analogInPin); \\ analogInPin = A0 and there what can i do because value sensorValue  i wont?

Jiggy-Ninja i have done the analogRead with no value but my problem is there :(

How quickly (in microseconds) are you reading the analog value after changing either the internal reference or the pin that is being sampled. When you make these changes the value from the first read may not be correct so it is best to discard it. See Section 23.4 "Prescaling and Conversion Timing" in the datasheet.

...R

I also had exactly the same problem. Looking at the source code (file wiring_analog.c) I found that the call to analogReference does NOT change the reference voltage. The change is delayed until you first call analogRead. Second problem is: switching from 5V to 1V1 reference voltage takes about 7ms. This time is needed to discharge the decoupling capacitor that is present on the arduino board down to 1.1V I was successful by calling analogReference, then analogRead discarding the result, then delay (10).

Taking a look back at my old code, I had a delay after the read just like olf2012. Here's the routine I used to read my LM35 temp sensor:

float readTemperatureK( int adcPin )
{
  analogReference( INTERNAL );
//  Dummy read to set the new reference.
  analogRead( adcPin );
//  may not be necessary to stabalize the new ADC reference,
//  but this delay is a "just in case" sort of thing"
  delay( 10 );
  int tempSense = analogRead( adcPin );
//  Temperature sensor is calibrated to read Celsius.
  float celsiusTemp = tempSensorToCelsius( tempSense, vRefTemp );
//  Covert to Kelvins.
  return temperatureCtoK( celsiusTemp );
}

Are showing us your code snippet because it is working now, or because there is still a problem?

Assuming it's the latter ...

If you don't save the result of the first analogRead() into a variable I wonder if the compiler includes it at all?

I would have "tempSense = analogRead( adcPin );" at both locations.

And while you are trying to get things to work it would be useful to display both values in the serial monitor.

...R

I read your first code, and it was overcomplicated and hard to follow.

I'd suggest that you change what you are doing so that you don't need to try using both analog methods in the same project. Given the way the hardware works, you are just "asking for trouble" of some kind.

How about dividing the first device voltage by 5 with resistors, and reading them both with the 1.1 V range ?

The datasheet explicitly says:

When the bandgap reference voltage is used as input to the ADC, it will take a certain time for the voltage to stabilize. If not stabilized, the first value read after the first conversion may be wrong.

i will can with one voltage divider to drive the first and second divice. but would like to know if in the same loop can work the internal and external with some delay ? for me just not work :(

I haven't seen anything in the Atmega datasheet that suggests you can't change internal references in a program. Have you?

Create a voltage divider that gives a constant voltage that can be read with both references without causing damage. Then write a short sketch to read the voltage with the different references leaving a suitable delay between changing reference and reading the value. Read each value twice in succession and see if both reads give the same result.

If it doesn't seem to work for you post a copy of the sketch and your wiring diagram.

...R