HMP60 temp/humidity sensor integration issues

Hello all! Long time lingerer that finally found a need to ask a question. I am working on a project to put a temp/humidity sensor http://www.vaisala.com/Vaisala%20Documents/Brochures%20and%20Datasheets/HMP60-datasheet-B210851EN-C-LoRes.pdf into a fixed wing UAV for use in atmospheric research. We have the analog version of the sensor as well as a RS-484 connection with drivers installed to get serial data through a terminal. When hooked up in this mode the readings received are very accurate. (Img below)

When I hook up to the arduino, however, the accuracy seems to fall off. It also seems to move in a much less controlled incremental manner. It’s easy to see on the terminal that the temperature and humidity move .01 degrees at a time whereas the serial line outputs a much more sporadic pattern in arduino. I’m wondering if it’s my code (which I have posted below along with the serial monitor) or if I simply need better hardware to make more precise readings. This is my first foray into the realm of exacting readings so I’m not sure what’s needed. I think I’ve read something about ADC upgrades.

Anyway, forgive my ramblings and I appreciate any advice in advance. I just need to know if I need to continue to beat my head against a hardware wall, software wall or both!

Edit: The HMP-60 has an input voltage of 0-1.0V

When you read an analog value with analogRead() on a Arduino Uno board, it is only 10 bits, and the reference is the 5V. The 5V is not accurate when powered with the usb plug.

You can use a power supply for the barrel jack (or to Vin), to have a good 5.0V. Or you can set the voltage reference to an internal reference (independent of the 5V). http://arduino.cc/en/Reference/AnalogReference

