Created
May 19, 2025 05:47
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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