Arduino, DHT22, Webserver

This was so far the most difficult Arduino project I’ve had to do so far. The goal was simple display some sensor data from a DHT22 temperature and humidity sensor. The code presented a number of problems. You can read the full run down how we got the working code here. The original code for this project was taken from Peter Oakes at this site.


You will find the code here:

#include <SPI.h>  
#include <Wire.h>  
#include <Ethernet.h>  
//#include <UIPEthernet.h>  
#include <DHT.h>  
#include <stdio.h>

#define DHTTYPE DHT22
#define DHTPIN 2

DHT dht(DHTPIN, DHT22);

float combined_temp_C;  
float combined_temp_F;  //create a new variable  
byte TempHi;              // Variable hold data high byte  
byte TempLo;              // Variable hold data low byte  
boolean P_N;              // Bit flag for Positive and Negative  
boolean P_N112;  
boolean P_N212;  
unsigned int Decimal;     // Variable hold decimal value  
char * strTempC = NULL;  
char * strTempF = NULL;  
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x00, 0x4E, 0x10 };  // MAC address 84.85.88.16.0.36  
byte ip[]  = { 
  192, 168, 1, 20 };                     // ip-address, please change to fit your network  
byte mydns[] = { 
  192, 168, 1, 1 };              
byte gateway[] = { 
  192, 168, 1, 1 };               
byte subnet[] = { 
  255,255,255,0 };   
EthernetServer server(8080);  
static char output[300] = "";  



char headerHTML[] = "HTTP/1.1 200 OK\r\n"  
"Content-Type: text/html\r\n"  
"Connection: close\r\n"  
"Refresh: 5\r\n"  
"\r\n"  
"<!DOCTYPE HTML>"  
"<Title>Office Environmental Server</Title>"  
"<html>";  

char footerHTML[] = "</html>" ;  


void setup() 
{  
  Serial.begin(9600);  
  //ethernet  
  Ethernet.begin(mac, ip);  
  server.begin();  
  Serial.print("server is at ");  
  Serial.println(Ethernet.localIP());  
}  

char * TimeElapsed() 
{ // Was Home Page  
  long t = millis() / 1000;  
  word h = t / 3600;  
  byte m = (t / 60) % 60;  
  byte s = t % 60;  
  sprintf(output, "<h1>%d%d:%d%d:%d%d</h1>" , h/10, h%10, m/10, m%10, s/10, s%10);  
  return output;  
} 

void sendTempToNetwork(EthernetClient myClient)  
{  
  // now humidity / temp sensor  
  // int chk = DHT.read22(DHTPIN);  
  myClient.print("Humidity=");  
  myClient.print(dht.readHumidity(), 0);  
  myClient.print("%");  
  myClient.print("<BR/>");  
  myClient.print("Temperature=");  
  myClient.print(dht.readTemperature(), 0);  
  myClient.write(" ");  
  myClient.print("C");  
  myClient.print("<BR/>");  
  myClient.print("Dewpoint=");  
  myClient.print(dewPoint(dht.readTemperature(), dht.readHumidity() ), 0);  
  myClient.write(" ");  
  myClient.print("C");  
  myClient.print("<BR/><BR/>");  
}  
void sendAnalogToNetwork(EthernetClient myClient)  
{  
  // output the value of each analog input pin for good measure  
  for (int analogChannel = 0; analogChannel < 6; analogChannel++) {  
    int sensorReading = analogRead(analogChannel);  
    myClient.print("analog input ");  
    myClient.print(analogChannel);  
    myClient.print(" is ");  
    myClient.print(sensorReading);  
    myClient.println("<br />");         
  }  
}  
/******************************************************************************* 
 * Main Loop 
 *******************************************************************************/
