Go Down

Topic: Mux Shield and DHT22 Temperature Sensor - UNO Rv3 (Read 10465 times) previous topic - next topic

bmplabs

Hi everyone! This is my first post after spending hours searching for my answer without success. I've only completed some pretty simple projects with the Arduino and I'm trying to get to the next level--you know, from infant to toddler.

Below is working code for my DHT22 Temperature & Humidity sensor:
Code: [Select]
//
//   FILE:  dht_test.pde
// PURPOSE: DHT library test sketch for Arduino
// BY: Rob Tillaart http://playground.arduino.cc/Main/DHTLib

#include <dht.h>

dht DHT;

#define DHT11_PIN 4
#define DHT22_PIN 5

void setup()
{
  Serial.begin(115200);
  Serial.println("DHT TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT_LIB_VERSION);
  Serial.println();
  Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
}

void loop()
{
  // READ DATA
  Serial.print("DHT22, \t");
  int chk = DHT.read22(DHT22_PIN);
  switch (chk)
  {
    case DHTLIB_OK: 
Serial.print("OK,\t");
break;
    case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
    case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
    default:
Serial.print("Unknown error,\t");
break;
  }
  // DISPLAY DATA
  Serial.print(DHT.humidity, 1);
  Serial.print(",\t");
  Serial.println(DHT.temperature, 1);

  delay(1000);

  // READ DATA
  Serial.print("DHT11, \t");
  chk = DHT.read11(DHT11_PIN);
  switch (chk)
  {
    case DHTLIB_OK: 
Serial.print("OK,\t");
break;
    case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
    case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
    default:
Serial.print("Unknown error,\t");
break;
  }
// DISPLAT DATA
  Serial.print(DHT.humidity,1);
  Serial.print(",\t");
  Serial.println(DHT.temperature,1);

  delay(1000);
}
//
// END OF FILE
//


And here is the sample code for the MuxShield by MayhewLabs http://mayhewlabs.com/products/arduino-mux-shield
Code: [Select]
//Mux_Shield_DigitalIn_Example
//http://mayhewlabs.com/arduino-mux-shield

/*
This example shows how to read and store all pins as digital inputs into arrays and print the results over serial.
Switches should be connected from ground to the pin input.
Internal pull-up resistors are used on the inputs, so when a switch is depressed, the reading
changes from 1 to 0, but to correct this logic, the digitalRead function is corrected with '!'
to actually store a 1 when a switch is depressed.

To simplify this code further, one might use nested for loops or function calls.
*/

//Give convenient names to the control pins
#define CONTROL0 5   
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2

//Create arrays for data from the the MUXs
//See the Arduino Array Reference: http://www.arduino.cc/en/Reference/Array
int mux0array[16];
int mux1array[16];
int mux2array[16];

void setup()
{
  //Set MUX control pins to output
  pinMode(CONTROL0, OUTPUT);
  pinMode(CONTROL1, OUTPUT);
  pinMode(CONTROL2, OUTPUT);
  pinMode(CONTROL3, OUTPUT);
 
  //Open the serial port at 28800 bps
  Serial.begin(28800);
 
  //Set analog pins to digital input 
  pinMode(14, INPUT);         
  pinMode(15, INPUT);
  pinMode(16, INPUT);
 
  //Turn on pullup resistors
  digitalWrite(14, HIGH);       
  digitalWrite(15, HIGH);
  digitalWrite(16, HIGH);
}
 

void loop()
{
  //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    //See the Arduino Bitwise AND Reference: http://www.arduino.cc/en/Reference/BitwiseAnd
    //See the Aruino Bitshift Reference: http://www.arduino.cc/en/Reference/Bitshift
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
   
    //Read and store the input
    //Since internal pullup is on, the pin goes low on changing, so the value needs to be flipped from 0 to 1 (!)
    mux0array[i] = !digitalRead(14);
  }
 
  //This for loop is used to scroll through the SECOND multiplexer
  for (int i=0; i<16; i++)
  {
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
    mux1array[i] = !digitalRead(15);
  }
 
  //This for loop is used to scroll through the THIRD multiplexer
  for (int i=0; i<16; i++)
  {
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
    mux2array[i] = !digitalRead(16);
  }   
 
  //The following lines are for printing out results of array0
  Serial.print("mux0array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }
  Serial.println();  //line feed
 
  //The following lines are for printing out results of array1
  Serial.print("mux1array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux1array[i]);
    Serial.print("-");
  }
  Serial.println();
 
  //The following lines are for printing out results of array2
  Serial.print("mux2array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux2array[i]);
    Serial.print("-");
  }
  Serial.println();
}


I'm stuck at trying to adapt the DHT22 code to read the muxshield. I had the sensor plugged in, the code--what I thought--correct, and the sensor in mux0array[0] and I wasn't receiving anything. I have not been able to find any simple code examples integrating sensors with the mux shield. I'm hoping to grasp how the muxshield works so I'll be able to adapt many sensors to the mux. Any help will be greatly appreciated.

Thanks!!

Dr_Ugi

I don't remember the details of communication with the DHT22 but It's a one-wire digital communication, which is not going to be easy to multiplex!  I remember reading a comment (by Lady Ada I think, who knows her stuff) that the timing of the interface is relatively difficult.

I expect that it can be done, but I don't think the DHT22 is a very good choice as a first sensor for using with a multiplexer. Assuming that you can read switches etc OK then you might rather use a TMP36 or similar analogue device if you want to read temperature as a first project using the multiplexer.

Ugi

bmplabs

Thanks for the reply Ugi! I guess I should of researched how the multiplexer worked before buying it--figured it was simple since it just says expands i/o of arduino.

robtillaart

The DHT22 timing in my library is time critical. If an ISR happens while bits are clocked in communication can/will fail.

That said, I see no reason why it cannot be communicated over the mux-shield. It seems not too difficult as the library only needs small modifications.
I assume the mux shield does not affect the timing significantly.
I assume the mux shield does not invert the signal otherwise you need to add some ! to invert)

