You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.5 KiB
238 lines
5.5 KiB
/* |
|
* 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 <http://www.gnu.org/licenses/>. |
|
*********************************************************************** |
|
*/ |
|
|
|
#include <sys/time.h> |
|
#include <stdio.h> |
|
//#include <stdlib.h> |
|
//#include <unistd.h> |
|
|
|
#include <wiringPi.h> |
|
|
|
#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 ; |
|
}
|
|
|