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.

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:


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:

And from the front, display pointing the right way:

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