/* * rht03.c: * Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. * Copyright (c) 2016-2017 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ * * wiringPi is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * wiringPi is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with wiringPi. * If not, see . *********************************************************************** */ #include #include #include #include #include "wiringPi.h" #include "rht03.h" /* * maxDetectLowHighWait: * Wait for a transition from low to high on the bus ********************************************************************************* */ static int maxDetectLowHighWait (const int pin) { struct timeval now, timeOut, timeUp ; // If already high then wait for pin to go low gettimeofday (&now, NULL) ; timerclear (&timeOut) ; timeOut.tv_usec = 1000 ; timeradd (&now, &timeOut, &timeUp) ; while (digitalRead (pin) == HIGH) { gettimeofday (&now, NULL) ; if (timercmp (&now, &timeUp, >)) return FALSE ; } // Wait for it to go HIGH gettimeofday (&now, NULL) ; timerclear (&timeOut) ; timeOut.tv_usec = 1000 ; timeradd (&now, &timeOut, &timeUp) ; while (digitalRead (pin) == LOW) { gettimeofday (&now, NULL) ; if (timercmp (&now, &timeUp, >)) return FALSE ; } return TRUE ; } /* * maxDetectClockByte: * Read in a single byte from the MaxDetect bus ********************************************************************************* */ static unsigned int maxDetectClockByte (const int pin) { unsigned int byte = 0 ; int bit ; for (bit = 0 ; bit < 8 ; ++bit) { if (!maxDetectLowHighWait (pin)) return 0 ; // bit starting now - we need to time it. delayMicroseconds (30) ; byte <<= 1 ; if (digitalRead (pin) == HIGH) // It's a 1 byte |= 1 ; } return byte ; } /* * maxDetectRead: * Read in and return the 4 data bytes from the MaxDetect sensor. * Return TRUE/FALSE depending on the checksum validity ********************************************************************************* */ static int maxDetectRead (const int pin, unsigned char buffer [4]) { int i ; unsigned int checksum ; unsigned char localBuf [5] ; struct timeval now, then, took ; // See how long we took gettimeofday (&then, NULL) ; // Wake up the RHT03 by pulling the data line low, then high // Low for 10mS, high for 40uS. pinMode (pin, OUTPUT) ; digitalWrite (pin, 0) ; delay (10) ; digitalWrite (pin, 1) ; delayMicroseconds (40) ; pinMode (pin, INPUT) ; // Now wait for sensor to pull pin low if (!maxDetectLowHighWait (pin)) return FALSE ; // and read in 5 bytes (40 bits) for (i = 0 ; i < 5 ; ++i) localBuf [i] = maxDetectClockByte (pin) ; checksum = 0 ; for (i = 0 ; i < 4 ; ++i) { buffer [i] = localBuf [i] ; checksum += localBuf [i] ; } checksum &= 0xFF ; // See how long we took gettimeofday (&now, NULL) ; timersub (&now, &then, &took) ; // Total time to do this should be: // 10mS + 40µS - reset // + 80µS + 80µS - sensor doing its low -> high thing // + 40 * (50µS + 27µS (0) or 70µS (1) ) // = 15010µS // so if we take more than that, we've had a scheduling interruption and the // reading is probably bogus. if ((took.tv_sec != 0) || (took.tv_usec > 16000)) return FALSE ; return checksum == localBuf [4] ; } /* * myReadRHT03: * Read the Temperature & Humidity from an RHT03 sensor * Values returned are *10, so 123 is 12.3. ********************************************************************************* */ static int myReadRHT03 (const int pin, int *temp, int *rh) { int result ; unsigned char buffer [4] ; // Read ... result = maxDetectRead (pin, buffer) ; if (!result) return FALSE ; *rh = (buffer [0] * 256 + buffer [1]) ; *temp = (buffer [2] * 256 + buffer [3]) ; if ((*temp & 0x8000) != 0) // Negative { *temp &= 0x7FFF ; *temp = -*temp ; } // Discard obviously bogus readings - the checksum can't detect a 2-bit error // (which does seem to happen - no realtime here) if ((*rh > 999) || (*temp > 800) || (*temp < -400)) return FALSE ; return TRUE ; } /* * myAnalogRead: ********************************************************************************* */ static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) { int piPin = node->fd ; int chan = pin - node->pinBase ; int temp = -9997 ; int rh = -9997 ; int try ; if (chan > 1) return -9999 ; // Bad parameters for (try = 0 ; try < 10 ; ++try) { if (myReadRHT03 (piPin, &temp, &rh)) return chan == 0 ? temp : rh ; } return -9998 ; } /* * rht03Setup: * Create a new instance of an RHT03 temperature sensor. ********************************************************************************* */ int rht03Setup (const int pinBase, const int piPin) { struct wiringPiNodeStruct *node ; if ((piPin & PI_GPIO_MASK) != 0) // Must be an on-board pin return FALSE ; // 2 pins - temperature and humidity node = wiringPiNewNode (pinBase, 2) ; node->fd = piPin ; node->analogRead = myAnalogRead ; return TRUE ; }