The following code is not tested, it is about how I would start. Nothing changed on the code only the  mux- channel selection is added.

The mux-ified DHT.cpp   (timing values might need to be adjusted)
Code: [Select]

// assume the multiplexer is connected to Arduino pin 14, you need to add the mux channel in the DHT lib read function
// so you call it something like DHT.read22(14, 5);

//
//    FILE: dht.cpp
// VERSION: 0.1.05
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
//
// DATASHEET:
//
// HISTORY:
// 0.1.05 fixed negative temperature bug (thanks to Roseman)
// 0.1.04 improved readability of code using DHTLIB_OK in code
// 0.1.03 added error values for temp and humidity when read failed
// 0.1.02 added error codes
// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011)
// 0.1.0 by Rob Tillaart (01/04/2011)
// inspired by DHT11 library
//

#include "dht.h"

#define TIMEOUT 10000

/////////////////////////////////////////////////////
//
// PUBLIC
//


// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
#include "dht.h"

#define TIMEOUT 10000

/////////////////////////////////////////////////////
//
// PUBLIC
//


// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht::read11(uint8_t pin, int channel)
{
       // READ VALUES
       int rv = read(pin, channel);
       if (rv != DHTLIB_OK)
   {
               humidity    = DHTLIB_INVALID_VALUE; // or is NaN prefered?
               temperature = DHTLIB_INVALID_VALUE;
               return rv;
       }

       // CONVERT AND STORE
       humidity    = bits[0];  // bit[1] == 0;
       temperature = bits[2];  // bits[3] == 0;

       // TEST CHECKSUM
       uint8_t sum = bits[0] + bits[2]; // bits[1] && bits[3] both 0
       if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;

       return DHTLIB_OK;
}

// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht::read22(uint8_t pin, int channel)
{
       // READ VALUES
       int rv = read(pin, channel);
       if (rv != DHTLIB_OK)
      {
               humidity    = DHTLIB_INVALID_VALUE;  // invalid value, or is NaN prefered?
               temperature = DHTLIB_INVALID_VALUE;  // invalid value
               return rv;
       }

       // CONVERT AND STORE
       humidity    = word(bits[0], bits[1]) * 0.1;

       if (bits[2] & 0x80) // negative temperature
       {
                       temperature = word(bits[2]&0x7F, bits[3]) * 0.1;
                       temperature *= -1.0;
       }
       else
       {
                       temperature = word(bits[2], bits[3]) * 0.1;
       }

       // TEST CHECKSUM
       uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3];
       if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;

       return DHTLIB_OK;
}


int dht::read(int pin, int channel)
{
 digitalWrite(CONTROL0, channel & 15);
 digitalWrite(CONTROL1, channel & 7);  
 digitalWrite(CONTROL2, channel & 3);  
 digitalWrite(CONTROL3, channel & 1);

       // INIT BUFFERVAR TO RECEIVE DATA
       uint8_t cnt = 7;
       uint8_t idx = 0;

       // EMPTY BUFFER
       for (int i=0; i< 5; i++) bits[i] = 0;

       // REQUEST SAMPLE
       pinMode(pin, OUTPUT);
       digitalWrite(pin, LOW);
       delay(20);
       digitalWrite(pin, HIGH);
       delayMicroseconds(40);
       pinMode(pin, INPUT);

       // GET ACKNOWLEDGE or TIMEOUT
       unsigned int loopCnt = TIMEOUT;
       while(digitalRead(pin) == LOW)
               if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

       loopCnt = TIMEOUT;
       while(digitalRead(pin) == HIGH)
               if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

       // READ THE OUTPUT - 40 BITS => 5 BYTES
       for (int i=0; i<40; i++)
       {
               loopCnt = TIMEOUT;
               while(digitalRead(pin) == LOW)
                       if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

               unsigned long t = micros();

               loopCnt = TIMEOUT;
               while(digitalRead(pin) == HIGH)
                       if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

               if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
               if (cnt == 0)   // next byte?
               {
                       cnt = 7;  
                       idx++;      
               }
               else cnt--;
       }

       return DHTLIB_OK;
}


dht.h file
Code: [Select]

//
//    FILE: dht.h
// VERSION: 0.1.05
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
//
//     URL: http://arduino.cc/playground/Main/DHTLib
//
// HISTORY:
// see dht.cpp file
//

#ifndef dht_h
#define dht_h

#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

#define DHT_LIB_VERSION "0.1.05"

#define DHTLIB_OK                               0
#define DHTLIB_ERROR_CHECKSUM   -1
#define DHTLIB_ERROR_TIMEOUT    -2
#define DHTLIB_INVALID_VALUE    -999

class dht
{
public:
       int read11(uint8_t pin, uint8_t channel);
   int read22(uint8_t pin, uint8_t channel);
       double humidity;
       double temperature;

private:
       uint8_t bits[5];  // buffer to receive data
       int read(uint8_t pin, uint8_t channel);
};
#endif
//
// END OF FILE
//


Let me know if it works!
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Added a link on the lib page - http://playground.arduino.cc//Main/DHTLib - to this discussion
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

bmplabs


The DHT22 timing in my library is time critical. If an ISR happens while bits are clocked in communication can/will fail.

That said, I see no reason why it cannot be communicated over the mux-shield. It seems not too difficult as the library only needs small modifications.
I assume the mux shield does not affect the timing significantly.
I assume the mux shield does not invert the signal otherwise you need to add some ! to invert)

The following code is not tested, it is about how I would start. Nothing changed on the code only the  mux- channel selection is added.

Let me know if it works!



First off, Rob, thank you for replying and thanks for contributing the library! It's you guys that make us guys, the absolute newbs, have way too much fun with the arduino.

Quick question: In my sketch, I'll need to pass the channel parameter to read22, right?

Code: [Select]

#define DHT22_PIN 5
#define DHT22_CHANNEL 0



Code: [Select]
  int chk = DHT.read22(DHT22_PIN, DHT22_CHANNEL);


For channel 0?

robtillaart

yes, looks perfect

If you could connect multiple DHT22 sensors to 1 arduino pin you could use an array.

Code: [Select]
#define DHT22_PIN 5
uint8_t channel[5] =  { 0,4,5,6,10 };
int chk = DHT.read22(DHT22_PIN, channel[idx] );


(and, .... does it work?)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

bmplabs


Added a link on the lib page - http://playground.arduino.cc//Main/DHTLib - to this discussion


You have this in your .cpp:
Code: [Select]
int dht::read22(uint8_t pin, int channel)

and this in you .h:
Code: [Select]
int read22(uint8_t pin, uint8_t channel);

I was getting a compile error, I changed them all to
Code: [Select]
uint8_t

But now I'm getting another compile error:
Code: [Select]

....Arduino/libraries/dht/dht.cpp: In member function 'int dht::read(uint8_t, uint8_t)':
....Arduino/libraries/dht/dht.cpp:109: error: 'CONTROL0' was not declared in this scope
....Arduino/libraries/dht/dht.cpp:110: error: 'CONTROL1' was not declared in this scope
....Arduino/libraries/dht/dht.cpp:111: error: 'CONTROL2' was not declared in this scope
....Arduino/libraries/dht/dht.cpp:112: error: 'CONTROL3' was not declared in this scope


I added the following to the cpp in public scope line 39
Code: [Select]

