Problem reading two sensors with analogRead()

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Strohkopf
 
Posts: 2
Joined: Sat Nov 24, 2012 6:44 am

Re: Problem reading two sensors with analogRead()

Post by Strohkopf »

Hi! Seems I have problems w/ reading sensors too.

I have arduini uno board, seeeduino wifly-shield http://www.seeedstudio.com/wiki/Wifi_Shield and extension DFRduino shield.
I need to send results from IR and Ultra Sound length-meters via WiFi on PC, just making a robot.

Simple code of my programm is

Code: Select all

#include "Wifly.h"
#include <SoftwareSerial.h>
WiflyClass Wifly(2,3);

int sensors[6];

void setup()
{
  Serial.begin(9600);//use the hardware serial to communicate with the PC
  bool wifi = true;
  if(wifi){
    Wifly.init();//Initialize the wifishield
    Wifly.setConfig("MyWiFi","12345678");//here to set the ssid and password of the Router
    Wifly.join("MyWiFi");
    Wifly.checkAssociated();
    while(!Wifly.connect("192.168.137.1","40020"));//connect the remote service
    Wifly.writeToSocket("Connected!");
  }
}

void loop(){
  Serial.print("Sensors:");
  for( int i = 0 ; i < 6 ; i++ ){
    analogRead(i);
    delay(10);
    sensors[i] = analogRead(i);
    Serial.print(sensors[i]);
    Serial.print(", ");
    delay(30);
  }
  Serial.println(";");
  
}
If i set wifi = true, then sensors show me some rubbish, every pin shows value is about 1010, and does not change on differenr ranges.
But when I set wifi = false, i.e. do not do wifly initialisation, everything works propally. I found that priblem in function WiFly.init() which do the next:

Code: Select all

void WiflyClass::init() {
	
	pinMode(WIFLY_RST, OUTPUT);
	pinMode(WIFLY_GPIO6, INPUT);
	SoftwareSerial::begin(9600);
	reset();
	unavailConn = 0;
}
This WiFly class is a child of SoftwareSerial class. I guess here some conflict between serial prints. Dd anyone face this problem?
Sorry for bad english.
Cheers!

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

If i set wifi = true, then sensors show me some rubbish, every pin shows value is about 1010, and does not change on differenr ranges.
Could be interference from the WiFly radio. Have you posted this over at Sparkfun to see if it is a known issue?

Strohkopf
 
Posts: 2
Joined: Sat Nov 24, 2012 6:44 am

Re: Problem reading two sensors with analogRead()

Post by Strohkopf »

adafruit_support wrote: Could be interference from the WiFly radio. Have you posted this over at Sparkfun to see if it is a known issue?
Nope, they said that they do not support this shield.

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

Nope, they said that they do not support this shield.
Sorry, I meant SeeedStudio instead of SparkFun. They make a version of this shield also.
We do not have any experience with these shields and do not sell or support them here.

manrussian
 
Posts: 2
Joined: Tue Jan 15, 2013 8:45 pm

Re: Problem reading two sensors with analogRead()

Post by manrussian »

Just registered here to say thanks for the informative thread. Had stability issues reading only a single TMP36 with my Uno while working on a smart web-enabled thermostat project where I would like to keep the temperature with 1 degree F.

I used the mentioned solution of just taking many samples and finding an average. In my case I'm sticking with 64 samples. Speed isn't a big issue as even with the over-sampling all other project functions seems responsive (web server, user parameter parsing, NTP time synchronization, etc).

Without this fix I would get swings of multiple degrees. With 16 samples it still wasn't to my liking. 64 seems to do the trick.

I'm using the default 5v reference, with power from USB. TMP36 current on breadboard via some cheap jumper cables.

Didn't explore hardware fixes like low-pass RC/LC filters as there's no need to increase physical space with the above software fix.

Here's the code in case it helps someone:

Code: Select all


#define tsp 5                  //temp sensor input port
#define ADCsamples 64          //Number of temperature sensor values to take for average
float tempCurrent = 0.0;       //current temperature

void readTemp() {
  float tempFlast = tempCurrent;                    //For monitoring temperature sensor/ADC noise
  float ADCavg = 0.0;                               //To store average ADC value
  float ADCsum = 0.0;                               //Store sum of ADC samples
  for (int i = 0; i < ADCsamples; i++) {
    ADCsum += analogRead(tsp);
  }
  ADCavg=ADCsum / (float)ADCsamples;
  float tspVolts = ADCavg * (aRef/1024.0);           //convert ADC value to voltage
  float tempC = (tspVolts - 0.5) * 100.0;            //convert voltage to Centigrate temp for TMP36 temp sensor
  float tempF = (tempC * 9.0 / 5.0) + 32.0;          //Convert Centigrade to Farenheit 
  tempCurrent = tempF;                               //Set current temperature to user expected Farenheit value
  Serial.println(tempF - tempFlast);                 //Output difference from last average
}

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

I'm using the default 5v reference,
This does tend to be the noisiest reference on the Arduino, since it supplies all the digital logic too. The 3.3v reference is typically the most stable on this platform.

