Skip to content

Instantly share code, notes, and snippets.

@mutoo
Created May 19, 2025 05:47
Show Gist options
  • Save mutoo/2ef606e23e6543cc39312dabec58a724 to your computer and use it in GitHub Desktop.
Save mutoo/2ef606e23e6543cc39312dabec58a724 to your computer and use it in GitHub Desktop.
A simple Arudino controller for triggering 2-wire dry contact heater with a 5v relay. It uses 1602 LCD and a rotary encoder to adjust the temperature.
#include <LiquidCrystal.h>
#include <DHT11.h>
// ===== Pin Definitions =====
#define DHTPIN 8 // DHT11 data pin
DHT11 dht11(DHTPIN);
// LCD pins: RS, E, D4, D5, D6, D7
const int rsPin = 12;
const int enPin = 11;
const int d4Pin = 4;
const int d5Pin = 5;
const int d6Pin = 6;
const int d7Pin = 7;
LiquidCrystal lcd(rsPin, enPin, d4Pin, d5Pin, d6Pin, d7Pin);
// Rotary encoder pins
const int pinEncoderCLK = 2;
const int pinEncoderDT = 3;
// Relay control pin
const int pinRelay = 10;
// ===== Control Parameters =====
float targetTemp = 20.0; // Desired temperature (°C)
float smoothedTemp = 20.0; // Smoothed measured temperature
const float alpha = 0.8; // Smoothing factor (0 < α < 1)
const float hysteresis = 0.5; // Hysteresis band ±0.5°C
// ===== State Variables =====
bool relayOn = false; // Relay state
volatile bool encA_last = LOW; // Last state of encoder CLK
volatile bool encB_last = LOW; // Last state of encoder DT
void setup() {
// Initialize relay pin
pinMode(pinRelay, OUTPUT);
digitalWrite(pinRelay, LOW); // Relay off
// Initialize LCD (16 cols × 2 rows)
lcd.begin(16, 2);
lcd.clear();
// Initialize encoder pins with pullups
pinMode(pinEncoderCLK, INPUT_PULLUP);
pinMode(pinEncoderDT, INPUT_PULLUP);
encA_last = digitalRead(pinEncoderCLK);
encB_last = digitalRead(pinEncoderDT);
// Attach interrupt on CLK pin
attachInterrupt(digitalPinToInterrupt(pinEncoderCLK), handleEncoder, CHANGE);
}
void loop() {
// 1. Read temperature & humidity from DHT11
float newTemp = dht11.readTemperature(); // °C
float hum = dht11.readHumidity(); // %
// If reading failed, skip update
if (!isnan(newTemp)) {
// 2. Exponential smoothing of temperature
smoothedTemp = alpha * newTemp + (1 - alpha) * smoothedTemp;
}
// 3. Hysteresis control for relay
if (!relayOn && smoothedTemp < targetTemp - hysteresis) {
relayOn = true;
digitalWrite(pinRelay, LOW);
} else if (relayOn && smoothedTemp > targetTemp + hysteresis) {
relayOn = false;
digitalWrite(pinRelay, HIGH);
}
// 4. Update LCD display
// lcd.clear();
// Line 1: Setpoint and Humidity
lcd.setCursor(0, 0);
lcd.print("Set:");
lcd.print(targetTemp, 1);
lcd.print((char)223); // degree symbol
lcd.print("C H:");
if (!isnan(hum)) {
lcd.print(hum, 0);
} else {
lcd.print("--");
}
lcd.print("%");
// Line 2: Current temperature and relay state
lcd.setCursor(0, 1);
lcd.print("Cur:");
lcd.print(smoothedTemp, 1);
lcd.print((char)223);
lcd.print("C ");
lcd.print(relayOn ? "ON " : "OFF");
delay(1000); // Update every second
}
// Interrupt service routine for rotary encoder
void handleEncoder() {
bool encA = digitalRead(pinEncoderCLK);
bool encB = digitalRead(pinEncoderDT);
// Only act on state change of CLK
if (encA != encA_last) {
// Determine rotation direction
if (encA != encB) {
targetTemp -= 0.5; // Clockwise → increase
} else {
targetTemp += 0.5; // Counter-clockwise → decrease
}
// Clamp targetTemp within reasonable bounds
if (targetTemp < 5.0) targetTemp = 5.0;
if (targetTemp > 30.0) targetTemp = 30.0;
}
encA_last = encA;
encB_last = encB;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment