Mux Shield and DHT22 Temperature Sensor - UNO Rv3

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:

// 
//   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 Mux Shield | Mayhew Labs

//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!!

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

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.

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)

// 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

// 
//    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!

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

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.

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?

#define DHT22_PIN 5
#define DHT22_CHANNEL 0
  int chk = DHT.read22(DHT22_PIN, DHT22_CHANNEL);

For channel 0?

yes, looks perfect

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

#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?)

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

You have this in your .cpp:

int dht::read22(uint8_t pin, int channel)

and this in you .h:

int read22(uint8_t pin, uint8_t channel);

I was getting a compile error, I changed them all to uint8_t

But now I'm getting another compile error:

....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

//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.

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 - ?

temp humidity -DHT22.pdf (371 KB)

robtillaart:
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:

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

// 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

#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

 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;
  }

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

int chk = DHT.read22(DHT22_PIN,DHT22_CHANNEL);

was:

  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.

I meant this way!

#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

Good to hear it works now!

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

thanks,