void loop()   
{  
  // listen for incoming clients  
  EthernetClient client = server.available();  
  if (client) {  
    Serial.println("new client");  
    // an http request ends with a blank line  
    boolean currentLineIsBlank = true;  
    while (client.connected()) {  
      if (client.available()) {  
        char c = client.read();  
        Serial.write(c);  
        // if you've gotten to the end of the line (received a newline  
        // character) and the line is blank, the http request has ended,  
        // so you can send a reply  
        if (c == '\n' && currentLineIsBlank) {  
          // send a standard http response header  
          client.print(headerHTML);  
          // now send the stuff we want  
          client.print(TimeElapsed()); // your old code here  
          // do some more stuff  
          sendTempToNetwork(client);  
          sendAnalogToNetwork(client);  
          // were done sending so now send the footer to close the page  
          client.println(footerHTML);  
          break;  
        }  
        if (c == '\n') {  
          // you're starting a new line  
          currentLineIsBlank = true;  
        }   
        else if (c != '\r') {  
          // you've gotten a character on the current line  
          currentLineIsBlank = false;  
        }  
      }  
    }  
    // give the web browser time to receive the data  
    delay(1);  
    // close the connection:  
    client.stop();  
    Serial.println("client disconnected");  
  }  
  delay(2000);  
}  
void Cal_Temp()  
{  
  if (TempHi&0x80)     // If bit7 of the TempHi is HIGH then the temperature is negative  
    P_N = 0;  
  else       // Else the temperature is positive  
  P_N = 1;  
  TempHi = TempHi & 0x7F;   // Remove sign  
  TempLo = TempLo & 0xF0;   // Filter out last nibble  
  TempLo = TempLo >>4; // Shift right 4 times  
  Decimal = TempLo;  
  Decimal = Decimal * 625;  // Each bit = 0.0625 degree C  
  combined_temp_C= TempHi + TempLo*.0625;  
  combined_temp_F = combined_temp_C*1.8+32;  
  sprintf(strTempC, "%f", combined_temp_C);  
  sprintf(strTempF, "%f", combined_temp_F);  
}  
////Celsius to Kelvin conversion  
//double Kelvin(double celsius)  
//{  
//        return celsius + 273.15;  
//}  
// dewPoint function NOAA  
// reference: http://wahiduddin.net/calc/density_algorithms.htm   
double dewPoint(double celsius, double humidity)  
{  
  double A0= 373.15/(273.15 + celsius);  
  double SUM = -7.90298 * (A0-1);  
  SUM += 5.02808 * log10(A0);  
  SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;  
  SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;  
  SUM += log10(1013.246);  
  double VP = pow(10, SUM-3) * humidity;  
  double T = log(VP/0.61078);   // temp var  
  return (241.88 * T) / (17.558-T);  
}  
// delta max = 0.6544 wrt dewPoint()  
// 5x faster than dewPoint()  
// reference: http://en.wikipedia.org/wiki/Dew_point  
double dewPointFast(double celsius, double humidity)  
{  
  double a = 17.271;  
  double b = 237.7;  
  double temp = (a * celsius) / (b + celsius) + log(humidity/100);  
  double Td = (b * temp) / (a - temp);  
  return Td;  
}

Arduino, DHT22, and a LCD: Rotate That Colour

Welcome to my latest Arduino project. This project is based on the DHT22 temperature and humidity sensor. I’m using a 20×4 RGB LCD screen to output the data to. I got the idea that since the LCD can do RGB why not make it rotate through these colours while dislaying the data from the sensor. All parts used here are or where available from . the full sketch is below and if you have any comments leave them in the comments section below.

// include the library code:
#include <LiquidCrystal.h>
#include <Wire.h>
#include "DHT.h"  //sensor library
#define DHTPIN 2   //  pin 32 (TQFP-32)
#define DHTTYPE DHT22   // type of sensor DHT 22  (AM2302) 

#define REDLITE 3
#define GREENLITE 5
#define BLUELITE 6

byte degreeChar[8] = 
{ B01100,
  B10010,
  B10010,
  B01100,
  B00000,
  B00000,
  B00000,
  B00000, };
DHT dht(DHTPIN, DHTTYPE);


 
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
 
// you can change the overall brightness by range 0 -> 255
int brightness = 255;
 
void setup() {
  lcd.begin(20, 4);
  analogReference(INTERNAL);
  pinMode(0, OUTPUT);
  digitalWrite(0, HIGH); // power on
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // backlight on
  dht.begin(); //  start sensor 
  lcd.setCursor(0,0);
    
    
  pinMode(REDLITE, OUTPUT);
  pinMode(GREENLITE, OUTPUT);
  pinMode(BLUELITE, OUTPUT); 
    
  brightness = 100;
}


