/*Libraries*/
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <SD.h>
#include <PID_v1.h>
#include <Adafruit_MAX31855.h>
/*TFT*/
#define TFT_SCLK 13
#define TFT_MOSI 11
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
/*SD card*, clk 13, miso 12, mosi 11*/
const int chipSelect = A0;
/* 6 X 3 array for SD card read data */
#define ROW_DIM 6
#define COL_DIM 3
int array[ROW_DIM][COL_DIM];
int i = 0; // First array index.
int j = 0; // Second array index
size_t n; // Length of returned field with delimiter.
char str[20]; // Must hold longest field with delimiter and zero byte.
char *ptr; // Test for valid field.
File file;
size_t readField(File* file, char* str, size_t size, char* delim) {
char ch;
size_t n = 0;
while ((n + 1) < size && file->read(&ch, 1) == 1) {
// Delete CR.
if (ch == '\r') {
continue; }
str[n++] = ch;
if (strchr(delim, ch)) {
break; } }
str[n] = '\0';
return n; }
#define errorHalt(msg) {Serial.println(F(msg)); while(1);}
/*time*/
#define SECS_PER_MIN (60UL)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
/*PID working variables*/
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, 2, 5, 1, DIRECT);
int WindowSize = 1000;
unsigned long windowStartTime;
/*Thermocouple MAX31855*/
#define maxSO 5
#define maxCS 6
#define maxSCK 7
Adafruit_MAX31855 kTC(maxSCK, maxCS, maxSO);
const int numReadings = 10; //average number of readings from thermocouple
double v = 0;
int readings[numReadings];
int readIndex = 0;
double total;
double vavg;
double Ctemp, Ftemp;
double offset = 0; //temp offset for calibration
/*rotary encoder*/
int sw1 = 2; //rotary encoder pushbutton
const int encoderPinB = 3; //rotary encoder B
const int encoderPinA = 4; //rotary encoder A
boolean encoderALast = LOW; //remembers the previous rotary encoder pin state
//edit setpoint time, sptime
//edit setpoint temperature, sptemp
/*opto-isolator*/
int relay1 = A4;
unsigned long relayStartTime = 0; //time the relay is switched on
/*calculations and status*/
String seconds; //used in setTimer function to display strings on LCD
int setTime = 0; //initial on time selected in milliseconds
void setup(void) {
Serial.begin(9600);
pinMode(relay1, OUTPUT); digitalWrite(relay1, LOW);
pinMode(encoderPinA, INPUT); digitalWrite(encoderPinA, HIGH);
pinMode(encoderPinB, INPUT); digitalWrite(encoderPinB, HIGH);
pinMode(sw1, INPUT); digitalWrite(sw1, HIGH);
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
//PID
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint = 30;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip
//splash screen
tft.fillScreen(ST7735_BLACK);
tft.setTextWrap(false);
tft.setCursor(20, 0);
tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
tft.setTextSize(1);
tft.println("FURNACE CONTROL");
tft.println("");
tft.println("V0.9");
tft.println("October 2017");
delay(3000);
// close the SD card
if (!SD.begin(chipSelect)) {
Serial.println("no sd");
errorHalt("begin failed");
}
// open the SD file.
file = SD.open("datalog.TXT", FILE_WRITE);
if (!file) {
errorHalt("open failed");
}
// Fill array
file.seek(0);
for (i = 0; i < ROW_DIM; i++) {
for (j = 0; j < COL_DIM; j++) {
n = readField(&file, str, sizeof(str), ",\n");
if (n == 0) {
errorHalt("Too few lines");
}
array[i][j] = strtol(str, &ptr, 10);
if (ptr == str) {
errorHalt("bad number");
}
while (*ptr == ' ') {
ptr++;
}
if (*ptr != ',' && *ptr != '\n' && *ptr != '\0') {
errorHalt("extra characters in field");
}
if (j < (COL_DIM - 1) && str[n - 1] != ',') {
errorHalt("line with too few fields");
}
}
// Allow missing endl at eof.
if (str[n - 1] != '\n' && file.available()) {
errorHalt("missing endl");
}
}
setMenu();
}
void loop() {
setMenu();
}
void setMenu() {
int encoderPos = 1;
int x = 0;
tft.fillScreen(ST7735_BLACK);
tft.setTextWrap(false);
tft.setCursor(20, 0);
tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
tft.setTextSize(1);
tft.println("START OR LEARN");
tft.println("");
tft.setCursor(25, 50);
tft.setTextColor(ST7735_YELLOW, ST7735_RED);
tft.setTextSize(2);
tft.print("START");
tft.setCursor(25, 70);
tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
tft.setTextSize(2);
tft.print("LEARN");
while (digitalRead(sw1) == HIGH) {
boolean encoderA = digitalRead(encoderPinA);
if ((encoderALast == HIGH) && (encoderA == LOW)) {
if (digitalRead(encoderPinB) == LOW) {
encoderPos--;
encoderPos = constrain(encoderPos, 1, 2); }
else {
encoderPos++;
encoderPos = constrain(encoderPos, 1, 2); }
switch (encoderPos) {
case 1:
Serial.println("START");
tft.setTextWrap(false);
tft.setTextSize(2);
tft.setCursor(25, 70);
tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
tft.print("LEARN");
tft.setCursor(25, 50);
tft.setTextColor(ST7735_YELLOW, ST7735_RED);
tft.print("START");
x = 1;
break;
case 2:
Serial.println("LEARN");
tft.setTextWrap(false);
tft.setTextSize(2);
tft.setCursor(25, 50);
tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
tft.print("START");
tft.setCursor(25, 70);
tft.setTextColor(ST7735_YELLOW, ST7735_RED);
tft.print("LEARN");
x = 2;
break; }
}
encoderALast = encoderA; }
if (x <= 1) {
Serial.println("ramp");
run_ramp();
return; }
else {
Serial.println("learn");
learn();
return; }
return; }