Created
February 20, 2021 21:09
-
-
Save benrules2/1d34c74a25401d482e66a981b2e3e174 to your computer and use it in GitHub Desktop.
Sketch to control a relay and thermocouple Coffee Roaster
This file contains 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 "MAX31855.h" | |
const int doPin = 7; | |
const int csPin = 6; | |
const int clPin = 5; | |
const int relayPin = 13; | |
MAX31855 tc(clPin, csPin, doPin); | |
float getTemp() { | |
float temp = 0; | |
for (int i = 0; i < 3; i++) { | |
temp += tc.getTemperature(); | |
delay(5); | |
} | |
return temp / 3; | |
} | |
int getSecondsSinceStart() { | |
return millis() / 1000; | |
} | |
int getHeaterOffTime(float targetTemp, int maxDelay) { | |
int status = tc.read(); | |
if (status != 0) { | |
Serial.print("Error status in probe, disabling heater: "); | |
Serial.println(status); | |
return maxDelay; | |
} | |
float currentTemp = getTemp(); | |
// Error describes how far off the target temperature are. This should scale how long heater stays on, or off. | |
float error = max(0, currentTemp) / targetTemp; | |
float scalingFactor = 2; | |
float heatDelay = error * error * error * (maxDelay/scalingFactor) - maxDelay*0.2; | |
// make sure delay says between 0 and maxDelay | |
heatDelay = max(0, min(maxDelay, heatDelay)); | |
// Serial.println("Current Temp, Target Temp, Cooling Period"); | |
Serial.print(currentTemp); | |
Serial.print(","); | |
Serial.print(targetTemp); | |
Serial.print(","); | |
Serial.print(heatDelay); | |
Serial.println(); | |
return heatDelay; | |
} | |
// This function allows a warm up phase, first target temp, and second target temp, | |
// and finally sets target temp to zero to allow the fan to cool the beans | |
float getTargetTemp() { | |
//Time to bring roaster and beans up to a casual warm temp | |
const int preHeatTimeSeconds = 120; | |
float preHeatTemp = 120; | |
//Time at the first roast temp | |
const int firstTempTimeMins = 9; | |
float firstRoastTemp = 150; | |
//Time at the second roast temp | |
const int secondTempTimeMins = 4; | |
float secondRoastTemp = 200; | |
int secondsSinceStart = getSecondsSinceStart(); | |
bool startRoast = secondsSinceStart > preHeatTimeSeconds; | |
bool preheat = !startRoast; | |
bool startSecondPhase = secondsSinceStart > preHeatTimeSeconds + firstTempTimeMins * 60; | |
bool cooldown = secondsSinceStart > preHeatTimeSeconds + (firstTempTimeMins + secondTempTimeMins) * 60; | |
// Check roasting conditions in reverse order because once these bool values are true, | |
// they remain true even as subsequent phases start | |
if (cooldown) { | |
return 0; | |
} else if (startSecondPhase) { | |
return secondRoastTemp; | |
} else if (startRoast) { | |
return firstRoastTemp; | |
} else if (preheat) { | |
return preHeatTemp; | |
} | |
return 0; | |
} | |
void setup() | |
{ | |
Serial.begin(115200); | |
Serial.print("Starting loop: "); | |
Serial.println(MAX31855_VERSION); | |
Serial.println(); | |
tc.begin(); | |
pinMode(relayPin, OUTPUT); | |
} | |
void loop() | |
{ | |
float targetTemp = getTargetTemp(); | |
int updateInterval = 500; | |
int heaterOffDelay = getHeaterOffTime(targetTemp, updateInterval); | |
int heaterOnDelay = updateInterval - heaterOffDelay; | |
// Turn on heater | |
digitalWrite(relayPin, HIGH); | |
delay(heaterOnDelay); | |
delay(5); | |
digitalWrite(relayPin, LOW); | |
delay(heaterOffDelay); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment