Temperature And Humidity Display Using Arduino, DHT22, And MAX7219 Display

I finished another project today. This time it’s a simple temperature and humidity display, and so far it’s working pretty well. It’s built around an Arduino Nano and uses a DHT22 sensor. The display is an extremely cheap MAX7219-based four-module LED matrix (130x32mm), and its brightness is controlled by a capacitive touch sensor (11x15mm).

In this case, everything runs off a 5V supply so there are no level shifters needed and a single USB cable can power the whole thing. Any other 5V Arduino with hardware SPI will work fine here, too. The software libraries I used also support software SPI but I haven’t tried that out.

Here’s the layout:

  • Everything is connected to the +5V and GND pins on the USB connector.
  • MAX7219 CLK to Arduino 13.
  • MAX7219 DATA to Arduino 11.
  • MAX7219 CS to Arduino 10.
  • DHT22 I/O to Arduino 2.
  • Touch sensor I/O to Arduino 4.

I had everything on a breadboard but forgot to take a picture before wiring everything up to fit in the case… here it is wired up and just before being prepared to put into the case.

Arduino DHT22 ST7735

The program uses the MD_MAX72XX and MD_PAROLA libraries for the display, and the SimpleDHT library for the DHT22. It took me a while to wrap my head around the MD_PAROLA stuff, but the examples included with the libraries were very helpful. Here’s the program:

/* Temp and RH DHT22 MAX7219 for Dot 04
 *  Uses Nano to check DHT22 and display on 8x8 dot matrix (x4) MAX7219.
 *  Meant to be used indoors.
 *  Has two brightness settings, 4 and 15 (on scale of 0-15)
 *  Runs off 5V USB.
 *  MAX7219 controlled by MD_Parola and MD_MAX72xx libraries
 *  DHT22 using SimpleDHT
 *  PINS:
 *  DHT22 data: D2
 *  MAX7219 clock: D13, data: D11, CS: D10
 *  Intensity: D4
 *  Uses a MAX7219 32x8 LED module from Banggood. Hardware type is MD_MAX72XX::ICSTATION_HW, 4 devices
 *  Puts temp and RH on display at same time
 */

/*
 * MAKE SURE YOU RUN THE MD_MAX72XX_HW_Mapper to confirm the hardware setting for your particular display!
 * The results I got for the display I have were:
 * 
 * HW_DIG_ROWS 1
 * HW_REV_COLS 1
 * HW_REV_ROWS 1
 * Your hardware matches the setting for IC Station modules. Please set ICSTATION_HW.

 * 
 */

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SimpleDHT.h>
#include <SPI.h>

// Set up DHT22 vars for data TX/RX
#define h_w 8
#define h_h 8
static unsigned char h_w_bits[] = {
   0x3c, 0x42, 0xa5, 0x81, 0xa5, 0x99, 0x42, 0x3c };

#define s_w 8
#define s_h 8

static unsigned char s_w_bits[] = {
   0x3c, 0x42, 0xa5, 0x81, 0x99, 0xa5, 0x42, 0x3c };

// Create instance for the DHT22 using pin 2 for data xfer
SimpleDHT22 dht22(2);


// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW  // Found using the MD HW mapping program

#define MAX_DEVICES 4 // Four 8x8 modules on this particular board

#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

#define BRIGHT_PIN 4

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

byte CountUp = 0;

void setup() {

  delay(500); // Need this because display doesn't seem to start up right away.

  P.begin(2); // Using 2 zones, one for temp, one for humidity

  pinMode(BRIGHT_PIN, INPUT);
  
  P.setZone(0,0,1);
  P.setZone(1,2,3);
  
  P.displayZoneText(0, "Hi!", PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayZoneText(1, "Hi!", PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);

  P.setZoneEffect(0, 1, PA_FLIP_UD);  // Need this because I glued the display in upside down >:-(
  P.setZoneEffect(1, 1, PA_FLIP_UD);  // Need this because I glued the display in upside down >:-(
  P.setZoneEffect(0, 1, PA_FLIP_LR);  // Need this because I glued the display in upside down >:-(
  P.setZoneEffect(1, 1, PA_FLIP_LR);  // Need this because I glued the display in upside down >:-(
  P.displayAnimate();    
  delay(2000);
}

void loop() {

  jumpback:

  // If touch sensor is active, cycle through the 16 levels of brightness until sensor is inactive.
  int brightness_change = digitalRead(4);
  while (brightness_change == 1){
    if (CountUp == 16){
      CountUp = 0;
    }
    P.setIntensity(0, CountUp);
    P.setIntensity(1, CountUp);
    delay(250);
    CountUp = CountUp + 1;
    brightness_change = digitalRead(4);
  }

  float temperature = 0;
  float humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht22.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    // If we're here, there was a problem reading the DHT22. Show an error then try again.
    P.displayZoneText(0, "Dht", PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);
    P.displayZoneText(1, "Err", PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);
    P.displayAnimate();
    delay(5000);
    goto jumpback;  // I know, I know. Don't say it...
  }

  // Convert the float to a string to display
  char temp_result[6];
  dtostrf(temperature,2,0,temp_result);

  // Convert the float to a string to display
  char hum_result[6];
  dtostrf(humidity,2,0,hum_result);

  P.displayZoneText(1, hum_result, PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayZoneText(0, temp_result, PA_CENTER, 75, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayAnimate();

  delay(3500);  // DHT22 max sample rate is about 2 seconds.
}

If you are using a MAX7219-based display, save yourself some time and frustration by connecting it and running the MD_MAX72XX_HW_Mapper program that comes with the MD_MAX72XX library before you do anything else. It will tell you how your display is set up, regardless of how it actually looks.

After doing some testing, I found that the capacitive touch sensor I was using could reliably detect my finger out to about 5mm away. That was great because then I could hide it inside the case and there’d be no switch, no pad… just a “magic” spot on the back that changes the brightness if you put your finger there.

I designed a case for this particular project, including the specific display and touch sensor I had on hand. It’s vented, has a hole for a USB cable, and is closed up with four 6mm M3 screws:

Arduino DHT22 MAX7219
Fresh off the printer… with a bit of over-extrusion.
Arduino DHT22 MAX7219
The capacitive touch sensor in its dedicated spot right in the middle of the back panel.

With everything wired up and tested, I hot-glued everything… and I mean everything. Every connector, every module (except the Nano’s mini-USB port – never know if I’ll want or need to reprogram it) … it’s all quite secure inside the case. I glued put a piece of plastic on the back of the display just in case any other parts work their way loose and came in contact with it. I’m still a little wary of doing things this way, but it sure beats drawing up and etching boards for this kind of stuff!

Once the glue had cooled and I confirmed everything was stuck good and tight, I closed up the case and plugged the cable into a 5V USB power supply. The LEDs flashed, and then… everything was upside down. I’d glued the display in upside down.

So… another 45 minutes or so of pondering and looking and I found how to flip the display in software so it looked right again. If you run into this problem, check out setZoneEffect() in the MD_PAROLA documentation.

Here it is, from the back:

Arduino DHT22 MAX7219

And from the front, display pointing the right way:

Arduino DHT22 MAX7219

The STL files for the case are available at https://www.thingiverse.com/thing:4202464

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.