The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
Humidity and Temperature Sensor Driver HIH6130 I2C
This was my excuse to learn more about I2C and bitwise operations on the Netduino. To that end, this is my first attempt at a driver for the HIH6130 sensor. Not only will this driver give you accurate temperature and humidity readings, but can also give you the calculated heat index!
Further, if you optionally connect the VDD to a digital pin, the driver is capable of putting the sensor into command mode for reading and writing to the EEPROM and configuring the sensor settings. The sensor also provides optional high and low humidity alarm pins, which are fully configurable through the driver, and use event handlers to trigger whenever the alarm state changes.
Here's an example how the driver is used:
public class Program
{
private static HIH6130 sensor;
public static void Main()
{
//Create the sensor
sensor = new HIH6130(0x27, power: Pins.GPIO_PIN_D0, AL_H: Pins.GPIO_PIN_D1);
//Enter command mode
sensor.enterCommandMode();
//Read the current sensor configuration
byte[] config = new byte[3];
sensor.readEEPROM(HIH6130.EEPROM.Cust_Config, config);
//Write some random data to the custom storage EEPROM
byte[] data = new byte[] { 0x20, 0x2F };
sensor.writeCustomROM(data, 2);
//Read the custom data
byte[] custom = new byte[3];
sensor.readEEPROM(HIH6130.EEPROM.Cust_ID2, custom);
//Set the high humidity alarm
sensor.setAlarmHigh(80, 75);
//Exit command mode
sensor.exitCommandMode(true);
//Attach a high alarm event
sensor.highAlarmEvent += sensor_highAlarmEvent;
while (true)
{
//Take a measurement. Note: The alarm will only trigger after a measurement, so we need to keep taking measurements
sensor.takeMeasurement();
Debug.Print("Temperature: " + sensor.tempC.ToString("f") + "\nHumidity: " + sensor.hum.ToString("f") + "%\nHeat index: " + sensor.heatIndexC.ToString("f"));
Thread.Sleep(60000);
}
}
static void sensor_highAlarmEvent(object sender, HIH6130.AlarmArgs e)
{
Debug.Print("The alarm temperature is: " + e.TempC.ToString("f") + "\nThe alarm humidity is: " + e.hum.ToString("f") + "\nThe alarm pin state is: " + e.state.ToString());
}
}
Anyway, the driver is attached below, any suggestions are more than welcome. If you have any questions, let me know, and enjoy! HIH6130.cs20.31KB43 downloads
I think the support is tricky enough that I chose specifically not to try to use one, and have been looking for something else. While I think $30 is a lot I'll likely get one, as it's SO much less code/load on the board to get R/H.
Also, I took a peak, nice commenting within and good explanation of everything, it's much appreciated by the community!!
suggestion:
remove the sensor.enterCommandMode(); and sensor.exitCommandMode(true); for the user.
make it automatically if you call the functions that wants command mode.
That's an interesting suggestion. The only reason I would hesitate is that the sensor needs to reboot upon leaving command mode or before entering command mode, so if you wanted to pass several commands one after another (say, to set the high and low alarms and write some custom data to the EEPROM) the sensor would powercycle between each command twice (once to enter command mode, once to leave command mode after the first command, again to enter command mode for the second command, etc…). Doing that seems a bit inefficient, and would require some code to make sure the sensor has powered back on before doing anything. A simple Thread.Sleep(250) would probably work, but would slow things down. I should point out the reason I make it optional to reboot when leaving command mode is that the reboot is only necessary to make changes to the EEPROM take effect, so you could leave command mode and enter normal operation without rebooting, and then reboot later to have the changes take effect.
I think the support is tricky enough that I chose specifically not to try to use one, and have been looking for something else. While I think $30 is a lot I'll likely get one, as it's SO much less code/load on the board to get R/H.
Those were my thoughts exactly. Looking through the DHT thread made it seem very complicated and unreliable, having to implement tweaks like:
Due to the resolution of Netduino system timer which is not enough to precisely measure duration of sensor pulses, it may happen that the sensor readout fails due to invalid checksum, usually for specific values of RH or temperature. You could either ignore that or try tuning BitThreshold value in DhtSensor.cs
I needed something very reliable and simple, as I was using it to control appliances in my home, and could rack up quite the electricity bill if something went wrong. Also, I2C easily allows for multiple sensors, and of course has all the extra features like EEPROM storage and programmable humidity alarms.
Thanks a bunch for posting HIH6130.cs. I would have gotten nowhere without it.
As a disclaimer, I have no formal programming experience and still can't fully explain the bit shifting stuff. However, please correct me if I am wrong, but in the function takeMeasurement() shouldn't line:
The difference being a left shift of 8 rather than 6. If I shift 6, the RH is only in the mid teens. If I shift 8 similar to the arduino code out there, I get a more reasonable RH = 60 for my region.
I am using the SparkFun breakout board and tested it with an arduino as well. I also sliced up your code and some arduino code so I could see everything at a glance for testing...
public class Program { static I2CDevice sensor; static Double hum; static Double temp; static String status; public static void Main() { //0x27 is the default address of the HIH6130. sensor = new I2CDevice(new I2CDevice.Configuration((Byte)0x27, 300)); while (true) { takeMeasurements(); Debug.Print("Device state: " + status); Debug.Print("Temperature = " + temp.ToString()); Debug.Print("Relative humidity = " + hum.ToString()); Debug.Print(string.Empty); Thread.Sleep(3000); } } public static void takeMeasurements() { //Byte buffer to hold device output. byte[] readBuffer = new byte[4]; //Send temp/hum request to HIH6130. sensor.Execute(new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(new byte[] { (byte)0x00 }) }, 1000); //Give it a moment to record reading in device. Thread.Sleep(100); //Read device reading. sensor.Execute(new I2CDevice.I2CTransaction[] { I2CDevice.CreateReadTransaction(readBuffer) }, 1000); //http://www.phanderson.com/arduino/I2CCommunications.pdf (see fig. 4) byte hhigh = readBuffer[0]; byte hlow = readBuffer[1]; byte thigh = readBuffer[2]; byte tlow = readBuffer[3]; //// Slice of state bytes byte state = (Byte)((hhigh >> 6) & (Byte)0x03); // Clean up remaining humidity bytes hhigh = (Byte)(hhigh & (Byte)0x3f); // Shift humidity bytes into a value // Convert value to humidity per data sheet float hdata = (((uint)hhigh) << 8) | hlow; hdata = (float)(hdata * 6.10e-3); // Shift temperature bytes into a value // Convert value to temperature per data sheet float tdata = (((uint)thigh) << 8) | tlow; tdata = tdata / 4; tdata = (float)(tdata * 1.007e-2 - 40.0); //Set variables for debug in Main. switch (state) { case 0: status = "normal"; break; case 1: status = "stale data"; break; case 2: status = "command mode"; break; default: status = "diagnostic"; break; } temp = ((tdata * 9) / 5 + 32); hum = hdata; } }
Honestly, I've had a tough time getting my head around bit shifting in conjunction with the "|" operator and am just posting the code in case you see that I'm doing something wrong...
But, in my tests the bit shift of 6 generates a relative humidity in the teens. If I shift it 8 then I get a more realistic measurement of around 60. A couple of Arduino examples for this sensor also shift 8 bits. Is there something I'm missing?
Thanks for posting the HIH6130.cs. I couldn't have gotten my sensor to work without this code. I do have one question though. In the takeMeasurement method you have:
Shouldn't it be a left bit shift of 8, not 6? I'm still getting my head around bit shifts. I am basing my question off of arduino code I've seen for this sensor and the fact that if I use a shift of 6 my RH value is in the teens, but if I use 8 I get a more reasonable value.
I'm glad you found my code useful, and I think you're perfectly right that there is an error with that line. It seems like I, rather absentmindedly, used the same shift for the humidity as for the temperature (d'oh!). The line should read:
I'm pretty new to bit shifts myself, so I'd be happy to go over in more detail what each operation is doing with the sensor data if you'd like. As is evident here, a second pair of eyes really helps to find mistakes.
In any case, I've updated the driver with the correct line and reattached it to my first post. I admit, I don't have a separate humidity meter so I can't double check the values, but this should work, though I'd love for someone to verify that with a a proper humidity meter.
Thanks for your help catching that mistake, and I'd love to know about the project you're working on!
Hey ShVerni, thanks for sharing your code, this looks like exactly what I need. I tried DHT11 and could not get this to work at all, though it works perfectly on my Arduinos, and the whole approach seems very unreliable. I will probably pick up the sensor to play with.
You don't need to connect VDD to a digital output pin, and could instead connect directly to 3.3V on the Neduino, however doing so would preclude you from entering command mode on the sensor. You can also use any GPIO you want for VDD, of course, not just D0.
You will also need pull-up resistors on the SDA and SCL lines. I use two 1.6k resistors, but anything between 1k-3k would probably work.