Permalink
Browse files

Wireless Arduino temperature sensor

  • Loading branch information...
drbrain committed Aug 30, 2011
0 parents commit d32203d6cb3b42f7e14293f1d0fe73cbcf1142b4
Showing with 622 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +243 −0 DHT22.cpp
  3. +37 −0 DHT22.h
  4. +42 −0 README.rdoc
  5. +71 −0 temperature_monitor.pde
  6. +12 −0 watch.rb
  7. +216 −0 xbee_modem_setup.rb
@@ -0,0 +1 @@
+*.swp
243 DHT22.cpp
@@ -0,0 +1,243 @@
+/*
+ DHT22.cpp - DHT22 sensor library
+ Developed by Ben Adams - 2011
+ Original source: https://github.com/nethoncho/Arduino-DHT22
+
+ This library 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 2.1 of the License, or (at your option) any later version.
+
+ This library 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 this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Humidity and Temperature Sensor DHT22 info found at
+http://www.sparkfun.com/products/10167
+
+Version 0.4: 24-Jan-2011 by Ben Adams
+Added return code constants to keywords.txt
+Returns DHT_ERROR_CHECKSUM on check sum mismatch
+
+Version 0.3: 17-Jan-2011 by Ben Adams
+This version reads data
+Needs check sum code added at the end of readData
+
+Version 0.2: 16-Jan-2011 by Ben Adams
+Changed coding style to match other Arduino libraries.
+This version will not read data either!
+
+Version 0.1: 10-Jan-2011 by Ben Adams nethoncho AT gmail.com
+First Version is a skeleton. This version will not read data!
+Code adapted from the following sources:
+The Arduino OneWire lib
+http://sheepdogguides.com/arduino/ar3ne1humDHT11.htm
+
+*/
+
+#include "DHT22.h"
+#include "pins_arduino.h"
+
+extern "C" {
+#include "WConstants.h"
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+}
+
+#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
+#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask))
+#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask))
+#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask))
+//#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask))
+
+// This should be 40, but the sensor is adding an extra bit at the start
+#define DHT22_DATA_BIT_COUNT 41
+
+DHT22::DHT22(uint8_t pin)
+{
+ _bitmask = digitalPinToBitMask(pin);
+ _baseReg = portInputRegister(digitalPinToPort(pin));
+ _lastReadTime = millis();
+ _lastHumidity = DHT22_ERROR_VALUE;
+ _lastTemperature = DHT22_ERROR_VALUE;
+}
+
+//
+// Read the 40 bit data stream from the DHT 22
+// Store the results in private member data to be read by public member functions
+//
+DHT22_ERROR_t DHT22::readData()
+{
+ uint8_t bitmask = _bitmask;
+ volatile uint8_t *reg asm("r30") = _baseReg;
+ uint8_t retryCount;
+ uint8_t bitTimes[DHT22_DATA_BIT_COUNT];
+ int currentHumidity;
+ int currentTemperature;
+ uint8_t checkSum, csPart1, csPart2, csPart3, csPart4;
+ unsigned long currentTime;
+ int i;
+
+ currentHumidity = 0;
+ currentTemperature = 0;
+ checkSum = 0;
+ currentTime = millis();
+ for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
+ {
+ bitTimes[i] = 0;
+ }
+
+ if(currentTime - _lastReadTime < 2000)
+ {
+ // Caller needs to wait 2 seconds between each call to readData
+ return DHT_ERROR_TOOQUICK;
+ }
+ _lastReadTime = currentTime;
+
+ // Pin needs to start HIGH, wait until it is HIGH with a timeout
+ cli();
+ DIRECT_MODE_INPUT(reg, bitmask);
+ sei();
+ retryCount = 0;
+ do
+ {
+ if (retryCount > 125)
+ {
+ return DHT_BUS_HUNG;
+ }
+ retryCount++;
+ delayMicroseconds(2);
+ } while(!DIRECT_READ(reg, bitmask));
+ // Send the activate pulse
+ cli();
+ DIRECT_WRITE_LOW(reg, bitmask);
+ DIRECT_MODE_OUTPUT(reg, bitmask); // Output Low
+ sei();
+ delayMicroseconds(1100); // 1.1 ms
+ cli();
+ DIRECT_MODE_INPUT(reg, bitmask); // Switch back to input so pin can float
+ sei();
+ // Find the start of the ACK Pulse
+ retryCount = 0;
+ do
+ {
+ if (retryCount > 25) //(Spec is 20 to 40 us, 25*2 == 50 us)
+ {
+ return DHT_ERROR_NOT_PRESENT;
+ }
+ retryCount++;
+ delayMicroseconds(2);
+ } while(!DIRECT_READ(reg, bitmask));
+ // Find the end of the ACK Pulse
+ retryCount = 0;
+ do
+ {
+ if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+ {
+ return DHT_ERROR_ACK_TOO_LONG;
+ }
+ retryCount++;
+ delayMicroseconds(2);
+ } while(DIRECT_READ(reg, bitmask));
+ // Read the 40 bit data stream
+ for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
+ {
+ // Find the start of the sync pulse
+ retryCount = 0;
+ do
+ {
+ if (retryCount > 35) //(Spec is 50 us, 35*2 == 70 us)
+ {
+ return DHT_ERROR_SYNC_TIMEOUT;
+ }
+ retryCount++;
+ delayMicroseconds(2);
+ } while(!DIRECT_READ(reg, bitmask));
+ // Measure the width of the data pulse
+ retryCount = 0;
+ do
+ {
+ if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+ {
+ return DHT_ERROR_DATA_TIMEOUT;
+ }
+ retryCount++;
+ delayMicroseconds(2);
+ } while(DIRECT_READ(reg, bitmask));
+ bitTimes[i] = retryCount;
+ }
+ // Now bitTimes have the number of retries (us *2)
+ // that were needed to find the end of each data bit
+ // Spec: 0 is 26 to 28 us
+ // Spec: 1 is 70 us
+ // bitTimes[x] <= 11 is a 0
+ // bitTimes[x] > 11 is a 1
+ // Note: the bits are offset by one from the data sheet, not sure why
+ for(i = 0; i < 16; i++)
+ {
+ if(bitTimes[i + 1] > 11)
+ {
+ currentHumidity |= (1 << (15 - i));
+ }
+ }
+ for(i = 0; i < 16; i++)
+ {
+ if(bitTimes[i + 17] > 11)
+ {
+ currentTemperature |= (1 << (15 - i));
+ }
+ }
+ for(i = 0; i < 8; i++)
+ {
+ if(bitTimes[i + 33] > 11)
+ {
+ checkSum |= (1 << (7 - i));
+ }
+ }
+
+ _lastHumidity = currentHumidity & 0x7FFF;
+ if(currentTemperature & 0x8000)
+ {
+ // Below zero, non standard way of encoding negative numbers!
+ currentTemperature &= 0x7FFF;
+ _lastTemperature = currentTemperature * -1;
+ }
+ else
+ {
+ _lastTemperature = currentTemperature;
+ }
+
+ csPart1 = currentHumidity >> 8;
+ csPart2 = currentHumidity & 0xFF;
+ csPart3 = currentTemperature >> 8;
+ csPart4 = currentTemperature & 0xFF;
+ if(checkSum == ((csPart1 + csPart2 + csPart3 + csPart4) & 0xFF))
+ {
+ return DHT_ERROR_NONE;
+ }
+ return DHT_ERROR_CHECKSUM;
+}
+
+int DHT22::getHumidity()
+{
+ return _lastHumidity;
+}
+
+int DHT22::getTemperatureC()
+{
+ return _lastTemperature;
+}
+
+//
+// This is used when the millis clock rolls over to zero
+//
+void DHT22::clockReset()
+{
+ _lastReadTime = millis();
+}
37 DHT22.h
@@ -0,0 +1,37 @@
+#ifndef _DHT22_H_
+#define _DHT22_H_
+
+#include <inttypes.h>
+
+#define DHT22_ERROR_VALUE -99.5
+
+typedef enum
+{
+ DHT_ERROR_NONE = 0,
+ DHT_BUS_HUNG,
+ DHT_ERROR_NOT_PRESENT,
+ DHT_ERROR_ACK_TOO_LONG,
+ DHT_ERROR_SYNC_TIMEOUT,
+ DHT_ERROR_DATA_TIMEOUT,
+ DHT_ERROR_CHECKSUM,
+ DHT_ERROR_TOOQUICK
+} DHT22_ERROR_t;
+
+class DHT22
+{
+ private:
+ uint8_t _bitmask;
+ volatile uint8_t *_baseReg;
+ unsigned long _lastReadTime;
+ double _lastHumidity;
+ double _lastTemperature;
+
+ public:
+ DHT22(uint8_t pin);
+ DHT22_ERROR_t readData(void);
+ int getHumidity();
+ int getTemperatureC();
+ void clockReset();
+};
+
+#endif /*_DHT22_H_*/
@@ -0,0 +1,42 @@
+= Arduino + DHT22 + XBee Temperature Monitor
+
+This project allows you to monitor the temperature remotely. The hardware used
+in this project includes:
+
+* {Arduino Uno}[http://www.sparkfun.com/products/10356]
+* {DHT22 Humidity & Temperature Sensor}[http://www.sparkfun.com/products/10167]
+* Two {XBees}[http://www.sparkfun.com/products/8664]
+* One {XBee Explorer}[http://www.sparkfun.com/products/8687]
+* One {XBee Adapter Kit}[http://www.adafruit.com/products/126]
+* {Jumper wires}[http://www.sparkfun.com/products/9387]
+* One {Breadboard}[http://www.sparkfun.com/products/137]
+
+The XBee Adapter Kit was my first soldering attempt and I'm told I did a great
+job. A PanaVise Junior and a Third Hand helped immensely, along with choosing
+a 1/64 inch soldering iron tip over the 1/32" tip that came with my soldering
+iron.
+
+I also cut three jumper wires, stripped them and soldered them to the DHT22.
+This was more difficult, but placing the sensor in the vise and using the Third
+Hand to hold the wire with a folded up piece of paper to protect the insulation
+helped line everything up.
+
+I attached the XBee Adapter to the breadboard and wired up 5V power and ground.
+I attached the TX pin of the adapter to digital pin 2 of the Arduino and the RX
+pin of the adapter to digital pin 3 of the Arduino. I attached the sensor's
+data pin to port 7 (from the {DHT22
+source}[https://github.com/nethoncho/Arduino-DHT22]) and the ground and power
+to the proper pins on the breadboard.
+
+The xbee_mode_setup.rb script was used to set up the to XBees to communicate with each other. Be sure to use the Arduino XBee's serial number as the destination address of the XBee Explorer and vice versa.
+
+The watch.rb script can be used to monitor the temperature the Arduino reads.
+
+Excluding the cost of the soldering equipment, this project cost under $150.
+
+Most of the software used in this project was already written by third-parties
+that I adapted to my needs. The DHT22 library was changed from returning float
+to int (that I can decode on the ruby side). xbee_mode_setup.rb was updated to
+work with a newer serialport gem for ruby and the documentation was
+reformatted.
+
@@ -0,0 +1,71 @@
+#include <SoftwareSerial.h>
+#include "DHT22.h"
+
+#define XBee_rx_PIN 2
+#define XBee_tx_PIN 3
+#define DHT22_PIN 7
+#define interval 2
+
+DHT22 temp_sensor(DHT22_PIN);
+SoftwareSerial XBee(XBee_rx_PIN, XBee_tx_PIN);
+
+void setup(void)
+{
+ pinMode(XBee_rx_PIN, INPUT);
+ pinMode(XBee_tx_PIN, OUTPUT);
+
+ XBee.begin(9600);
+
+ Serial.begin(9600);
+}
+
+void loop(void)
+{
+ DHT22_ERROR_t errorCode;
+ char out[40] = "";
+
+ delay(interval * 1000);
+ errorCode = temp_sensor.readData();
+ switch(errorCode)
+ {
+ case DHT_ERROR_NONE:
+ snprintf(out, 40, "%5iC %5i%%",
+ temp_sensor.getTemperatureC(), temp_sensor.getHumidity());
+
+ Serial.println(out);
+ XBee.println(out);
+ break;
+ case DHT_ERROR_CHECKSUM:
+ snprintf(out, 40, "check sum error %5iC %5i%%",
+ temp_sensor.getTemperatureC(), temp_sensor.getHumidity());
+
+ Serial.println(out);
+ XBee.println(out);
+ break;
+ case DHT_BUS_HUNG:
+ Serial.println("BUS Hung");
+ XBee.println("BUS Hung");
+ break;
+ case DHT_ERROR_NOT_PRESENT:
+ Serial.println("Not Present");
+ XBee.println("Not Present");
+ break;
+ case DHT_ERROR_ACK_TOO_LONG:
+ Serial.println("ACK timeout");
+ XBee.println("ACK timeout");
+ break;
+ case DHT_ERROR_SYNC_TIMEOUT:
+ Serial.println("Sync Timeout");
+ XBee.println("Sync Timeout");
+ break;
+ case DHT_ERROR_DATA_TIMEOUT:
+ Serial.println("Data Timeout");
+ XBee.println("Data Timeout");
+ break;
+ case DHT_ERROR_TOOQUICK:
+ Serial.println("Polled too quick");
+ XBee.println("Polled too quick");
+ break;
+ }
+}
+
Oops, something went wrong.

0 comments on commit d32203d

Please sign in to comment.