 # HIH-4030 Humidity Sensor and Arduino example code?

Look for example code for how to interface with the HIH-4030 Humidity Sensor. http://www.sparkfun.com/commerce/product_info.php?products_id=9569

Did you look at the data sheet for the sensor? The output is nearly linear. That means that reading the ouptut, using analogRead, and mapping it to the correct range is all that is required.

The from range, in the call to map, will depend on the voltage supplied to the sensor, which you will need to measure.

The to range is 0 to 100 to get an output as a percentage.

Easyest way to map if you do linear regressionin excel.
From: http://stevenengineering.com/tech_support/PDFs/31HUM.PDF
You can see that:
at 0C: 0.8V = 0% RH and 4.07V = 100% RH
25C: 0.8V = 0% RH and 3.90V = 100% RH
85C: 0.8V = 0% RH and 3.50V = 100% RH

now 0.8V = 164 when read from analog.read
4.07V = 833 ---------""----------------------
3.90V = 798 ---------""----------------------
3.50V = 716 ---------""----------------------

Now you do scatterplot in excel with known value as x-axis
(That would be the number read from analog in pin)
So: x-axis: analog in expected values y-axis: RH% expected values

For 0C:
%RH = 0,1495x - 24,514 ;where x=analog-in value

For 25C:
%RH = 0,1577x - 25,868

For 85C:
%RH = 0,1812x - 29,71

For any temperature if Temp is known in C:
%RH = ((0,0004*Temp_C + 0,149)Analog_in)-(0,0617Temp_C + 24,436)

Let me know if it is not working David

To read analog signal check out the examples that came with the arduino enviroment: http://www.arduino.cc/en/Serial/Println or here: http://itp.nyu.edu/physcomp/Labs/AnalogIn

You only need to sample the analog pin connected to your sensor put it in a variable use a formula to calculate %RH (seen in previous post) put the calculation in another variable (might be the same step as above) send your variable with %RH to serial or datalogger or watever with a timestamp perhaps.

I have never used this sensor but these steps are logical to take Just shooting from the hip here ;)

Also if your signal is way under 160, then the sensor is not powered or you have faulty connections/sensor, same applies if signal is way over 900

David

ok, working through this. Here is the current code.

``````float val = 0;
float RH = 0;

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

void loop()
{
val = analogRead(0);
delay(500);
Serial.println(val);
RH = ((((val/1023)*5)-0.8)/3.1)*100;
Serial.println(RH);
//RH = ((0,0004*20 + 0,149)*val)-(0,0617*20 + 24,436);
//Serial.println(RH);
delay(500);
}
``````

Now the fun part. Some output.

``````517.00
55.71
519.00
56.02
514.00
55.23
515.00
55.39
515.00
55.39
516.00
55.55
``````

I know I am operating at about 68F (20C). The voltage range is 0.8V to 3.9V. If I offset that by 0.8V (0v to 3.1V) then the math is easy, (V-0.8) / 3.1V = %RH. It happens to agree with my radioshack RH sensor. Thanks for the great input and help!

One final suggestion. This line:

``````  RH = ((((val/1023)*5)-0.8)/3.1)*100;
``````

has a lot of "magic" numbers in it. Some are obvious, such as 1023, 5, and 100. Some are less obvious, like 0.8 and 3.1. You remember today what they mean. Will you remember a year from now?

Add some statements like this at the top of the code:

# define ZeroPercentVoltage 0.8

Then replace 0.8 with ZeroPercentVoltage in the code. The meaning of ZeroPercentVoltage is much more obvious than 0.8.

If you change the sensor with one that has a 0.35V output at 0% it will be easier to see where the code needs to change, too.

Yes, the simplest methd is the easiest to use.!

Comment your code! Its great to have comments when code is shared or for debugging when the code gets to big to remember it all.

I see that i used a comma in stead of period in my calculations so the arduino will probably choke on that ;) (I live in Norway where we use a comma instead of period)

