Electric Biochar Reactor Arduino Circuit and Code

The control device is an Arduino Uno, the IDE is V 1.8.19

The display device is an SSD1306 oled 0.96 inch
The SSD1306 has four pins:
GND - connect to (-);
VCC - connect to 3.3VDC or 5.0 VDC;
SCL (clock signal) - connect to A4 analog pin on Uno;
SDA (data) - connect to A5 pin on Uno

The temperature sensor is a MAX6675 Type-K thermocouple and amplifier
two thermocouple connections to the amplifier plus five amplifier pins:
GND - connect to (-)
VCC - connect to 3.3VDC
SCK - connect to Uno digital; choose D13
DO/SO - connect to Uno digital; choose D12
SC - connect to Uno digital; choose D11

There is a 10kohm potentiometer with one side grounded and the other side at 5VDC. The POTPIN variable reads the voltage at the potentiometer variable output.
There is an LED with a 220ohm series resistor between A1 and ground, parallel to the control relay signal, to indicate when the relay is being called to engage.

Control Sketch:
(this page editor treats some asterisks as format-italics, so some spaces have been inserted here which may render copied text into bad format for the Arduino IDE. Copying from the post-editor might resolve such an error if it is not otherwise obvious to the user.)

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <MAX6675.h>

#define MAXDO 12 //DO or SO pin on Max6675 to D12
#define MAXCLK 13 //SCK to D13
#define MAXCS 11 //CS to D11
#define POTPIN A0 // voltage on A0 will define setpoint
#define RELAY A1 // A1 calls relay to engage

#define OUTMIN 0 // the minimum PID output
#define OUTMAX 255 // the maximum PID output
#define KP 5 //PID proportionality constant
#define KD 200 //PID rate constant (millisec/degree)
#define KI .00001 //PID integral constant (1/deg-millisec)

float temp; //temp reading from thermocouple
float SetPoint; //calculated from 10k pot 0-5V
float SPMin = 250.; //minimum setpoint (250C for pyrolysis)
float SPMax = 550.; //max setpoint (550C)
float output; //PID output for relay control
float PinOut; //analog reading for determining setpoint
float error; // temperature - setpoint
float POut; // proportional control output contribution
float lastime; //processor clock time in prior loop
float lasterror; //setpoint error in prior loop
float tstep; // time step for PID control
float estep; // error change for PID control
float istep; // increment of integral error * time
float isum; // total integral error * time
float IOut; // integral control output contribution
float DOut; //derivative control output contribution
unsigned long ton; //relay ON time this relay cycle
unsigned long tonsum = 0; //cumulative ON time
unsigned long toff; //relay OFF time this relay cycle
int RELAYSTATE = 0; //relay is off initially
unsigned long now; //the current time to check relay timer
unsigned long before = 900; //the last time the relay status changed
// initialize to 900 = 3 x 300ms delays to first use of “before”.

#define OLED_RESET -1
#define DIS_WIDTH 128
#define DIS_HEIGHT 32
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(DIS_WIDTH, DIS_HEIGHT, &Wire, OLED_RESET);
// display call defines A4 and A5 connections for this device
MAX6675 thermoCouple;

void setup() {
Serial.begin(9600); //in case we need
// to communicate to the serial monitor
delay(500);
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
thermoCouple.begin(MAXCLK, MAXCS, MAXDO);
thermoCouple.setSPIspeed(4000000);
delay(300); // 250ms min frequency of thermocouple reads
int status = thermoCouple.read();
if (status != STATUS_OK)
{
display.println(“ERROR”);
display.display();
}
temp = thermoCouple.getTemperature();

/* Serial prints for troubleshooting
Serial.print("temp ");
Serial.println(temp);//initial temp */

PinOut = analogRead(POTPIN); //0-1024 reading on POTPIN
SetPoint = SPMin + (PinOut / 1024)*(SPMax-SPMin);

/* Serial.print("SP ");
Serial.println(SetPoint);// */

error = temp - SetPoint; //initial error
lastime = millis(); //initialize lastime counter
lasterror = error; //initialize lasterror counter
isum = 0.; //initialize integral response
} //end of setup

