239 lines
5.5 KiB
C
239 lines
5.5 KiB
C
|
/*
|
||
|
* 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 ;
|
||
|
}
|