void loop() {
  
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (isnan(t) || isnan(h)) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("SENSOR");    
    lcd.setCursor(0,1);
    lcd.print("ERROR");
  } 
  else {
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("TEMPERATURE ");
    lcd.print(t);
    lcd.createChar(0, degreeChar);
    lcd.setCursor(18,1);
    lcd.write(byte(0));
    lcd.print("C");
    lcd.setCursor(0,2);
    lcd.print("HUMIDTY     ");
    lcd.print(h);
    lcd.print(" %");
}  
  for (int i = 0; i < 255; i++) {
    setBacklight(i, 0, 255-i);
    delay(15);
  }
  for (int i = 0; i < 255; i++) {
    setBacklight(255-i, i, 0);
    delay(15);
  }
  for (int i = 0; i < 255; i++) {
    setBacklight(0, 255-i, i);
    delay(15);
  }
}
 
 
 
void setBacklight(uint8_t r, uint8_t g, uint8_t b) {
  // normalize the red LED - its brighter than the rest!
  r = map(r, 0, 255, 0, 100);
  g = map(g, 0, 255, 0, 150);
 
  r = map(r, 0, 255, 0, brightness);
  g = map(g, 0, 255, 0, brightness);
  b = map(b, 0, 255, 0, brightness);
 
  // common anode so invert!
  r = map(r, 0, 255, 255, 0);
  g = map(g, 0, 255, 255, 0);
  b = map(b, 0, 255, 255, 0);
  Serial.print(" R = "); Serial.print(r, DEC);
  Serial.print(" G = "); Serial.print(g, DEC);
  Serial.print(" B = "); Serial.println(b, DEC);
  analogWrite(REDLITE, r);
  analogWrite(GREENLITE, g);
  analogWrite(BLUELITE, b);
}

DHT22/RHT03 Humidity/Temperature Sensor and 4 Character Display, My Second Arduino Project

So I’ve been working on learning about the SoC called Arduino, to do so I’ve been using the book, Environmental Monitoring with Arduino, by Emily Gertz and Patrick Di Justo; published by O’Reilly Press. This project is designed to help you learn how to work with and program sensors. The sensor used here is the DHT22/RHT03 from adafruit. To date the project has not been going that well. Being that I’m not a programmer to start is my first hurdle and being new to electronics is my second. So I’m having real fun here. The set up seemed simple with the exception of the description of where and how the 4.7K resistor was to be placed, that could have be illustrated better.

Presently I’m getting the following problem:

6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum46Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum46Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum6Error Cheksum0Temperature: -3276.70C Humidity: 3263.80%
-1086.55d

As you can see we have all those cheksum errors and then there is the whole problem of incorrect humidity and temperature readings and the fact that nothing useful is showing up on the 4 character display.

Hopefully my local Maker friends will have a solution for me.

The following is the code taken from the Environmental Monitoring with Arduino book;
/* Temperature-Humidity-Dewpoint Monitor
This sketch gathers temperature and humidity data via a DHT22 sensor,
and also calculates dew point based on those measurements.
*/

#include
#include

#define DHT22_ERROR_VALUE -99.5

#define DHT22_PIN 4

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;
float _lastHumidity;
float _lastTemperature;

public:
DHT22(uint8_t pin);
DHT22_ERROR_t readData(void);
float getHumidity();
float getTemperatureC();
void clockReset();
};

// Setup a DHT22 instance
DHT22 myDHT22(DHT22_PIN);

#define SerialIn 2
#define SerialOut 3

#define WDelay 900

byte thou=0;
byte hund=0;
byte tens=0;
byte ones=0;

SoftwareSerial mySerialPort(SerialIn, SerialOut);

void setup(void)
{

// start serial port
Serial.begin(9600);
Serial.println(“DHT22 Library Demo”);

pinMode(SerialOut, OUTPUT);
pinMode(SerialIn, INPUT);

mySerialPort.begin(9600);
mySerialPort.print(“v”);

mySerialPort.print(“xxxx”);
delay(WDelay);
mySerialPort.print(“—-“);
delay(WDelay);
mySerialPort.print(“8888”);
delay(WDelay);
mySerialPort.print(“xxxx”);
delay(WDelay);

}