void loop()
{
delay(700); // this is the only recurring delay 250 minimum
PinOut = analogRead(POTPIN); //0-1024 reading on POTPIN
SetPoint = SPMin + (PinOut/ 1024)*(SPMax - SPMin); // recheck SP
thermoCouple.begin(MAXCLK, MAXCS, MAXDO);
int status = thermoCouple.read();
// Serial.print(status);
temp = thermoCouple.getTemperature();

display.clearDisplay();
display.display();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.cp437(true);
display.print("T= “);
display.display();
display.print(temp, 0);
display.print(” SP= ");
display.println(SetPoint, 0); //temp and set-point displayed
display.display(); //temp and set-point displayed

now = millis();
error = temp - SetPoint; // this is usually negative
POut = -KP * error; //proportional response to error
if(POut > OUTMAX) {
POut = OUTMAX; //proportional response cap
} else {
if(POut < -OUTMAX) {
POut = -OUTMAX;
}
}
tstep = now-lastime; //time since last loop - a positive value
lastime = now; //record time in this loop pass
estep = error - lasterror; //error change
lasterror = error; //record error in this loop pass
istep = error * tstep; //recent error duration - usually negative
isum = isum + istep; //cumulative error X duration
if(isum < -12000000) { //2 minute of -100 degree error - arbitrary
isum = -12000000;
} else {
if(isum > 12000000) { //2 min. of +100 degree error
isum = 12000000;
}
}
IOut = -KI * isum; //integral response to cumulative error
if(IOut >= OUTMAX) {
IOut = OUTMAX;
}
DOut = -KD * (estep/tstep); //derivative response to error change
/* because tstep is less than one second, and estep
has “noise” due to relay cycling this parameter is
not employed nor has there been troubleshooting*/
output = POut + IOut + DOut;//cumulative PID response

// note there can be offsetting contributions (+/-) to output
// need different integral reset criterion. REVISIT
// is integral reset necessary? Yes, it remains maxxed long-term otherwise

if(output >= OUTMAX) {
output = OUTMAX; //total controller response cap
} else {
if(output <= OUTMIN) {
output = OUTMIN;
}
}

display.print("P-I-D: “);
display.print(POut,0);
display.print(” “);
display.print(IOut,0);
display.print(” ");
display.println(DOut,0);
display.display();

/*Serial.print("output = ");
Serial.println(output);
Serial.print(output/255); */

ton = ((output/255) * 48000) + 1000 ; // on time 49000 ms max
toff = 50000 - ton; //relay on/off cycle time is 50 seconds

/*Serial.print("time on (ms): ");
Serial.println(ton);
Serial.print("RELAYSTATE: ");
Serial.println(RELAYSTATE); */

if(RELAYSTATE == 255) {
tonsum = tonsum + tstep;
// add last cycle time to the on-time total
}
if(RELAYSTATE == 0) {
if((now - before) >= toff) {
RELAYSTATE = 255;
/if the relay was off and toff has passed
turn the relay on and reset “before”
/
before = now; // before records last relay state change
}
} else {
if((now - before) >= ton) {
RELAYSTATE = 0;
/* else, if the relay was on and ton has passed,
turn the relay off and reset “before”*/
before = now;
}
/ * else, if state change is not due, loop again */
}

analogWrite(RELAY, RELAYSTATE); //5VDC to control AC Power relay and LED

float time = millis(); //compute the nominal hh:mm:ss
int hour = time/3600000;
int min = time/60000 - (hour60);
int sec = time/1000 - (min
60) - (hour*3600);

display.print("run time: “);
display.print(hour);
display.print(”: “);
display.print(min);
display.print(”: ");
display.println(sec);
display.print("ON time (s): ");
display.print(tonsum/1000);
display.display();
}
End of Sketch

Data displays:
Current temperature and Setpoint temperature
PID response factors
Time since start (hh:mm:ss)
Heat on time since start (seconds) - for calculating cumulative energy input
LED light to show "heat ON’’

the amplifier component for the thermocouple (MAX6675) failed on first test attempt. The arduino sketch now reads gibberish instead of a temperature value. I constructed a simple transistor voltage amplifier from available components, but could not detect a useful output change from the thermocouple so although it still shows low resistance, I cannot confirm that it is functional. I am abandoning this design for the foreseeable future.

I replaced the thermocouple amplifier, new one works