40: C++ map() function vs. the HIH-4030 Humidity Sensor
-- revised 5/22/2016 --
-- re-revised5/25/2016 --
-- revised 5/22/2016 --
-- re-revised5/25/2016 --
So I got my expensive HIH sensor (explained in post 39).
tiny, isn't it
According to Honeywell's graph there is a straight line relationship between voltage output (at 5v, 20C) and relative humidity. I.e., 0.8v = 0% to 3.75v = 100%.
So I wrote this Arduino sketch:
=============
#define spr(x) Serial.print(x) // because I'm a slow typist
#define spl(x) Serial.println(x) // " "
void setup() {
pinMode(A1, INPUT);
Serial.begin(9600);
delay(5000);
spl("HIH-4030");
}
void loop() {
int r = analogRead(A1);
spr("raw: ");spr(r);
float v = r * (5.0 / 1023.0);
spr(", V: ");spr(v);
float rh = map(v, 0.8,3.75, 0.01,100.0);
spr(", rh%: ");spl(rh);
delay(5000);
}
============
This produced the following output (from Mac Coolterm):
============
raw: 297, V: 1.45, rh%: 33.00
raw: 305, V: 1.49, rh%: 33.00
raw: 289, V: 1.41, rh%: 33.00
raw: 224, V: 1.09, rh%: 33.00
raw: 651, V: 3.18, rh%: 100.00 *
raw: 526, V: 2.57, rh%: 66.00
raw: 367, V: 1.79, rh%: 33.00
raw: 322, V: 1.57, rh%: 33.00
raw: 291, V: 1.42, rh%: 33.00
raw: 278, V: 1.36, rh%: 33.00
============ * I breathed on the sensor
The "33", "66", etc. made me suspect that while the C++ map() function happily accepts float arguments, it treats them as integers. So I wrote my own float version:
============
#define spr(x) Serial.print(x)
#define spl(x) Serial.println(x)
float mapf(float value, float istart, float istop, float ostart, float ostop) {
return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
}
void setup() {
pinMode(A1, INPUT);
Serial.begin(9600);
delay(5000);
spl("HIH-4030");
}
void loop() {
int r = analogRead(A1);
spr("raw: ");spr(r);
float v = r * (5.0 / 1023.0);
spr(", V: ");spr(v);
float rh = mapf(v, 0.8,3.75, 0.0,100.0);
spr(", rh%: ");spl(int(rh));
delay(5000);
}
============
Here's the "mapf()" output:
============
raw: 295, V: 1.44, rh%: 25
raw: 294, V: 1.44, rh%: 24
raw: 293, V: 1.43, rh%: 24
raw: 318, V: 1.55, rh%: 29
raw: 449, V: 2.19, rh%: 52 *
raw: 378, V: 1.85, rh%: 39
raw: 306, V: 1.50, rh%: 27
raw: 293, V: 1.43, rh%: 24
raw: 291, V: 1.42, rh%: 24
============ * hot breath, again
Nasty! I wonder whether the provided map() code protects against divide-by-zero? It could happen.
Now I just have to worry about why my HIH-4030 values are screwy -- readings around my house are in the 40s, at the moment.
Later: Then I moved the program to the Particle Photon. The only source change was for the 12-bit analog return (4095 instead of 1023). The Particle C++ map() function bug ("feature") was the same. But, for some reason the results were correct!
============ code:
#define spr(x) Serial.print(x)
#define spl(x) Serial.println(x)
// sensor to Photon: 5v to Vin, 0v to A1, GND to GND
float mapf(float value, float istart, float istop, float ostart, float ostop) {
return ostart + (ostop-ostart) * ((value-istart) / (istop-istart));
}
void setup() {
pinMode(A1, INPUT);
Serial.begin(9600);
delay(5000);
spl("HIH-4030");
}
void loop() {
int r = analogRead(A1);
spr("raw: ");spr(r);
float v = r * (5.0 / 4095.0);
spr(", V: ");spr(v);
float rh = mapf(v, 0.8,3.75, 0.0,100.0);
spr(", rh%: ");spl(int(rh));
delay(5000);
}
============ ok results?
rawh: 1674, V: 2.04, rh%: 42
rawh: 1576, V: 1.92, rh%: 38
rawh: 1607, V: 1.96, rh%: 39
rawh: 1562, V: 1.91, rh%: 37
============
Finally, about the HIH readings: they vary a lot between samples so my latest code reports a weighted running average -- 3 previous readings and the latest one doubled.
Revision: I soldered the tiny board to wires -- trying to keep from frying it in the process. I found new software on Github. Now the Arduino is right (seemingly) and the Photon is too high*. The HIH-4030 is a pain. The mounting board should be bigger just to protect the sensor part.
* Because the Photon analog pins are only rated for 3.3v. It's in their Docs -- but not obvious. Forget my code. Use the more accurate code from github.
No comments:
Post a Comment