Time to put week two together. No new parts — today is about combining what you know into a sketch that’s tidy enough to keep running on your desk.
Wiring
Day 10’s DHT22 and day 12’s LCD, together:
| Part | Pin | Uno |
|---|---|---|
| DHT22 | + / − / OUT | 5V / GND / pin 2 |
| LCD backpack | VCC / GND / SDA / SCL | 5V / GND / A4 / A5 |
Both share the Uno’s 5V and GND — use the breadboard’s power rails.
If day 12 found your LCD at 0x3F, change LCD_ADDRESS before uploading.
What the screen shows
- Line 1: temperature and humidity, updated every 2.5 s.
- Line 2: flips every 4 s between today’s low/high (since power-on) and the feels-like temperature.
What to notice in the code
- Two millis() timers (day 7): one for reading the sensor, one for flipping the page. Neither blocks the other.
- Small functions (day 9):
printLine(),showNow(),showPage().loop()reads like a summary. printLine()pads every line to 16 characters with%-16s, so a short line overwrites a long one completely — no stray characters left behind.dtostrf()turns afloatinto text. On the Uno,snprintfcan’t do%f(it’s left out to save memory), which surprises everyone once.- Errors are shown, not hidden. A failed read puts “Sensor error” on screen instead of an old value that looks right.
Make it permanent
- Power it from any 5 V phone charger through the USB port.
- Keep the DHT22 away from the LCD and the Uno’s regulator — they warm up a little and the reading creeps up.
Try it
- Add day 3’s button to reset the min/max.
- Light day 7’s LED when humidity goes above 80 % — a monsoon mould warning for your cupboard.
You’re done when…
- Line 1 shows something like
29.4°C RH 62%and updates every few seconds. - Line 2 alternates every 4 s between
Lo28.9 Hi29.6andFeels 31.2°C. - Breathing on the sensor pushes the humidity up and, if it warms the sensor, the Hi value too — and Lo/Hi survive the page flips.
- Pulling the DATA wire shows
Sensor erroron line 1 within a few seconds. - Powered from a phone charger instead of the laptop, it starts on its own.
Next week: Wi-Fi. You’ll move to the ESP32.
Today's code
Verified — core avr 1.8.8, DHT sensor library 1.4.7, 3 Nov 2026Compile-only
// Day 15 — Week-two project: a desk weather display (Arduino Uno / Nano)
// DHT22 module: + → 5V, - → GND, OUT → pin 2 (10 k pull-up to 5V on a bare sensor).
// 16x2 LCD with I2C backpack: VCC → 5V, GND → GND, SDA → A4, SCL → A5. Address 0x27 (or 0x3F).
// Line 1: temperature and humidity now. Line 2 changes every 4 s: today's min/max, then "feels like".
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const uint8_t DHT_PIN = 2;
const uint8_t LCD_ADDRESS = 0x27; // change to 0x3F if day 12's sketch found that instead
const unsigned long READ_EVERY = 2500;
const unsigned long PAGE_EVERY = 4000;
DHT dht(DHT_PIN, DHT22);
LiquidCrystal_I2C lcd(LCD_ADDRESS, 16, 2);
float tempNow = NAN, humNow = NAN;
float tempMin = 1000, tempMax = -1000;
unsigned long lastRead = 0, lastPage = 0;
int page = 0;
void printLine(int row, const char* text) {
char padded[17];
snprintf(padded, sizeof padded, "%-16s", text); // pad with spaces to clear old text
lcd.setCursor(0, row);
lcd.print(padded);
}
// AVR snprintf has no %f, so dtostrf() turns a float into text first.
void showNow() {
char t[8], line[17];
dtostrf(tempNow, 4, 1, t);
snprintf(line, sizeof line, "%s%cC RH %d%%", t, (char)223, (int)(humNow + 0.5)); // 223 = ° on these LCDs
printLine(0, line);
}
void showPage() {
char a[8], b[8], line[17];
if (page == 0) {
dtostrf(tempMin, 4, 1, a);
dtostrf(tempMax, 4, 1, b);
snprintf(line, sizeof line, "Lo%s Hi%s", a, b);
} else {
dtostrf(dht.computeHeatIndex(tempNow, humNow, false), 4, 1, a);
snprintf(line, sizeof line, "Feels %s%cC", a, (char)223);
}
printLine(1, line);
}
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
printLine(0, "Desk weather");
printLine(1, "Reading...");
}
void loop() {
unsigned long now = millis();
if (now - lastRead >= READ_EVERY) {
lastRead = now;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
printLine(0, "Sensor error");
Serial.println(F("DHT22 read failed"));
return;
}
tempNow = t;
humNow = h;
if (t < tempMin) tempMin = t;
if (t > tempMax) tempMax = t;
showNow();
Serial.print(t, 1);
Serial.print(F(" C, "));
Serial.print(h, 0);
Serial.println(F(" %"));
}
if (!isnan(tempNow) && now - lastPage >= PAGE_EVERY) {
lastPage = now;
showPage();
page = 1 - page; // flip between 0 and 1
}
}// Day 15 — Week-two project: a desk weather display (Arduino Uno / Nano)
// DHT22 module: + → 5V, - → GND, OUT → pin 2 (10 k pull-up to 5V on a bare sensor).
// 16x2 LCD with I2C backpack: VCC → 5V, GND → GND, SDA → A4, SCL → A5. Address 0x27 (or 0x3F).
// Line 1: temperature and humidity now. Line 2 changes every 4 s: today's min/max, then "feels like".
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const uint8_t DHT_PIN = 2;
const uint8_t LCD_ADDRESS = 0x27; // change to 0x3F if day 12's sketch found that instead
const unsigned long READ_EVERY = 2500;
const unsigned long PAGE_EVERY = 4000;
DHT dht(DHT_PIN, DHT22);
LiquidCrystal_I2C lcd(LCD_ADDRESS, 16, 2);
float tempNow = NAN, humNow = NAN;
float tempMin = 1000, tempMax = -1000;
unsigned long lastRead = 0, lastPage = 0;
int page = 0;
void printLine(int row, const char* text) {
char padded[17];
snprintf(padded, sizeof padded, "%-16s", text); // pad with spaces to clear old text
lcd.setCursor(0, row);
lcd.print(padded);
}
// AVR snprintf has no %f, so dtostrf() turns a float into text first.
void showNow() {
char t[8], line[17];
dtostrf(tempNow, 4, 1, t);
snprintf(line, sizeof line, "%s%cC RH %d%%", t, (char)223, (int)(humNow + 0.5)); // 223 = ° on these LCDs
printLine(0, line);
}
void showPage() {
char a[8], b[8], line[17];
if (page == 0) {
dtostrf(tempMin, 4, 1, a);
dtostrf(tempMax, 4, 1, b);
snprintf(line, sizeof line, "Lo%s Hi%s", a, b);
} else {
dtostrf(dht.computeHeatIndex(tempNow, humNow, false), 4, 1, a);
snprintf(line, sizeof line, "Feels %s%cC", a, (char)223);
}
printLine(1, line);
}
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
printLine(0, "Desk weather");
printLine(1, "Reading...");
}
void loop() {
unsigned long now = millis();
if (now - lastRead >= READ_EVERY) {
lastRead = now;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
printLine(0, "Sensor error");
Serial.println(F("DHT22 read failed"));
return;
}
tempNow = t;
humNow = h;
if (t < tempMin) tempMin = t;
if (t > tempMax) tempMax = t;
showNow();
Serial.print(t, 1);
Serial.print(F(" C, "));
Serial.print(h, 0);
Serial.println(F(" %"));
}
if (!isnan(tempNow) && now - lastPage >= PAGE_EVERY) {
lastPage = now;
showPage();
page = 1 - page; // flip between 0 and 1
}
}