Interfacing a Temperature sensor DHT22 with a Raspberry and I2C

Hi,

I am beginning with Arduino and I2C but I think I am not too bad in programmation. I think some technical consideration affect the good functionning of my code.

I figure out how to setup the Temperature / humidity sensor DHT22 with my Arduino Uno Rev 3 and I was able to read the temperature and humidity.

I want to be able to send the values to a Raspberry and display the temperature on a web page and eventually manage a power relay to control the heater in my house.

I am able to send the data to the Raspberry, but after 2 or 3 request, the loop() function stop to run and each request return the last read value.

I tried many possibility and the only way I am able to send the data is when I read the data in the loop. I tried to read the temperature and humidity in the callback request just before the write to the Raspberry, but for any reason, the Rasberry doesn't read anything.

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"
#include <Wire.h>
#define DHTPIN 2     // what pin we're connected to
#define SLAVE_ADDRESS 0x2A // define slave address (0x2A = 42)
String strVal;
float t, h;
String rVal = "";

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200); 
  Serial.println("DHTxx test!");
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(request);
  Wire.onReceive(OnReceive);
  strVal = "";
  dht.begin();
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  strVal = getHumiditeTemperature();
  Serial.println(strVal);
  delay(1000);
}
void request()
{
  String strToSend = "";
  Serial.println("Request received");
  strToSend = strVal;


  char bufVal[10];
  memset(bufVal, 0, 10);

  strToSend.toCharArray(bufVal,10);
//  Serial.println(bufVal);
  Wire.write(bufVal);
  
  free(bufVal);
  
}
void OnReceive(int count)
{
  strVal = "";
  Serial.print("Process OnReceived: ");
  char c = Wire.read();
  strVal = getHumiditeTemperature();
}

String getHumiditeTemperature()
{
  String rVal = "";
  t = dht.readTemperature() - 2;
  h = dht.readHumidity();
  if (isnan(t) || isnan(h))
  {
    Serial.println("Failed to read from DHT");
  } else {

  char * bufHum;
  char * bufTemp;
  bufHum=(char *) malloc (12);
  bufTemp=(char *) malloc (12);
  dtostrf (h, 1, 1, bufHum);
  dtostrf (t, 1, 1, bufTemp);
  String strHum=bufHum;
  String strTemp=bufTemp;
  rVal=(strHum+":"+strTemp+"\0");
  free(bufTemp);
  free(bufHum);

  return(rVal);
 }
  
}

The Raspberry is Sending 1 byte to the Arduino and it wait 2 second before to request the data, my OnReceive callback is then reading the values in the DHT22 and set the strVal value. But again, if I remove the strVal = getHumiditeTemperature(); from the main loop. The data is not sent properly to the Raspberry.

My main problem is not to request the temperature every 1 second in the main loop, but it is when I request teh data from the Raspberry 2 or 3 times, the main loop just stop to loop. It is like the request callback function never resume to the loop. If I send more request, the callback is still executing, but the temperature is nto updated.

Any clue what cause my callback not resuming in the loop() function?

Thanks for any help.

2 things popped up.

  1. The DHT22 needs at least 2 seconds between readings, see datasheet. your delay(1000) is too short

  2. The use of the String class is known to corrupt memory in Arduino (problems with malloc() / free()).
    Rewrite your code using char array's

Thank you for the reply.

I changed the String to char * and everything works now.

I am able to read the temperature when the Arduino receive a byte from the Raspberry now.

Can you post your final code for future reference ?
Thanks,

Here is my code.

I set a delay of 1/4 of second in the loop. The program print the read value every 10 second as per the value of 40 set in iLoop.

The value will stay empty until the OnReceive is triggered. Then it will print the same value until it receive another OnReceive callback.

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"
#include <Wire.h>
#define DHTPIN 2     // what pin we're connected to
#define SLAVE_ADDRESS 0x2A // define slave address (0x2A = 42)
char * strVal;
float t, h;
int iLoop;

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200); 
  Serial.println("DHTxx test!");
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(request);
  Wire.onReceive(OnReceive);
  memset(strVal,0,10);
  dht.begin();
  iLoop = 0; //240 X .25 seconde = 1 minute, will read DHT every 60 secondes.
  
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  if (iLoop == 0)
  {
    Serial.print("Display values ");
    Serial.println(strVal);
    iLoop = 40;
  
  }
  iLoop = iLoop - 1;
  delay(250);
}
void request()
{
  Serial.println("Request received");
  Serial.print("Sending --> ");
  Serial.println(strVal);
  Wire.write(strVal);
  
}
void OnReceive(int count)
{
  strVal = "";
  Serial.print("Process OnReceived: ");
  char c = Wire.read();
  getHumiditeTemperature();
}

void getHumiditeTemperature()
{
  memset(strVal, 0, 10);
  strVal[0] = '\0';
  t = dht.readTemperature();
  h = dht.readHumidity();
  if (isnan(t) || isnan(h))
  {
    Serial.println("Failed to read from DHT");
  } else {

  char * bufHum;
  char * bufTemp;
  bufHum=(char *) malloc (12);
  bufTemp=(char *) malloc (12);
  dtostrf (h, 1, 1, bufHum);
  dtostrf (t, 1, 1, bufTemp);

  sprintf(strVal, "%s:%s", bufHum, bufTemp);
  
  free(bufTemp);
  free(bufHum);

 }
  return;
  
}

I tried 2 différents DHT22 sensor and they display the same value. Comparing the value return for the temperature to a small meteo station close to the sensor, the value is about 2 celcius higher. The datasheet of the DHT22 stated that the sensor is calibrated and tested and supposed to have a good accuracy. I compared the temperature return to at least 3 other electronic temperature sensor and the offset is always about 2 Celsius higher.

Of course, if the oftset is always the same from one sensor to the other, I may applied an offset to the return value in the code in the arduino, or I can set an offset value at the Raspberry level in my database sensor.

Have a good day

I use this code on my arduino (i'm using the Adafruit Lib), i'm sending the data to my raspberry, which stores the data on an mysql db.

#include <SPI.h>
#include <Ethernet.h>
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
#define SENSORID 1
EthernetClient client;
DHT dht(DHTPIN, DHTTYPE);
byte mac[] = {here your intended Mac Address};
char serverName[] = "Here your server address";
long previousMillis = 0;
long interval = 5000;
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;
}
void setup()
{
  Serial.begin(9600); 
  if (Ethernet.begin(mac) != 1)
  {
    Serial.println("Erro no DHCP");
    while(true);
  }
  else
  {
    Serial.println("DHCP OK");
    dht.begin();
  }
}

void loop()
{
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    previousMillis = currentMillis;   
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    double d=dewPointFast(t,h);
    if (isnan(t) || isnan(h))
    {
      Serial.println("Failed to read from DHT");
    }
    else
    {
      Serial.println("Connecting");
      if (client.connect(serverName, 80))
      {
        client.print("GET /registar.php?temp=");
        client.print(t,DEC);
        client.print("&hum=");
        client.print(h,DEC);
        client.print("&dew=");
        client.print(d,DEC);
        client.print("&sensor=");
        client.print(SENSORID);
        client.println(" HTTP/1.0");
        client.print(" Host: ");
        client.println(SENSORID);
        client.println();
      }
    } 
  }
}

And here's my PHP script:

<?php
error_reporting(0);
    $fields = explode("&", $_SERVER['QUERY_STRING']);
    $values = array();
    foreach ($fields as $field)
    {
        $keyval = explode("=", $field);
        $values[$keyval[0]] = $keyval[1];
    }
	$t=round($values['temp'],2);
	$h=round($values['hum'],2);
	$po=round($values['dew'],2);
	$sensor=($values['sensor']);
//Put your own values below
$user="";
$password="";
$database="";
$host="localhost";
mysql_connect($host,$user,$password);
@mysql_select_db($database) or die( "Unable to select database");
$query="INSERT INTO `TABLE`(`Temperatura`, `Humidade`, `Ponto_Orvalho`, `Sensor`) VALUES ($t,$h,$po,$sensor);";
mysql_query($query);
mysql_close();
?>