void setup(){ Serial.begin(19200); analogReference(INTERNAL); //use AREF for voltage }

I thought that was what that line of code did. Unless I'm completely misunderstanding how to implement it?

Edit: Also, to get a more precise reading should I consider upgrading to something like this? http://www.gravitech.us/i2c128anco.html

It seems that dividing by 4096 instead of 1024 would be quite a jump in precision.

Sorry, I didn't see you already have the internal reference.

When you want 9 or 9-and-a-half bit accuracy with the Arduino, also the hardware must be okay. Perhaps you use a breadboard, or some noise is introduced in the circuit.

Moving from 10 bits to 12 bits is not worth it. Aim for 16 or 24 bits. Before you buy new hardware, try using the average of a few analogRead(). The average of only 5 samples should increase the accuracy a lot.

It seems strange that I am several degrees and several percentage points low on both readings however. I do not have a breadboard. I simply have the hmp60 power going to 5v, ground to ground, channel 1 to A0 and channel2 to A1. Is this the best way to connect this?

Yes, that is the best way.

The internal reference is never 1.10000 Volt. I always have to adjust my calculation for every single Arduino. After that correction the accuracy is good and stays good (with the Arduino always at room temperature). But I also use often the average of 5 to 20 samples.

Forgive me for the naive question, but how do you calculate the actual voltage of that internal reference? A running 5 second average (with 1 reading/sec) has smoothed things out a fair amount. I’m wondering if I should increase the number of samples per second or if my average will be good enough with 1 reading/sec. I definitely find that with the two different hookups (terminal vs serial monitor) that my arduino has a MUCH higher standard deviation (about an average of .1 vs .01).
I’m assuming this has more to do with the ADC than my average? Or is it a possibility I have to up my readings to stablize the output. I suppose it’s entirely possible that the numbers being returned in my terminal are on a much more aggressive averaging process with a higher sampling rate. Any thoughts? I’d be happy to post my spreadsheets if need be.

Answered my own question with the higher sampling rate...It definitely makes for a smoother curve (ran at a delay of 100 ms and used a running average of 10 measurements). I'm wondering how many samples I should take a second while still retaining accurate readings?

I can't tell from here why you have more deviation with the Arduino. It is probably noise in the hardware, like ground current or so. The normal Arduino with the ATmega328p microcontroller has a 10-bit ADC. But it is very hard to achieve 9 or 9-and-a-half bit accuracy. Sometimes a small capacitor of 1nF from analog input to ground will help to remove some noise.

To know the internal reference, I measure the input voltage with an accurate voltage meter, and calculate what the internal reference should be. Then I use that in the calculation in the sketch.

Don't hold back on the average. You can also take 1000 or 10000 samples. But you have to add them up with a long integer.

I am making an attempt at smoothing my data and have been beating my head against a wall for a few hours. I can tell that the problem is obvious with integer division but I can’t for the life of me figuring out where I’ve gone wrong (pardon the commented out code…it’s a bit messy right now. The loop function appears to be working but is only returning integer values.

int reference;
float VIn;

// Define the number of samples to keep track of. The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input. Using a constant rather than a normal variable lets
// use this value to determine the size of the readings array.

const int numReadings = 100; //numbers of readings to take
int readings[numReadings]; //create array for readings
int index = 0; //Create variable for index of current reading
long total = 0.0; //Store the total value of all readings
long average = 0.0; //Average of 100 stored values
int tempPin = A1;

double temperature = 0.0;
int humidityPin = A0;
double humidity = 0.0;
int sensorValueTemp = 0;

void setup(){
Serial.begin(19200);
analogReference(INTERNAL); //use AREF for voltage

//Initialize all readings to zero
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}

void loop() {

//Use the following to find actual Voltage input

//reference = analogRead(14) ;
//VIn = (1.1/reference) * 1023.0;
//Serial.println(VIn);

//Subtract the last reading
total = total - readings[index];

//Read from the temp sensor
sensorValueTemp = analogRead(tempPin);
temperature = ((sensorValueTemp/1024.0) * 100.0 - 40.0);
readings[index] = temperature;

//add the temp reading to the total
total = total + readings[index];

//Move to the next array position
index = index +1;

//Create if statement to determine if all array indexes have been filled

if(index >= numReadings)

//Loop around to zero if this statement is true
index = 0;

//Time to calculate the average
average = total / numReadings;
Serial.println(average);

//int sensorValueRH = analogRead(A0);
//Serial.println(sensorValueRH);
//float humidity = (sensorValueRH/1024.0) * 100.0;
//Serial.println(humidity);

delay(1); //to allow time between readings
}

//Serial.println(sensorValueTemp);

The average is just adding 10 samples and dividing it by 10. You don’t need an array.

This is okay: temperature = ((sensorValueTemp/1024.0) * 100.0 - 40.0);
You can also do this: temperature = (( (float)sensorValueTemp/1024.0) * 100.0 - 40.0);
So the integer of the raw value of analogRead() is forced into a float, and the calculation is done with float and stored in a float.
This is not okay: readings[index] = temperature;
That converts a float (temperature) into an integer (readings).

To get the average of the temperature, you can make a function. That makes the sketch better to read.

float getTemp (int pin)
{
  // 100 samples with 1ms in between.
  // 100 samples won't fit into a 16-bit integer, so an unsigned long is used.

  const int num_samples = 100;
  unsigned long total = 0;       // start with 0
  
  for(i=0; i<num_samples; i++)
  {
    total += analogRead (pin);
    delay(1);
  }
  // calculate voltage at the Arduino pin
  float voltage = (float) (total/num_samples) / 1023.0 * 1.1
  
  // calculate temperature for the HMP60
  float temperature = ( voltage * 100.0 ) - 40.0;
  return (temperature);
}

Thanks a lot for all the help. I’ve stabilized my temperature greatly. It’s actually so stable it hardly ever changes. When hooked up via rs 484, there seems to be a very consistent rolling number (.01 increments at a time) where-as my readings just stay put. They are still a little off (I assume this will be fixed once I figure out the actual reference voltage instead of 1.1000) but my main concern is that the usb plugin seems to a lot more accurate. Do you think this is because of my sampling rate or simply the lack of precision with the Arduino ADC?

Pictures of both outputs are posted below. Again, I really appreciate all of your help. I’d be spinning my tires still if it weren’t for your guidance. I also appreciate that you don’t spoon feed all your answers directly. It has really helped me gain a greater understanding of this project!

The Arduino ADC is indeed not extremely accurate, and you have to adjust the 1.1 in the calculation. But you have it working, so now you can upgrade :P For example an external ADC of 24-bits.

To help from a distance is mostly step by step and hoping it is going somewhere. There are too many possibilities, so I have to get a 'feeling' what could be wrong. For example I have an Arduino Mega that is powered with a prototype shield, and also the sensor is connected to the prototype shield. It turns out that the current used by the Arduino Mega caused the ground of the sensor to lift 15mV. I had to add that 15mV into my calculation to get the right values, since I use the reference of 1.1V. So even if the Arduino Mega ADC is only 10 bits, there are many things that can go wrong.