#include <OneWire.h>
#include <DallasTemperature.h>
#include <PID_v1.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// DS18B20 settings
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// PID settings
#define SSR_PIN 9 // PWM pin to control SSR
double Setpoint; // Loaded from EEPROM
double Input;
double Output;
double Kp = 10.0, Ki = 0.5, Kd = 0.1; // Adjusted for heater response
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// Button settings
#define INC_BUTTON 3
#define DEC_BUTTON 4
int lastIncState = HIGH;
int lastDecState = HIGH;
unsigned long lastDebounceTime = 0;
const long debounceDelay = 10;
// EEPROM settings
#define EEPROM_ADDRESS 0
// Timing
unsigned long previousMillis = 0;
const long interval = 1000; // 1-second update cycle
void setup() {
Serial.begin(9600);
// Initialize OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("PID Heater Control");
display.display();
// Initialize DS18B20
sensors.begin();
// Initialize PID
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255); // PWM range
pinMode(SSR_PIN, OUTPUT);
digitalWrite(SSR_PIN, LOW); // SSR off initially
// Initialize buttons with internal pull-ups
pinMode(INC_BUTTON, INPUT_PULLUP);
pinMode(DEC_BUTTON, INPUT_PULLUP);
// Load setpoint from EEPROM
EEPROM.get(EEPROM_ADDRESS, Setpoint);
if (isnan(Setpoint) || Setpoint < 0 || Setpoint > 100) {
Setpoint = 30.0; // Default 30°C
EEPROM.put(EEPROM_ADDRESS, Setpoint);
}
}
void loop() {
unsigned long currentMillis = millis();
// Handle button presses
int incReading = digitalRead(INC_BUTTON);
int decReading = digitalRead(DEC_BUTTON);
// Increase setpoint by 2 degrees
if (incReading != lastIncState) {
lastDebounceTime = currentMillis;
}
if ((currentMillis - lastDebounceTime) > debounceDelay && incReading == LOW) {
Setpoint += 0.05; // Changed from 1.0 to 2.0
if (Setpoint > 100) Setpoint = 100;
EEPROM.put(EEPROM_ADDRESS, Setpoint);
}
lastIncState = incReading;
// Decrease setpoint by 2 degrees
if (decReading != lastDecState) {
lastDebounceTime = currentMillis;
}
if ((currentMillis - lastDebounceTime) > debounceDelay && decReading == LOW) {
Setpoint -= 0.05; // Changed from 1.0 to 2.0
if (Setpoint < 0) Setpoint = 0;
EEPROM.put(EEPROM_ADDRESS, Setpoint);
}
lastDecState = decReading;
// Update PID and display
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Read temperature
sensors.requestTemperatures();
Input = sensors.getTempCByIndex(0);
// Compute PID output
myPID.Compute();
// Apply PWM to SSR
analogWrite(SSR_PIN, Output); // 0-255 controls SSR duty cycle
// Update OLED
display.clearDisplay();
display.setCursor(0, 0);
display.println("PID Heater Control");
display.setCursor(0, 16);
display.print("Setpoint: ");
display.print(Setpoint);
display.println(" C");
display.setCursor(0, 32);
display.print("Temp: ");
display.print(Input);
display.println(" C");
display.setCursor(0, 48);
display.print("Output: ");
display.print(Output);
display.println("/255");
display.display();
// Serial debug
Serial.print("Setpoint: ");
Serial.print(Setpoint);
Serial.print(" C, Temp: ");
Serial.print(Input);
Serial.print(" C, Output: ");
Serial.println(Output);
}
}