the temperature will probably change in the summer ;) So the 3.1 constant will probably go down if the room is not isolated or temerature regulated.

The max voltage value drops down 0.006705882 for each degree C over 0C. So if you make a varaiable that calculates this:

``````#define ZeroPercentVoltage 0.8;

float val = 0;
float RH = 0;
float my_room_temperature = 20; //in degrees C !
float max_voltage = 3.27;

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

void loop()
{
val = analogRead(0);
delay(500);
Serial.println(val);
my_room_temperature = 20; // If you have temperature reading, put it here (centigrade!)
max_voltage = (3.27-(0.006706*my_room_temperature)) ; // The max voltage value drops down 0.006705882 for each degree C over 0C. The voltage at 0C is 3.27 (corrected for zero precent voltage)
RH = ((((val/1023)*5)-ZeroPercentVoltage)/max_voltage)*100;
Serial.println(RH);
delay(500);
}
``````

This is probably the simplest code for variable temperature :)

Great that your project is comming along, glad to help.

David

You perhaps prefer the numbers in farenheit?

the voltage drop factor is then: 0.00372549 Volt pr. degree farenheit from 32F

``````  max_voltage = (3.27-(0.00372549*my_room_temperature)) ; // The max voltage value drops down 0.00372549 for each degree F over 32F. The voltage at 32F is 3.27 (corrected for zero precent voltage)
RH = ((((val/1023)*5)-ZeroPercentVoltage)/max_voltage)*100;
``````

my_room_temperature is then in farenheit NOT celsius

David

Of course, now you need a way to measure the room temperature, if you are going to compute max_voltage as a function of actual room temperature.

If it is to be calculated on a set temperature, it should be computed once, in setup, not every time the RH is checked.

As the relative humidty is a function of temperature and pressure, the sensor is not accurate without a temperature reading, but as you say if the temperature does not swing more than a few degrees, that accuracy is less than the accuracy of the %RH meter and can just be set as a constant outside of the loop. (@PaulS, you're absolutly right if he does not take temp readings!) :P

That said if you know the temperature and %RH you can calculate the partial vapour pressure of the water and the pressure in the atmosphere.

The dewpoint can aslo be calculated and using Humidex http://en.wikipedia.org/wiki/Humidex , one can calculate what temperature it "feels" like.

So the program could output: It's 78F inside but feels like 90F because the humidity is XX%

David

I love the DS18B20.

``````#include
OneWire  ds(7);  // on pin 10
float val = 0;
float RH = 0;
float my_room_temperature = 20; //in degrees C !
float max_voltage = 3.27;
float ZeroPercentVoltage = 0.8;

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

void loop(void) {
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
float temp = 0;
byte i;
byte present = 0;
byte data;
byte addr;

if ( !ds.search(addr)) {
//Serial.print("No more addresses.\n");
ds.reset_search();
delay(250);
return;
}

/*Serial.print("R=");
for( i = 0; i < 8; i++) {
Serial.print(addr[i], HEX);
Serial.print(" ");
}*/

if ( OneWire::crc8( addr, 7) != addr) {
Serial.print("CRC is not valid!\n");
return;
}

if ( addr != 0x28) {
Serial.print("Device is not a DS18B20 family device.\n");
return;
}

// The DallasTemperature library can do all this work for you!

ds.reset();
ds.select(addr);
ds.write(0x44,1);         // start conversion, with parasite power on at the end

delay(1000);     // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE);         // Read Scratchpad

/*Serial.print("P=");
Serial.print(present,HEX);
Serial.print(" ");*/

for ( i = 0; i < 9; i++) {           // we need 9 bytes
data[i] = ds.read();
//Serial.print(data[i], HEX);
//Serial.print(" ");
}

LowByte = data;
HighByte = data;
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000;  // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
temp = (Tc_100*.01*1.8)+32;
Serial.print("Temp in F: ");
Serial.println(temp);

val = analogRead(0);
delay(500);
Serial.println(val);
my_room_temperature = Tc_100*.01; // If you have temperature reading, put it here (centigrade!)
max_voltage = (3.27-(0.006706*my_room_temperature)); // The max voltage value drops down 0.006705882 for each degree C over 0C. The voltage at 0C is 3.27 (corrected for zero precent voltage)
RH = ((((val/1023)*5)-ZeroPercentVoltage)/max_voltage)*100;
Serial.println(RH);
delay(500);
}
``````

Output

``````Temp in F: 72.82
547.00
60.09
Temp in F: 72.82
548.00
60.25
Temp in F: 72.82
545.00
59.78
Temp in F: 72.82
547.00
60.09
Temp in F: 72.82
544.00
59.62
``````

More to come later. I need to break this thing into function, its far to ugly. And I will also comment the code, so I know what I was doing :-)

