Skip to content

Instantly share code, notes, and snippets.

@benrules2
Created February 20, 2021 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benrules2/1d34c74a25401d482e66a981b2e3e174 to your computer and use it in GitHub Desktop.
Save benrules2/1d34c74a25401d482e66a981b2e3e174 to your computer and use it in GitHub Desktop.
Sketch to control a relay and thermocouple Coffee Roaster
#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