/* * maxdetect.c: * Driver for the MaxDetect series sensors * * Copyright (c) 2013 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 #include "maxdetect.h" #ifndef TRUE # define TRUE (1==1) # define FALSE (1==2) #endif /* * 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 ********************************************************************************* */ 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] ; } /* * readRHT03: * Read the Temperature & Humidity from an RHT03 sensor * Values returned are *10, so 123 is 12.3. ********************************************************************************* */ int readRHT03 (const int pin, int *temp, int *rh) { static struct timeval then ; // will initialise to zero static int lastTemp = 0 ; static int lastRh = 0 ; int result ; struct timeval now, timeOut ; unsigned char buffer [4] ; // The data sheets say to not read more than once every 2 seconds, so you // get the last good reading gettimeofday (&now, NULL) ; if (timercmp (&now, &then, <)) { *rh = lastRh ; *temp = lastTemp ; return TRUE ; } // Set timeout for next read gettimeofday (&now, NULL) ; timerclear (&timeOut) ; timeOut.tv_sec = 2 ; timeradd (&now, &timeOut, &then) ; // Read ... result = maxDetectRead (pin, buffer) ; if (!result) // Try again, but just once 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 ; lastRh = *rh ; lastTemp = *temp ; return TRUE ; }