// Real time clock, calendar, temperature, humidity data logger using Arduino, DS3231 and DHT22 sensor
#include <SPI.h> // Include SPI library (needed for the SD card)
#include <SD.h> // Include SD library
#include <LiquidCrystal.h> // Include LCD library code
#include <Wire.h> // Include Wire library code (needed for I2C protocol devices)
#include <DHT.h> // Include DHT library code
// LCD module connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
#define B1 A1 // Button B1 is connected to Arduino pin A1
#define B2 A2 // Button B1 is connected to Arduino pin A2
#define DHTPIN A3 // DHT22 data pin is connected to Arduino pin A3
#define DHTTYPE DHT22 // DHT22 sensor is used
DHT dht(DHTPIN, DHTTYPE); // Initialize DHT library
File dataLog;
boolean sd_ok = 0;
char temperature[] = " 00.0";
char humidity[] = " 00.0 %";
char Time[] = " : : ";
char Calendar[] = " / /20 ";
byte i, second, minute, hour, date, month, year, previous_second;
int Temp, RH;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin())
Serial.println("initialization failed!");
else {
Serial.println("initialization done.");
sd_ok = 1;
}
pinMode(B1, INPUT_PULLUP);
pinMode(B2, INPUT_PULLUP);
lcd.begin(20, 4); // Set up the LCD's number of columns and rows
Wire.begin(); // Join i2c bus
dht.begin();
lcd.setCursor(0, 0); lcd.print("TIME:");
lcd.setCursor(0, 1); lcd.print("DATE:");
lcd.setCursor(0, 2); lcd.print("Temp =");
lcd.setCursor(11, 2); lcd.write(223); // Print degree symbol ( °)
lcd.setCursor(12, 2); lcd.write('C');
lcd.setCursor(0, 3); lcd.print("RH =");
Serial.println(" DATE | TIME | TEMPERATURE | HUMIDITY");
if(sd_ok) { // If SD card initialization was OK
dataLog = SD.open("Logger.txt", FILE_WRITE); // Open file Logger.txt
if(dataLog) { // if the file opened okay, write to it:
dataLog.println(" DATE | TIME | TEMPERATURE | HUMIDITY");
dataLog.close(); // Close the file
}
}
}
void DS3231_display(){
// Convert BCD to decimal
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
// End conversion
Time[7] = second % 10 + 48;
Time[6] = second / 10 + 48;
Time[4] = minute % 10 + 48;
Time[3] = minute / 10 + 48;
Time[1] = hour % 10 + 48;
Time[0] = hour / 10 + 48;
Calendar[9] = year % 10 + 48;
Calendar[8] = year / 10 + 48;
Calendar[4] = month % 10 + 48;
Calendar[3] = month / 10 + 48;
Calendar[1] = date % 10 + 48;
Calendar[0] = date / 10 + 48;
lcd.setCursor(5, 0);
lcd.print(Time); // Display time
lcd.setCursor(5, 1);
lcd.print(Calendar); // Display calendar
}
void blink_parameter(){
byte j = 0;
while(j < 10 && digitalRead(B1) && digitalRead(B2)){
j++;
delay(25);
}
}
byte edit(byte x, byte y, byte parameter){
char text[3];
while(!digitalRead(B1)); // Wait until button (pin #8) released
while(true){
while(!digitalRead(B2)){ // If button (pin #9) is pressed
parameter++;
if(i == 0 && parameter > 23) // If hours > 23 ==> hours = 0
parameter = 0;
if(i == 1 && parameter > 59) // If minutes > 59 ==> minutes = 0
parameter = 0;
if(i == 2 && parameter > 31) // If date > 31 ==> date = 1
parameter = 1;
if(i == 3 && parameter > 12) // If month > 12 ==> month = 1
parameter = 1;
if(i == 4 && parameter > 99) // If year > 99 ==> year = 0
parameter = 0;
sprintf(text,"%02u", parameter);
lcd.setCursor(x, y);
lcd.print(text);
delay(200); // Wait 200ms
}
lcd.setCursor(x, y);
lcd.print(" "); // Display two spaces
blink_parameter();
sprintf(text,"%02u", parameter);
lcd.setCursor(x, y);
lcd.print(text);
blink_parameter();
if(!digitalRead(B1)){ // If button (pin #8) is pressed
i++; // Increament 'i' for the next parameter
return parameter; // Return parameter value and exit
}
}
}
void loop() {
if(!digitalRead(B1)){ // If button (pin #8) is pressed
i = 0;
hour = edit(5, 0, hour);
minute = edit(8, 0, minute);
date = edit(5, 1, date);
month = edit(8, 1, month);
year = edit(13, 1, year);
// Convert decimal to BCD
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
// End conversion
// Write data to DS3231 RTC
Wire.beginTransmission(0x68); // Start I2C protocol with DS3231 address
Wire.write(0); // Send register address
Wire.write(0); // Reset sesonds and start oscillator
Wire.write(minute); // Write minute
Wire.write(hour); // Write hour
Wire.write(1); // Write day (not used)
Wire.write(date); // Write date
Wire.write(month); // Write month
Wire.write(year); // Write year
Wire.endTransmission(); // Stop transmission and release the I2C bus
delay(200); // Wait 200ms
}
Wire.beginTransmission(0x68); // Start I2C protocol with DS3231 address
Wire.write(0); // Send register address
Wire.endTransmission(false); // I2C restart
Wire.requestFrom(0x68, 7); // Request 7 bytes from DS3231 and release I2C bus at end of reading
second = Wire.read(); // Read seconds from register 0
minute = Wire.read(); // Read minuts from register 1
hour = Wire.read(); // Read hour from register 2
Wire.read(); // Read day from register 3 (not used)
date = Wire.read(); // Read date from register 4
month = Wire.read(); // Read month from register 5
year = Wire.read(); // Read year from register 6
DS3231_display(); // Diaplay time & calendar
if(previous_second != second){
previous_second = second;
// Read humidity
RH = dht.readHumidity() * 10;
//Read temperature in degree Celsius
Temp = dht.readTemperature() * 10;
if(Temp < 0){
temperature[0] = '-'; // If temperature < 0 put minus sign
Temp = abs(Temp); // Absolute value of 'Temp'
}
else
temperature[0] = ' '; // otherwise (temperature > 0) put space
temperature[1] = (Temp / 100) % 10 + 48;
temperature[2] = (Temp / 10) % 10 + 48;
temperature[4] = Temp % 10 + 48;
if(RH >= 1000)
humidity[0] = '1'; // If humidity >= 100.0% put '1' of hundreds
else
humidity[0] = ' '; // otherwise (humidity < 100) put space
humidity[1] = (RH / 100) % 10 + 48;
humidity[2] = (RH / 10) % 10 + 48;
humidity[4] = RH % 10 + 48;
lcd.setCursor(6, 2);
lcd.print(temperature);
lcd.setCursor(6, 3);
lcd.print(humidity);
// Send data to Arduino IDE serial monitor
Serial.print(Calendar);
Serial.print(" | ");
Serial.print(Time);
Serial.print(" | ");
Serial.print(temperature);
Serial.print("°C | ");
Serial.println(humidity);
if(sd_ok) { // If SD card initialization was OK
dataLog = SD.open("Logger.txt", FILE_WRITE); // Open file Logger.txt
if(dataLog) { // if the file opened okay, write to it:
dataLog.print(Calendar);
dataLog.print(" | ");
dataLog.print(Time);
dataLog.print(" | ");
dataLog.print(temperature);
dataLog.print("°C | ");
dataLog.println(humidity);
dataLog.close(); // Close the file
}
}
}
delay(50); // Wait 50ms
}
Thank you sir..
Can you pls provide me the pcb layout of above circuit which has sd card modulw
For the reading and storing of data every 1 minute ?
Thank you sir.
please i have somme errors in my project : [MMC cmd] command unsupported and the compulation failed because the mmc has not been initialised. please help me
Hi, I have got 2×16 LCD can I use this or I need to buy 20×4? What do I need to change in the code to use 2×16? Great project 🙂
If you use 16×2 LCD then the 3rd and the 4th rows will not be printed, this means you’ll not be able to see temperature and humidity values.
Otherwise, you’ve to do some modifications to the C code in order to print time, date, temperature & humidity values.
Very interesting project, thanks you for your sharing
Sir, Great Project and Easy to Implement, Want to how to Increase the logging interval (if want log temperature humidity every 10 min) what should be changed in C code. Please let us know. It Great help for us.
thank you.
humidity[] = (RH / 100) % 10 + 48; What is the use of +48 ?
Just for converting it to ASCII format.
it is not reading humidity why
can be this setup used for 20×4 i2c ?