What is the thermo-hygrometer used for?
A thermo-hygrometer is a device that measures ambient temperature and humidity. These two parameters are measured by a special sensor at regular time intervals. They can then simply be viewed on a display or stored on an SD card (in order to have a history) or even sent to a cloud server that can process them and show them on special graphs, obviously accompanied by the date and time of the acquisition. Our thermo-hygrometer, being a simple project, is limited to printing the measured values together with the date and time on an LCD display.
In the video below you can see our thermo-hygrometer in operation:
How the tutorial is organized
We will proceed to the realization of the project step by step:
- initially we will see how to connect the humidity and temperature sensor (the classic DHT22) to our Arduino and how to make it work
- next we will connect the DS3231 Real Time Clock (RTC) module without DHT22 sensor to see how to set and read date and time
- as a third step we will connect both modules
- as fourth step we will see how to connect and operate the 2 lines and 16 character LCD display with Arduino, without the previous modules and we will also implement a brightness control system
- finally we will put everything together and make the complete thermo-hygrometer
As you can see from the previous list, each step of this tutorial is independent from the others. So, if, for example, you are looking for an easy way to get your DS3231 module working, this tutorial is for you.
If your LCD display doesn’t have the 16-pin connector soldered and you don’t know how to do it, our tutorial Yet another tutorial on how to solder may be for you.
What components do we need?
The list of components is not particularly long:
- a breadboard to connect the Arduino UNO board to the other components
- some DuPont wires (male – male, male – female, female – female)
- a DHT22 sensor
- 3 10kΩ resistors
- a 10kΩ potentiometer
- a 2 x 16 LCD display
- an RTC (Real Time Clock) DS3231 module
- a 2N3904 transistor (or a 2N2222)
- a push button switch
- and, of course, an Arduino UNO board!
Another very useful thing, even if not strictly necessary, is a small wooden tablet where to fix the Arduino and the breadboard with self-tapping screws.
While this tutorial doesn’t seem that easy, it can be successfully accomplished even by beginners if followed step by step.
You can download the project from this link below (containing all the sketches mentioned in the tutorial):
Thermohygrometer firmware and libraries
Let’s run our DHT22
Let’s download and install the DHT22 library
The first step is to download and install the DHT22 sensor library.
Download the attached DHT.zip file. In this zip file you will find two files which must be in the \DHT subfolder. If you are on Windows, install the library by moving the \DHT folder inside the folder:
C:\Program Files (x86)\Arduino\libraries
So the two files dht.cpp and dht.h must be in a folder called DHT and there must be no other subfolders. You can get more information on installing the libraries in the Arduino IDE by clicking this link: https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries
Now let’s see the pinout of the DHT22 module:
Let’s connect the DHT22
Before uploading our sketch to Arduino, we need to connect the DHT22 sensor according to the following scheme:
- Vcc —> 10kΩ resistor —> 5V
- DATA —> 10kΩ resistor —> Pin 9
- NC (not connected)
- GND —> GND
You can also follow the Fritzing diagram (shown below) for further reference:
Loading code
Now, download the dht22.ino file and double-click it (remove the .txt extension if present) in order to open it from the Arduino IDE.
The IDE will ask you to save it in a folder with the same name as the sketch. Save it wherever you like.
Now take a look at the code. What are the differences between the original sketch of the Arduino site (which you can find at this link: https://playground.arduino.cc/Main/DHTLib) and ours?
First of all we deleted lines 15 and 16 that we don’t need:
#define DHT11_PIN 4
#define DHT21_PIN 5
and also lines 55 to 105:
// READ DATA
Serial.print("DHT21, \t");
chk = DHT.read21(DHT21_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;
}
// DISPLAY DATA
Serial.print(DHT.humidity,1);
Serial.print(",\t");
Serial.println(DHT.temperature,1);
delay(1000)
In fact we would need this part of code only if we were using sensors other than the DHT22.
The second difference is the change of the Arduino pin connected to the data pin of the DHT22. We chose pin 9 instead of pin 6 (chosen by default) because pin 6 is used by the LCD display.
Upload the sketch to the Arduino and open the IDE serial monitor (just press the magnifying glass button at the top right of the IDE). The serial monitor should show lines of output as in the following box and in the following screenshot:
DHT TEST PROGRAM
LIBRARY VERSION: 0.1.14
Type, status, Humidity (%), Temperature (C)
DHT22, OK, 52.4, 25.9
Congratulations, your DHT22 is working!
If you don’t get this kind of output double check your connections and repeat the whole procedure.
Let’s adjust the date and time in our DS3231
The best way to get the date and time is to use an external module (a so-called RTC or Real Time Clock). In our project we will use a well-known and well-tested module, the DS3231 with a 3.6V rechargeable battery (model lir2032). In this way our Arduino will be able to keep the date and time even if it is turned off.
Let’s download and install the DS3231 library
To download the DS3231 library download the attached file ds3231.zip. To install the library, follow the same procedure as in the previous step.
DS3231 connections
The DS3231 has six pins. Connect them following the scheme below:
- SCL —> A5
- SDA —> A4
- Vcc —> 5V
- GND —> GND
Ignore the 32K and SQW pins as they will not be used in this project. No resistors are needed.
NOTE: We have always powered the DS3231 module at 5V with no problems. In fact, reading the datasheet, it can be seen that it can be powered with voltages ranging from 2.3V to 5.5V, while the voltage suggested by the manufacturer is 3.3V.
You can find the DS3231 module datasheet here: DS3231 datasheet
You can also follow the following Fritzing scheme:
Date and time adjustment
Now, download the attached ds3231.ino file (remove the .txt extension if present) and double-click it. The arduino IDE will open and ask you to save the new sketch in a folder with the same name. Save the sketch wherever you like.
Now go to line 19 and uncomment it by deleting the two slashes (//) at the beginning:
//setDS3231time(30,12,21,6,1,05,15);
Replace the numbers in the brackets with the current values for seconds, minutes, hour, day, date, month, year respectively.
Also remember that:
- day 1 corresponds to Sunday (Sun) while day 7 corresponds to Saturday (Sat)
- the DS3231 module conventionally uses the 24 hours
Now upload the code to the Arduino and open the serial monitor, you should see an output like this (you can also see the screenshot below):
17:53:16 13/5/15 Day of week: Wednesday
Well done, date and time have been adjusted!
If you don’t get output like this double check the links and repeat the whole procedure.
NOTE: after you have adjusted date and time, recomment line 19 otherwise the current time in module DS3231 will be rewritten every time you load the sketch.
Let’s clean up the code of DS3231
Before merging the DS3231 module and the DHT22, it’s good to do some code cleaning by deleting the parts we no longer need in the ds3231.ino sketch that we used in the previous step.
As usual, the ds3231_bis.ino code is still attached (eliminate the .txt extension if present) even if it is always good to try to understand how it works.
Let’s delete the parts that are no longer needed
Open the DS3231 code and delete lines 3 to 7:
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
We no longer need these lines because we only use them when we need to adjust the date and time on form DS3231. For the same reason, we also delete lines 17 to 19 found in the setup function:
// set the initial time here:
// DS3231 seconds, minutes, hours, day, date, month, year
//setDS3231time(30,12,21,6,1,05,15);
Repeat the operation for lines 21 to 35:
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
// sets time and date data to DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(second)); // set seconds
Wire.write(decToBcd(minute)); // set minutes
Wire.write(decToBcd(hour)); // set hours
Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
Wire.write(decToBcd(month)); // set month
Wire.write(decToBcd(year)); // set year (0 to 99)
Wire.endTransmission();
}
The attached ds3231_bis.ino file contains the cleaned up code (remove the .txt extension if present).
Let’s combine DS3231 with DHT22
Well, the time has come to combine the two devices seen in the previous steps.
First, connect the devices as shown in the Fritzing diagram below:
Once all the elements are connected (and double-checked that everything is in order) we will deal with the sketch.
In practice, we will have to make a “collage” of the codes of the previous sketches. Open both sketches, copy the DHT22 code and paste it into the DS3231 code (the cleaned up version of the ds3231_bis.ino sketch).
Libraries, variables and constants
In the ds3231_bis.ino sketch add the DST22 library, define the pins to use and also define the variables used to read and write the detected temperature and humidity values. Here we show how the new code should start:
#include "Wire.h"
#include <dht.h>
#define DHT22_PIN 9
#define DS3231_I2C_ADDRESS 0x68
dht DHT;
Functions
Immediately after the two main functions (void loop and void setup), we will place the “secondary” functions:
- bcdToDec as mentioned before, it is needed to convert numbers from binary to decimal
- readDS3231time to read data from DS3231
- displayTime to print the date and time on the serial monitor
In order not to mess things up too much, we have created the dht22 function which contains the lines belonging to the setup function of our dht22.ino sketch. Thanks to this, our loop and setup functions look much cleaner and tidier.
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year)
{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
// READ DATA
void dht22 ()
{
// 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;
}
Serial.print(DHT.humidity, 1);
Serial.print(",\t");
Serial.println(DHT.temperature, 1);
}
void displayTime()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// retrieve data from DS3231
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
// send it to the serial monitor
Serial.print(hour, DEC);
// convert the byte variable to a decimal number when displayed
Serial.print(":");
if (minute<10)
{
Serial.print("0");
}
Serial.print(minute, DEC);
Serial.print(":");
if (second<10)
{
Serial.print("0");
}
Serial.print(second, DEC);
Serial.print(" ");
Serial.print(dayOfMonth, DEC);
Serial.print("/");
Serial.print(month, DEC);
Serial.print("/");
Serial.print(year, DEC);
Serial.print(" Day of week: ");
switch(dayOfWeek){
case 1:
Serial.println("Sunday");
break;
case 2:
Serial.println("Monday");
break;
case 3:
Serial.println("Tuesday");
break;
case 4:
Serial.println("Wednesday");
break;
case 5:
Serial.println("Thursday");
break;
case 6:
Serial.println("Friday");
break;
case 7:
Serial.println("Saturday");
break;
}
}
Setup function
The most important functions are Wire.begin() and Serial.begin(). These functions initialize the DS3231 and the serial monitor respectively. The other lines print other information about DHT22 that is not strictly necessary:
void setup()
{
Wire.begin();
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)");
}
Loop function
The loop function is very simple: it just calls the two functions displayTime() and dht22() and waits for 2 seconds. Why 2 seconds? Because the DHT22 needs 2 seconds to take a measurement:
#include "Wire.h"
void loop()
{
displayTime(); // display the real-time clock data on the Serial Monitor,
dht22 (); // display the value of humidity and temperature detected
delay(2000);
}
As usual we have attached the ready-to-use code so you can directly download the dht22andDS3231.ino sketch (eliminate the .txt extension if present).
Let’s connect the LCD display
Now is the time to connect the LCD display. You will need a 10 kΩ linear potentiometer and a 16-pin connector.
Once the display is connected as shown in the figure, connect the +5V line to a pin of the red stripe of the breadboard and the GND pin to a pin of the blue stripe. Also connect the upper and lower red strips together, then connect the upper and lower blue strips together (as shown in the figure above). Remember that by convention red wires are used for the +5V line and black wires for the GND line.
Now connect the light for the backlighting of the display and the potentiometer for the contrast: place the potentiometer as shown in the figure and connect its central pin to the V0 pin of the display while the two lateral pins you will connect them to GND.
Connect pin 16 of the display to GND and pin 15 to +5V (these two pins are connected internally in the display to a backlight light). If you connect the Arduino to power the backlight should turn on.
Now turn off the Arduino and continue with the remaining connections.
You can either follow the Fritzing scheme or the table below:
LCD Power Supply
VSS (pin1) GND
VDD (pin2) +5V
RW (pin5) GND
LCD ARDUINO
RS (pin4) pin2
E (pin6) pin3
D4 (pin11) pin4
D5 (pin12) pin5
D6 (pin13) pin6
D7 (pin14) pin7
LCD Backlight power supply
A (pin 15) +5V
K (pin 16) GND
At this point we can load the attached HelloWorld.ino sketch and test the circuit (remove the .txt extension if present). If everything is connected correctly you should read a message on the display.
Let’s check the light of the LCD display screen
Since the backlighting of the display draws a certain current, it may be useful to check that it is switched on, especially if you are planning to run the thermo-hygrometer on a battery. In our solution, you only need to press a button to turn on the backlight. The display will automatically turn off after about 8 seconds. We achieved this by controlling the led responsible for the backlighting with a PWM signal generated by Arduino. Since the PWM output cannot supply the current needed to control this led, we cannot connect it directly.
We solve the problem using a 2N3904 transistor and a 10 kΩ resistor, as shown in the Fritzing schematic below. The current required to turn on the LED will flow between the collector and emitter of the transistor rather than through the PWM output.
The sketch
First we define the required pins:
- pin 11 as PWM signal output
- pin 10 as an input to detect the state of the button
#define LUMIN 11
#define BUTTON 10
so, we declare these two variables:
int val = 0;
int counter = 0;
which are required to set the button status and the display lighting time, respectively.
In the setup function we have to define the pin used as input and the one used as output of the PWM signal:
pinMode(BUTTON, INPUT);
pinMode(LUMIN, OUTPUT);
In the loop function we find the brightness control:
val = digitalRead(BUTTON);
if (val == HIGH) {
counter = 1000;
analogWrite(LUMIN, 255); // turns on the led
}
if (val == LOW) {
if (counter > 0) {
counter--;
}
}
if (counter <= 0) {
analogWrite(LUMIN, 0); // turns off the led
}
Controlling the brightness of the display is quite simple:
initially the counter is set to 0, which means that the backlight is off.
However, when the button is pressed, the logic condition in the first “if” becomes true and the counter value is set to 1000 while the PWM output is set to the maximum level (255).
The backlight will remain on as long as the button is held down.
When the button is released, the logical condition of the second “if” becomes true (while the first becomes false) and the counter begins to be decremented. In each loop the counter decreases by one unit.
The last “if” turns off the backlight as soon as the counter assumes the value 0.
Notice that the second “if” has two conditions:
- the pin must be set to LOW (button not pressed)
- the counter value must be greater than 0
You can download the attached LCD_display_control.ino sketch (remembering to remove the .txt extension if present).
Let’s complete our thermo-hygrometer
At this point we are ready to put everything together (both the hardware and the software) to make our thermo-hygrometer.
For connections, follow the Fritzing diagram below:
Now let’s see the sketch which will be a “collage” of the previous ones.
Open both sketches LCD_display_control.ino and dht22andDS3231.ino and copy and paste the first into the second. In this step we will create a sketch showing the values detected by the DHT22 and the date and time on the LCD display.
First we need to replace all Serial.print() functions with lcd.print() functions.
This operation is quite simple if you use a text editor that has the automatic “find and replace” function (such as Notepad++). Then find all the lines where it says Serial and replace it with lcd.
The header of the sketch
Now, add the library required by the LCD display and declare the two variables and constants used to turn it on and off. Next you need to declare two byte arrays. These two arrays, called drop and temp, contain the icons shown on the display.
To initialize the display we use the LiquidCrystal() function which contains, within its brackets, the pins used by the display.
Functions
Scrolling down the sketch we find different functions:
- bcdToDec as mentioned before, it is used to convert binary numbers into decimal numbers
- readDS3231time needed to read data from the DS3231
- displayTime needed to print the date and time on the LCD display
- dht22 necessary to detect and print the temperature and humidity values on the display
To have a better display, we made some changes in the displayTime and dht22 functions.
Basically we need to show the date and time on the first line and the temperature and humidity on the second line. An LCD display like ours has only 16 characters (alphanumeric) per line so if you want to show all the information you need to organize it in an appropriate way.
First, we shortened the names of the days of the week, as you can see from the first switch/case statement. We also added another switch/case for shortened month names. We also eliminated the current year and seconds.
For the same reason we have also modified the dht22 function. In fact, this sketch no longer prints the information of the DHT22 library such as the line “Type, status, Humidity (%), Temperature (C)”
but only prints the two icons (drop and temp), the temperature followed by “° C” (because we use degrees Celsius) and the humidity followed by the “%”. Since space is still limited, we have decided to eliminate the second decimal place from the temperature and humidity values.
Setup function
The first two lines of the setup function initialize the two pins BUTTON and LUMIN. These are used for display backlight control. The third line initializes the DS3231. The fourth and fifth create the two icons.
The last one initializes the display.
Loop function
In the loop function we find the instructions necessary to control the backlighting of the display. We do not repeat here how they work because we addressed the problem in a previous step.
The last two statements call the functions that print date and time and temperature and humidity. The only difference from the code of the previous step is that the counter (which was initialized to 1000 before) is initialized to 5 this time because we have now inserted a 2 second delay.
As usual, you can download the attached complete sketch thermohygrometer.ino (remembering to remove the .txt extension if present).
Newsletter
If you want to be informed about the release of new articles, subscribe to the newsletter. Before subscribing to the newsletter read the page Privacy Policy (UE)
If you want to unsubscribe from the newsletter, click on the link that you will find in the newsletter email.