//Give convenient names to the control pins
#define CONTROL0 5    
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2


With the sensor connected to Channel 0 Pin 5, I'm getting a timeout and values of -999.9 displayed.

No work,... yet.

robtillaart

Thanks for fixing some 'shortcuts' I took in the code. Well resolved.
first the sensor needs 2 seconds between read operations.

The value of -999 indicates INVALID_VALUE that's OK for now.

The time out can be generated in a number of places.
You need to patch the code so that all time-out give a different error e.g. -10 -20 -30 -40 
This way you can localize which time-out fails, that gives an indication where to patch the timing.

Do you have a capacitor connected to the DHT22 - see datasheet attached - ?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

bmplabs



You need to patch the code so that all time-out give a different error e.g. -10 -20 -30 -40 

Do you have a capacitor connected to the DHT22 - see datasheet attached - ?


I do not have the capacitor connected and will have to run to the electronics store for that.

On another note, to patch the code for more specific error codes, how?

I'm getting the error:
Code: [Select]
dht_multiplexed.ino: In function 'void loop()':
dht_multiplexed:39: error: 'AHTLIB_ERROR_TIMEOUT' was not declared in this scope
dht_multiplexed:45: error: duplicate case value
dht_multiplexed:42: error: previously used here
dht_multiplexed:48: error: duplicate case value
dht_multiplexed:42: error: previously used here


What I did:
cpp
Code: [Select]
// GET ACKNOWLEDGE or TIMEOUT
        unsigned int loopCnt = TIMEOUT;
        while(digitalRead(pin) == LOW)
                if (loopCnt-- == 0) return ADHTLIB_ERROR_TIMEOUT;

        loopCnt = TIMEOUT;
        while(digitalRead(pin) == HIGH)
                if (loopCnt-- == 0) return BDHTLIB_ERROR_TIMEOUT;

        // READ THE OUTPUT - 40 BITS => 5 BYTES
        for (int i=0; i<40; i++)
        {
                loopCnt = TIMEOUT;
                while(digitalRead(pin) == LOW)
                        if (loopCnt-- == 0) return CDHTLIB_ERROR_TIMEOUT;

                unsigned long t = micros();

                loopCnt = TIMEOUT;
                while(digitalRead(pin) == HIGH)
                        if (loopCnt-- == 0) return DDHTLIB_ERROR_TIMEOUT;

                if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
                if (cnt == 0)   // next byte?
                {
                        cnt = 7;   
                        idx++;     
                }
                else cnt--;
        }


.h
Code: [Select]
#define DHTLIB_OK                               0
#define DHTLIB_ERROR_CHECKSUM   -1
#define ADHTLIB_ERROR_TIMEOUT    -2
#define BDHTLIB_ERROR_TIMEOUT    -2
#define CDHTLIB_ERROR_TIMEOUT    -2
#define DDHTLIB_ERROR_TIMEOUT    -2
#define DHTLIB_INVALID_VALUE    -999


pde
Code: [Select]
switch (chk)
  {
    case DHTLIB_OK: 
Serial.print("OK,\t");
break;
    case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
    case ADHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error A,\t");
break;
    case BDHTLIB_ERROR_TIMEOUT:
    Serial.print("Time out error B,\t");
    break;
    case CDHTLIB_ERROR_TIMEOUT:
    Serial.print("Time out error C,\t");
    break;
    case DDHTLIB_ERROR_TIMEOUT:
    Serial.print("Time out error D,\t");
    break;
    default:
Serial.print("Unknown error,\t");
break;
  }

bmplabs

Works!!! While going through my code I realized that the line:

Code: [Select]
int chk = DHT.read22(DHT22_PIN,DHT22_CHANNEL);

was:

Code: [Select]
  int chk = DHT.read22(DHT22_PIN,0);

-- I must of changed it at some point trying to debug. I need to start using version control on my arduino sketches.

robtillaart

I meant this way!
Code: [Select]

#define DHTLIB_OK                               0
#define DHTLIB_ERROR_CHECKSUM   -1
#define ADHTLIB_ERROR_TIMEOUT    -21
#define BDHTLIB_ERROR_TIMEOUT    -22
#define CDHTLIB_ERROR_TIMEOUT    -23
#define DDHTLIB_ERROR_TIMEOUT    -24
#define DHTLIB_INVALID_VALUE    -999
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Good to hear it works now!

Can you post your final code for future references?
lib.cpp lib.h and test sketch?

thanks,
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up