manrussian
 
Posts: 2
Joined: Tue Jan 15, 2013 8:45 pm

Re: Problem reading two sensors with analogRead()

Post by manrussian »

Any thoughts on whether the 3.3V is more or less stable than the "INTERNAL" analog reference described here?

http://arduino.cc/en/Reference/AnalogReference

Seems for my Uno that would be 1.1V. If my arithmetic is correct, with a TMP36 (.5v offset and 10mV per degree C) I can still measure up to 60 degrees C, or 140 degrees F. This would be plenty for my home thermostat project.

The advantages I see to this are:

1 - Less external connections (no need to connect 3.3V pin to aRef pin)
2 - Doesn't rely on external 3.3V regulator on Arduino.

Of course in all of the above I'm ignoring other noise sources like stray capacitance and unshielded cables that have been discussed earlier, but I'm willing to take what I can get while keeping external parts/connection to a minimum.

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

In theory, it ought to be more stable. But our experience says otherwise.
http://forums.adafruit.com/viewtopic.ph ... 97&p=83455

Midway
 
Posts: 2
Joined: Fri Sep 06, 2013 4:50 pm

Re: Problem reading two sensors with analogRead()

Post by Midway »

Hi,

I have the same porblem, but dont know how/where to add (write) the code inside this project.
When I integrate the PAvalue it will influenced the Temp / Fan control.

Code: Select all

#include <LiquidCrystal.h>

float Voltage;
float TempC;

int FAN = 9;                            // FAN Optocoupler (CNY74-2) connected to digital PWM pin 9
int Temperature;
int PAvalue;
int PAVin = 0;

const int LM35 = 0;                     // analog pin 0 (LM35CZ).
const int PA = 2;                       // analog pin 2 (PA signal Input).

const int LowTemp = 30;                 // Setting LOW Temperature setpoint. The Fan reach full speed then temperature is more than 10°C above setpoint.


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


void setup()
{ 
  lcd.begin(16,2);
  pinMode(FAN, OUTPUT);                 // Set pin for output to control FAN Optocoupler.
  pinMode(TempC, INPUT);                // sets analog pin 0 for input
  pinMode(PA, INPUT);                   // sets analog pin 2 for input
} 
void loop()
{
  Temperature = analogRead(LM35);                         // read the value from the LM35 sensor
  Voltage = Temperature * (5.0/1024);                     // convert reading to voltage (in V), for 5V input 
  TempC = ( 5.0 * Temperature * 100.0) / 1024.0;          // convert voltage to temperature

  analogWrite(FAN, constrain( (TempC - LowTemp) * 25, 0, 255));   // If the temperature is highher than the set point, run the fans.

  lcd.setCursor(0,1);
  lcd.print(TempC);                                       // Print Celsius temperature to LCD 
  lcd.print((char)223);                                   // degree symbol 
  lcd.print("C ");
  {
  } 
  PAvalue = analogRead(PA);                               // read the value from the PA output driver.
  float PAVin = PAvalue * (4.5 / 1024.0);

  if (PAVin>4)
  {
    lcd.setCursor(8, 0);
    lcd.print("10");
  }
  else
    if (PAVin>3 && PAVin<4)
    {
      lcd.setCursor(8, 0);
      lcd.print(" 8");
    }
    else
      if (PAVin>2 && PAVin<3)
      {
        lcd.setCursor(8, 0);
        lcd.print(" 6");
      }
      else
        if (PAVin>1 && PAVin<2)
        {
          lcd.setCursor(8, 0);
          lcd.print(" 4");
        }
        else
          if (PAVin>0.5 && PAVin<1)
          {
            lcd.setCursor(8, 0);
            lcd.print(" 3");
          }
          else
            if (PAVin>0 && PAVin<0.5)
            {
              lcd.setCursor(8, 0);
              lcd.print(" 2");
            }
  {
    lcd.setCursor(0, 0);
    lcd.print("Output:");
    lcd.setCursor(11, 0);
    lcd.print("Watt");
    lcd.setCursor(10, 1);
    lcd.print(PAVin);
    lcd.setCursor(15, 1);
    lcd.print("V");
  }
}
Any help will appriciate.

Thanks
Ed.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_rick »

Just duplicate the analogRead lines to read everything twice:

Code: Select all

  Temperature = analogRead(LM35);                         // read the value from the LM35 sensor
  Temperature = analogRead(LM35);                         // First time was for practice. Now read it for real.

Code: Select all

  PAvalue = analogRead(PA);                               // read the value from the PA output driver.
  PAvalue = analogRead(PA);                               // read it again, just to make sure.
If you want to change the analog reference to 3.3V, then you would also add this line at the end of your setup() function:

Code: Select all

analogReference(EXTERNAL);
You also have to attach a jumper wire between the 3.3V output pin and the AREF input pin.

Midway
 
Posts: 2
Joined: Fri Sep 06, 2013 4:50 pm

Re: Problem reading two sensors with analogRead()

Post by Midway »

Many thanks!!

it work fine now.

regards,
Ed.

pavlii
 