void loop(void)
{
float tempC;
float tempF;
float humid;
float dewPoint;

DHT22_ERROR_t errorCode;

delay(2000);

errorCode = myDHT22.readData();

Serial.print(errorCode);

switch(errorCode)
{
case DHT_ERROR_NONE:
Serial.print(“Temperature: “);
tempC = myDHT22.getTemperatureC();

Serial.print(tempC);
Serial.print(“C Humidity: “);

dispData((int)tempC, ‘C’);

tempF = (tempC*1.8)+32;

delay(WDelay);
dispData((int) tempF, ‘F’);
delay(WDelay);

humid = myDHT22.getHumidity();

Serial.print(humid);
Serial.println(“%”);

dispData((int)humid, ‘h’);
delay(WDelay);

dewPoint = calculateDewpoint(tempC, humid);
dispData((int) dewPoint, ‘d’);

Serial.print(dewPoint);
Serial.println(“d”);

delay(WDelay);

break;
case DHT_ERROR_CHECKSUM:
Serial.print(“Error Cheksum”);
break;
case DHT_BUS_HUNG:
Serial.print(“Bus Hung”);
break;
case DHT_ERROR_NOT_PRESENT:
Serial.print(“Not Present”);
break;
case DHT_ERROR_ACK_TOO_LONG:
break;
case DHT_ERROR_SYNC_TIMEOUT:
break;
case DHT_ERROR_DATA_TIMEOUT:
break;
case DHT_ERROR_TOOQUICK:
break;
}

}

float calculateDewpoint(float T, float RH)
{
// approximate dewpoint using the formula from wikipedia’s article on dewpoint

float dp = 0.0;
float gTRH = 0.0;
float a = 17.271;
float b = 237.7;

gTRH = ((a*T)/(b+T))+log(RH/100);
dp = (b*gTRH)/(a-gTRH);

return dp;
}

void dispData(int i, char c)
{

if(c == ‘k’ || c==’K’ || c==’m’ || c==’l’ || c == ‘v’ || c==’V’ || c==’W’ || c==’Z’ || c==’w’ || c==’z’)
{
mySerialPort.print(“bAdx”);
return;

}

if((i< -999) || (i>9999))
{
mySerialPort.print(“ERRx”);
return;
}

mySerialPort.print(“v”);

if (i > 999) { // i between 1000 and 9999 inclusive

mySerialPort.print(i, DEC);

} else if (i > 99) { // i between 100 and 999, inclusive

mySerialPort.print(i, DEC);
mySerialPort.print(c);

} else if (i > 9) { // i between 10 and 99 inclusive

mySerialPort.print(i, DEC);
mySerialPort.print(“x”);
mySerialPort.print(c);

} else if (i > 0) { // i between 1 and 9 inclusive

mySerialPort.print(“x”);
mySerialPort.print(i, DEC);
mySerialPort.print(“x”);
mySerialPort.print(c);

} else if (i < -99) { // i between -100 and -999, inclusive mySerialPort.print(i, DEC); mySerialPort.print(c); } else if (i < -9) { // i between -10 and -99, inclusive mySerialPort.print(i, DEC); mySerialPort.print(c); } else if (i < 0) { // i between -1 and -9 inclusive mySerialPort.print(i, DEC); mySerialPort.print("x"); mySerialPort.print(c); } } /* DHT22.cpp - DHT22 sensor library Developed by Ben Adams - 2011 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 "Arduino.h" extern "C" { //#include "WConstants.h" #include
#include
#include

}

#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 = (float(currentHumidity & 0x7FFF) / 10.0); if(currentTemperature & 0x8000) { // Below zero, non standard way of encoding negative numbers! currentTemperature &= 0x7FFF; _lastTemperature = (float(currentTemperature) / 10.0) * -1.0; } else { _lastTemperature = float(currentTemperature) / 10.0; } 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;
}

float DHT22::getHumidity()
{
return _lastHumidity;
}

float DHT22::getTemperatureC()
{
return _lastTemperature;
}

//
// This is used when the millis clock rolls over to zero
//
void DHT22::clockReset()
{
_lastReadTime = millis();

}