as the Dallas one wire uses the temp variable, you can just loose the my_room_temperature variable and use the farenheit equation so the code becomes:

``````#include
#include
OneWire  ds(7);  // on pin 10
float val = 0;
float RH = 0;
float max_voltage = 3.27;
float ZeroPercentVoltage = 0.8;

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

void loop(void) {
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
float temp = 0;
float dewpoint = 0;
float humidex = 0;
byte i;
byte present = 0;
byte data;
byte addr;

if ( !ds.search(addr)) {
//Serial.print("No more addresses.\n");
ds.reset_search();
delay(250);
return;
}

/*Serial.print("R=");
for( i = 0; i < 8; i++) {
Serial.print(addr[i], HEX);
Serial.print(" ");
}*/

if ( OneWire::crc8( addr, 7) != addr) {
Serial.print("CRC is not valid!\n");
return;
}

if ( addr != 0x28) {
Serial.print("Device is not a DS18B20 family device.\n");
return;
}

// The DallasTemperature library can do all this work for you!

ds.reset();
ds.select(addr);
ds.write(0x44,1);         // start conversion, with parasite power on at the end

delay(1000);     // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE);         // Read Scratchpad

/*Serial.print("P=");
Serial.print(present,HEX);
Serial.print(" ");*/

for ( i = 0; i < 9; i++) {           // we need 9 bytes
data[i] = ds.read();
//Serial.print(data[i], HEX);
//Serial.print(" ");
}

LowByte = data;
HighByte = data;
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000;  // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
temp = (Tc_100*.01*1.8)+32;
Serial.print("Temp in F: ");
Serial.println(temp);

val = analogRead(0);
delay(500);
Serial.println(val);
max_voltage = (3.27-(0.00372549*temp)) ; // The max voltage value drops down 0.00372549 for each degree F over 32F. The voltage at 32F is 3.27 (corrected for zero precent voltage)
RH = ((((val/1023)*5)-ZeroPercentVoltage)/max_voltage)*100;
Serial.println(RH);
// for dewpoint see: http://en.wikipedia.org/wiki/Dew_point
dewpoint = (237,7*(17.271*((temp-32)*5/9))/(237.7+*((temp-32)*5/9)+log(RH/100))/(17.271-(17.271*((temp-32)*5/9))/(237.7+*((temp-32)*5/9)+(log(RH/100))); // the numbers are constants, RH =relative humidity, temperature must be in C
Serial.print("Dewpoint: ");
Serial.println(dewpoint);
// for humidex see: http://en.wikipedia.org/wiki/Humidex
humidex = ((temp-32)*5/9(0.5555*(6.11*exp(5417.7530*((1/273.16)-(1/(273.16+dewpoint))))-10)); // apparent temp in C
Serial.print("Apparent temperature: ");
Serial.println(humidex*(9/5)+32); // apparent temp in F
delay(500);
}
``````

Added Dewpoint and Humidex to your code ;)

Not tested code, do not have the hardware :P

David.

Does anyone have an example of wiring to a one-wire DS18b20 and the HIH-4039 humidity sensor on the arduino. I have the code which should work, but can't figure out how to wire on breadboard. Thanks for the help.