Programming the Heater
Using Arduino (Teensy 3.1 also works) to control H-bridge drivers and PID.
Last updated
Using Arduino (Teensy 3.1 also works) to control H-bridge drivers and PID.
Last updated
Download the code file below:
Alternatively, you can implement a shut-down system where if the tempertaure goes way above the recommended temperature or if too much current is drawn; it can shut down automatically.
/**
Author: Sol Choi
Name: A PID controlled Peltier heater/cooler upon a button interaction
Basic rules:
1) Temperature is regulated to keep the sugar glass melted to around 55 celcius degrees (In hot mode).
2) Once button is pressed, it drops the temperature by reversing polarity
3) Once it reaches the cooled temperature (minTemp 20), it goest through 9s stableTime to declare it's been cooled.
4) Then it switches back to hot mode.
Power supply: Would need three power supplies: 12v for the fans (6pcs), 6v for two motors each, USB (3.3v) for Teensy modules.
** Feel free to use/distribute/experiment.
**/
#include <PID_v1_bc.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define tmp1 14
#define tmp2 15
#define tmp3 16
#define tmp4 17
#define oneButton 13
#define twoButton 12
#define oneFan 18
#define twoFan 19
#define extraFan 20
#define extraExtraFan 20
OneWire oneWire(tmp1);
OneWire twoWire(tmp2);
DallasTemperature sensors1(&oneWire);
DallasTemperature sensors2(&twoWire);
double constTemp1 = 55;
double constTemp2 = 55;
double coldTemp = 34;
double minTemp = 20;
double maxTemp = 70; // due to temperature gradient, around 50 is advised.
double cycle1, cycle2;
double currentTemp1, currentTemp2;
double Kp = 4.0, Ki = 5.0, Kd = 1.0;
PID pidControl1(¤tTemp1, &cycle1, &constTemp1, Kp, Ki, Kd, DIRECT);
PID pidControl2(¤tTemp2, &cycle2, &constTemp2, Kp, Ki, Kd, DIRECT);
#define oneHot 2
#define oneCold 4
#define twoHot 6
#define twoCold 8
#define oneEn 5
#define twoEn 9
unsigned long previousMillis = 0;
unsigned long stableTime = 9000;
unsigned long interval = 3000;
bool oneColdState = false;
int oneButtonState = 0;
bool twoColdState = false;
bool twoButtonState = 0;
void printTemp();
void printDuty();
void goDuty();
void setup() {
Serial.begin(9600);
sensors1.begin();
sensors2.begin();
pinMode(oneHot, OUTPUT);
pinMode(oneCold, OUTPUT);
pinMode(twoHot, OUTPUT);
pinMode(twoCold, OUTPUT);
pinMode(oneEn, OUTPUT);
pinMode(twoEn, OUTPUT);
pinMode(oneButton, INPUT_PULLUP);
pinMode(oneFan, OUTPUT);
pinMode(twoButton, INPUT_PULLUP);
pinMode(twoFan, OUTPUT);
pinMode(extraFan, OUTPUT);
pinMode(extraExtraFan, OUTPUT);
pidControl1.SetMode(AUTOMATIC);
pidControl1.SetOutputLimits(0, 255);
pidControl2.SetMode(AUTOMATIC);
pidControl2.SetOutputLimits(0, 255);
analogWrite(oneEn, 150);
analogWrite(twoEn, 150);
digitalWrite(oneHot, HIGH);
digitalWrite(oneCold, LOW);
digitalWrite(twoHot, HIGH);
digitalWrite(twoCold, LOW);
digitalWrite(oneFan, LOW);
digitalWrite(twoFan, HIGH);
digitalWrite(extraFan, LOW);
digitalWrite(extraExtraFan, HIGH);
}
void loop() {
// alternatively -> use this shutting down mechanism
// if (currentTemp1 <= minTemp || currentTemp1 >= maxTemp) {
// digitalWrite(oneHot, LOW);
// digitalWrite(oneCold, LOW);
// Serial.println("Temperature out of range. Shutting down Peltier module.");
// } else {
// digitalWrite(oneHot, HIGH);
// digitalWrite(oneCold, HIGH);
// }
// delay(1000);
// if (currentTemp2 <= minTemp || currentTemp2 >= maxTemp) {
// digitalWrite(twoHot, LOW);
// digitalWrite(twoCold, LOW);
// Serial.println("Temperature out of range. Shutting down Peltier module.");
// } else {
// digitalWrite(twoHot, HIGH);
// digitalWrite(twoCold, HIGH);
// }
// delay(1000);
unsigned long currentMillis = millis();
oneButtonState = digitalRead(oneButton);
if (oneButtonState == HIGH) {
delay(100);
if (digitalRead(oneButton) == HIGH) {
oneColdState = !oneColdState;
if (oneColdState) {
digitalWrite(oneHot, LOW);
digitalWrite(oneCold, HIGH);
digitalWrite(oneFan, HIGH);
Serial.println("One wants to be cold. IN1 LOW, IN2 HIGH");
}
}
}
if (oneColdState && currentTemp1 <= coldTemp && currentMillis - previousMillis >= stableTime) {
delay(1000);
digitalWrite(oneHot, HIGH);
digitalWrite(oneCold, LOW);
digitalWrite(oneFan, LOW);
oneColdState = false;
oneButtonState = false;
// when switching back, a ramping may be required.
Serial.println("One is cooled. Back to normal.");
}
twoButtonState = digitalRead(twoButton);
if (twoButtonState == HIGH) {
delay(100);
if (digitalRead(twoButton) == HIGH) {
twoColdState = !twoColdState;
if (twoColdState) {
digitalWrite(twoHot, LOW);
digitalWrite(twoCold, HIGH);
digitalWrite(twoFan, HIGH);
Serial.println("Two wants to be cold. IN1 LOW, IN2 HIGH");
}
}
}
if (twoColdState && currentTemp2 <= coldTemp && currentMillis - previousMillis >= interval) {
delay(1000);
digitalWrite(twoHot, HIGH);
digitalWrite(twoCold, LOW);
digitalWrite(twoFan, LOW);
// digitalWrite(twoFan, LOW);
twoColdState = false;
twoButtonState = false;
// when switching back, a ramping may be required.
Serial.println("Two is cooled. Back to normal.");
}
// digitalWrite(oneHot, HIGH);
// digitalWrite(oneCold, LOW);
// digitalWrite(twoHot, HIGH);
// digitalWrite(twoCold, LOW);
constTemp1 = constrain(constTemp1, minTemp, maxTemp);
sensors1.requestTemperatures();
currentTemp1 = sensors1.getTempCByIndex(0);
pidControl1.Compute();
constTemp2 = constrain(constTemp2, minTemp, maxTemp);
sensors2.requestTemperatures();
currentTemp2 = sensors2.getTempCByIndex(0);
pidControl2.Compute();
analogWrite(oneEn, cycle1);
analogWrite(twoEn, cycle2);
goDuty();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
printDuty();
printTemp();
}
delay(1000);
}
void printTemp() {
Serial.print("Temperature 1 is: ");
Serial.print(currentTemp1);
Serial.println(" °C");
Serial.print("Temperature 2 is: ");
Serial.print(currentTemp2);
Serial.println(" °C");
}
void goDuty() {
analogWrite(oneEn, (int)cycle1);
analogWrite(twoEn, (int)cycle2);
}
void printDuty() {
Serial.print("PWM 1 Duty Cycle: ");
Serial.println(cycle1);
Serial.print("PWM 2 Duty Cycle: ");
Serial.println(cycle2);
}