Posts: 5
Joined: Sun Sep 22, 2013 5:13 pm

Re: Problem reading two sensors with analogRead()

Post by pavlii »

Well, I am trying to read many sensors at once with Arduino Ethernet board, better said all my AD inputs are connected: AD0-4 to AMPLOC 25 current sensors (quite low output resistance, directly connected to AD inputs) and AD5 is a voltage divider, scanning solar array voltage (0-40V).

I do a continuous loop through all AD inputs as fast as possible and my server is reading summary values each minute over the ethernet interface. It simply reads sum of all AD reads on each AD input and a loop counter. The server divides the sum by a counter and gets an average value on the AD input for the finished minute. The goal was to measure power consumptions precisely.

Problem was, that the AMPLOC's are very sensitive and I needed to get a long term precision of one tenth of AD digit, that seemed unrealistic with Arduino. The zero value (sensor has a zero current value at half of the range, that is 2.5V when Vcc is taken from the +5V Arduino source and Arduino reference is set to Vcc), varied +-1AD digit minimum through the day. That is not much, but makes quite a difference in the measurement.

I started to read through the forums and soon I found this topic and tried the doubled AD reads (one blind to switch the mux and second to get the data) but I still got the AD reads influencing each other. Not much, but still... Please note, that I do not want to insert big delays, because I need as much measurements per minute, as possible. The code was like this:

Code: Select all

    AD0 = analogRead(0);  
    analogRead(1);  //switch mux to the next input to stabilize, discard this read  
    ADD0 = ADD0+AD0;  // some math to remember max, min and sum values. It gives some time to the mux cap to charge         
    MAX0 = max (AD0,MAX0);
    MIN0 = min (AD0,MIN0);

    AD1 = analogRead(1);  //read A1 value
    analogRead(2);  //switch mux to the next input to stabilize, discard this read  
    .....
At the end I found some reply here, that someone discharged the mux capacitor between the reads by switching the mux cap to a grounded AD input. I had no free AD input to test it, but at this moment I realized, that the only AD input, which does not vary a lot, is the internal thermal sensor at AD8. So I tried to insert an analogRead of the thermal sensor to (dis)charge the mux capacitor to a stable value before all reads, something like:

(please note that the following code is an example, you cannot use analogRead(8) with the Arduino Ethernet board, you have to use alternative analogRead routine, the Arduino internal will make analogRead(0) instead of analogRead(8), it does not take input numbers 8 and above)

Code: Select all

    AD0 = analogRead(0); // read the A0 value 
    analogRead(8);  // discharge the mux cap to stable temp value (+-10 digits do not matter)
    analogRead(1);  //switch mux to the next input to charge the mux cap (discard this read)
    ADD0 = ADD0+AD0;  // remember values        
    MAX0 = max (AD0,MAX0);
    MIN0 = min (AD0,MIN0);

    AD1 = analogRead(1);  
    analogRead(8);  // discard the mux cap to stable temp value (+-10 digits do not matter)
    analogRead(2);  //switch mux to the next input to charge the mux cap, discard this read
    etc...
This is much better! The long term AMPLOC sensor zero value precision is really in the range of 0.1 AD digits, that is perfect. Running this loop for all 6 inputs gives me a loop frequency around 260Hz. Not much but at least something with stable values.

Maybe this helps someone. If you have any further suggestions, please keep me posted.
Last edited by pavlii on Tue Sep 24, 2013 1:44 am, edited 1 time in total.

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

Clever solution! Thanks for posting it. This is a problem that comes up often and I'm sure someone will find this helpful.

pavlii
 
Posts: 5
Joined: Sun Sep 22, 2013 5:13 pm

Re: Problem reading two sensors with analogRead()

Post by pavlii »

Maybe it's useless to perform the whole analogRead command, if we want to switch the muxer only. Does anyone know the low level command to switch the muxer only (to another AD input) and not to do the whole ADC read? That would be faster and will reduce power consumption of the atmega.

User avatar
adafruit_support_bill
 
Posts: 88089
Joined: Sat Feb 07, 2009 10:11 am

Re: Problem reading two sensors with analogRead()

Post by adafruit_support_bill »

Here is the source code for analogRead (from wiring_analog.c)

Code: Select all


int analogRead(uint8_t pin)
{
	uint8_t low, high;

#if 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
#elif defined(analogPinToChannel) && (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
	pin = analogPinToChannel(pin);
#else
	if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif
	
#if defined(__AVR_ATmega32U4__)
	pin = analogPinToChannel(pin);
	ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#elif 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)
	ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif

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

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

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

	// we have to read ADCL first; doing so locks both ADCL
	// and ADCH until ADCH is read.  reading ADCL second would
	// cause the results of each conversion to be discarded,
	// as ADCL and ADCH would be locked when it completed.
	low  = ADCL;
	high = ADCH;
#else
	// we dont have an ADC, return 0
	low  = 0;
	high = 0;
#endif

	// combine the two bytes
	return (high << 8) | low;
}
You may find this post useful as well:
http://www.marulaberry.co.za/index.php/ ... duino-adc/

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”