//#include <Adafruit_GFX.h>
//#include <Adafruit_SPITFT_Macros.h>
//#include <Adafruit_SPITFT.h>
//#include <gfxfont.h>
#include <Adafruit_MAX31856.h> //Type K thermocouple module
//#include <ILI9486_SPI.h> //RPI 3.5 inch tft
#include <SPI.h>
#include <RA8875.h>
#include <XPT2046_Touchscreen.h> //Touchscreen 12 bits
#include <PID_v1.h> //PID controller
#include "symbols.h" //Keyboard symbols
#include "Monospaced_plain_22.h" //Monospaced font
#include <EEPROM.h>
#define ms22_spacing 14
#define MAX_CS 36 // MAX31856 CS
#define MAX_DI 37 // MAX31856 DI
#define MAX_DO 38 // MAX31856 DO
#define MAX_CLK 39 // MAX31856 CLK
Adafruit_MAX31856 maxtemp = Adafruit_MAX31856(MAX_CS, MAX_DI, MAX_DO, MAX_CLK);
#define TFT_CS 20 // RPI display CS
#define TFT_DC 18 // RPI display DC
// SCK = PA5, MISO = PA6, MOSI = PA7, RST = +3V3
//ILI9486_SPI tft(/*CS=4*/ TFT_CS, /*DC=*/ TFT_DC, /*RST=*/ 0);
#define RA8875_RESET 255 //Not used
#define RA8875_CS 20
RA8875 tft = RA8875(RA8875_CS, RA8875_RESET, 11, 13, 12); // 11=MOSI 13=SCLK 12=MISO 10=CS
#define CS_PIN 2 // Touchscreen CS
// SCK = PA5, MISO = PA6, MOSI = PA7
XPT2046_Touchscreen ts(CS_PIN);
// These are the default min and maximum values, set between 0 and 4095 (12 bit)
#define HMIN 230
#define HMAX 3930
#define VMIN 230
#define VMAX 3830
#define WIDTH 800 // Default screen resulution for X axis
#define HEIGHT 480 // Default screen resulution for Y axis
#define BUTTONW 80 // Default button resulution for X axis
#define BUTTONH 80 // Default button resulution for X axis
#define HEATER_PIN 3 //Heater output pin
#define FAN_PIN 4 //Fan output pin
#define BUZZER_PIN 5 //Buzzer output pin (option)
#define LTBLUE 0xB6DF
#define LTTEAL 0xBF5F
#define LTGREEN 0xBFF7
#define LTCYAN 0xC7FF
#define LTRED 0xFD34
#define LTMAGENTA 0xFD5F
#define LTYELLOW 0xFFF8
#define LTORANGE 0xFE73
#define LTPINK 0xFDDF
#define LTPURPLE 0xCCFF
#define LTGREY 0xE71C
#define BLUE 0x001F
#define MDBLUE 0x0016
#define TEAL 0x0438
#define GREEN 0x07E0
#define MDGREEN 0x05E0
#define CYAN 0x07FF
#define RED 0xF800
#define MDRED 0xC800
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define ORANGE 0xFC00
#define PINK 0xF81F
#define PURPLE 0x8010
#define GREY 0xC618
#define MDGREY 0x94B2
#define WHITE 0xFFFF
#define BLACK 0x0000
#define DKBLUE 0x000D
#define DKTEAL 0x020C
#define DKGREEN 0x03E0
#define DKCYAN 0x03EF
#define DKRED 0x6000
#define DKMAGENTA 0x8008
#define DKYELLOW 0x8400
#define DKORANGE 0x8200
#define DKPINK 0x9009
#define DKPURPLE 0x4010
#define DKGREY 0x4A49
uint16_t backcolor = BLUE; // color of display background
uint16_t txtcolor = WHITE; // color of text on display
uint16_t bordercolor = BLACK; // color of borders and lines
uint16_t trendcolor = CYAN; // color of trenline
uint16_t rastcolor = MDGREY; // color of the raster lines
int screen = 0; // screen = 0 is main screen screen = 1 is setup screen
int butnr =999; // number of touched button
int recipenr = 1; // start with recipe number one
int oldrecipenr = 1; // start with recipe number one
char rcptxt[6][11]={" ", " SAC305", " LEAD_FREE", " LEADED", " CURVE1", " CURVE2"};
//String rcptxt[6]; // The name of the reflow curve
uint8_t rptxt[6][7]; // The reflow zone the oven can be in (Stopped, Preheat, Soak, etc)
String rptext = "Stopped"; // The actual reflow zone the oven is in
String oldrptext = "Stopped"; // The actual reflow zone the oven is in
uint8_t xv[480]; // temperature values
uint16_t T[6][7]; // recipes temperature --- 5 recipes ---- 6 points per recipe
uint16_t m[6][7]; // recipes time --- 5 recipes ---- 6 points per recipe
int mt; // calculated total time trend x-axes
int Tt; // highest temoperatuur y-axes
int startcurve = 0; // 0 if the curve is not running -- 1 if the curve is running.
int pointcounter = 0; // The current point in a recipe
int cur = 2; // The current parameter
int valinit = 0; // valinit = 0 --- reprint the complete editor window on the setup screen (screen 1) valinit = 1 --- print only the changes
int redrtop = 1; // TRUE if the drawstring text should be completely redrawn
String valuestrm[6]; // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrm[6]; // temporarily variable to hold the previous recipe values of the current recipe
String valuestrT[6]; // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrT[6]; // temporarily variable to hold the previous recipe values of the current recipe
String valuestrtxt[6]; // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrtxt[6]; // temporarily variable to hold the previous recipe values of the current recipe
int btnr = 999; // Holds the pressed butten number 999 no button is pressed
int blocked = 0; // 0 = one puls button 1 = repeat puls button
int starttimer = 0; // start the timer for the repeat puls button. If you hold the button longer, the repeatfrequence goes up.
double rate = 1; // temperature rise per second
int tchd = 0; // 1 if the touchscreen is touched
int elapsedtime = 0; // elapsed time between steps in the temperature curve
int stepcounter = 0; // next step in the recipecurve
int curtemp, curtemp2;
int rtxtcur = 0; // recipe text cursor
int scrltxt = 0;
String zonetxt[6] = {"Stopped", "Preheat", "Soak", "Prereflow", "Reflow", "Cool"};
int maxvaluem[6] = {350, 350, 350, 350, 350, 350}; // maximum adjustable time value
int maxvalueT[6] = {350, 350, 350, 350, 350, 350}; // maximum adjustable temperature value
int xcursor[18] = {0, 0, 241, 20, 123, 216, 20, 123, 216, 20, 123, 216, 20, 123, 216, 20, 123, 216, }; // place of the cursor in the editor window
int ycursor[18] = {0, 0, 20, 110, 110, 110, 135, 135, 135, 160, 160, 160, 185, 185, 185, 210, 210, 210}; // place of the cursor in the editor window
int alphabet[38] = {32, 45, 48, 49, 50, 51, 52, 53, 54, 55 ,56 ,57, 65, 66 ,67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 ,78, 79 ,80, 81, 82, 83, 84, 85 ,86 ,87 ,88 ,89 ,90};
int alphabetconv[59] = {0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
//trend variables
int ybegin = 35;
int yend = 215;
int xbegin = 30;
int xend = 450;
int tempdiv = 50;
int timediv = 60;
double temperature, oldtemperature; // heater temperature
double sp = 0; // PID running setpoint
double Setpoint; // PID end setpiont
double Input; // PID input(heater temperature)
double Output; // PID output(heater power)
struct but { // button parameters
uint8_t draw; // 1 draw the button 0 draw an empty space
uint16_t x; // button x coordinate
uint16_t y; // button y coordinate
const uint8_t *bm; // button image name
uint16_t w; // button width
uint16_t h; // button height
uint16_t color; // button symbol color
uint16_t swcolor; // button active symbol color
uint16_t bacolor; // button background color
uint16_t bocolor; // button border color
uint8_t latch; // 0 push button 1 color inverted pushbutton 2 switch
uint8_t in; // 0 button is released 1 button is in
uint8_t repeat; // 0 repeat puls button 1 single puls button
};
//int buttons=10; // number of buttons
but scr[11]={ // button array to draw the buttons
{1, 0, 240, homesymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,1},
{1, 80, 240, fansymbol, BUTTONW, BUTTONH, MDGREY, GREEN, backcolor, bordercolor, 2,0,1},
{1, 160, 240, backwardsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
{1, 240, 240, forwardsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
{1, 320, 240, heatersymbol, BUTTONW, BUTTONH, MDGREY, GREEN, backcolor, bordercolor, 2,0,1},
{1, 400, 240, onoffsymbol, BUTTONW, BUTTONH, txtcolor, GREEN, backcolor, bordercolor, 2,0,1},
{1, 400, 0, rightsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
{1, 400, 80, upsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
{1, 400, 160, downsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
{1, 0, 240, gearsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,1},
{1, 400, 240, rightrightsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
};
int scr0but[7] = {0, 1, 2, 3, 4, 5};
int scr1but[10] = {1, 2, 3, 4, 6, 7, 8, 9, 10};
// define text instead of numbers for the buttons
#define gear 0
#define fan 1
#define backward 2
#define forward 3
#define heater 4
#define onoff 5
#define right 6
#define up 7
#define down 8
#define home 9
#define tab 10
unsigned long windowStartTime;
int WindowSize = 2000; // output limit for the PID controller
unsigned long meastime = 0;
int measwindow = 1000; //time in ms temperature measurement
unsigned long touchtime = 0;
int touchwindow = 0; //time in ms button touch delay
unsigned long drawtime = 0;
int drawwindow = 1000;
//Specify the links and initial tuning parameters
//double Kp=2, Ki=5, Kd=1;
double Kp=100, Ki=5, Kd=1;
PID myPID(&Input, &Output, &sp, Kp, Ki, Kd, DIRECT);
void setup()
{
//disableDebugPorts(); //Release PB4 (FAN_PIN) so we can used it as an output
tft.begin(RA8875_800x480);
tft.setRotation(0);
pinMode(HEATER_PIN, OUTPUT);
pinMode(FAN_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
windowStartTime = millis();
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
Serial.begin(115200);
//ts.begin(); // initialize the touchscreen
//ts.setRotation(1); // touchscreen the same as the tft
uint16_t DataWrite = 11111;
uint16_t AddressWrite = 0x10;
uint16_t StatusInit;
uint16_t StatusRead;
uint16_t StatusWrite;
uint16_t Data;
//delay(3000);
//StatusInit = EEPROM.init();
//delay(3000);
//EEPROM.PageBase0 = 0x801F000;
//EEPROM.PageBase1 = 0x801F800;
//EEPROM.PageSize = 0x800;
//StatusRead = EEPROM.read(AddressWrite, &Data);
if (Data != 11111){
//StatusWrite = EEPROM.write(AddressWrite, DataWrite);
// pre set recipes
// SAC305
T[1][0] = 0; m[1][0] = 0; rptxt[1][0] = 0;
T[1][1] = 150; m[1][1] = 90; rptxt[1][1] = 1;
T[1][2] = 175; m[1][2] = 90; rptxt[1][2] = 2;
T[1][3] = 217; m[1][3] = 30; rptxt[1][3] = 3;
T[1][4] = 249; m[1][4] = 30; rptxt[1][4] = 4;
T[1][5] = 217; m[1][5] = 30; rptxt[1][5] = 4;
T[1][6] = 20; m[1][6] = 90; rptxt[1][6] = 5;
// Lead-Free
T[2][0] = 0; m[2][0] = 0; rptxt[2][0] = 0;
T[2][1] = 150; m[2][1] = 90; rptxt[2][1] = 1;
T[2][2] = 200; m[2][2] = 90; rptxt[2][2] = 2;
T[2][3] = 245; m[2][3] = 45; rptxt[2][3] = 4;
T[2][4] = 200; m[2][4] = 45; rptxt[2][4] = 4;
T[2][5] = 20; m[2][5] = 90; rptxt[2][5] = 5;
T[2][6] = 20; m[2][6] = 0; rptxt[2][5] = 5;
// Leaded
T[3][0] = 0; m[3][0] = 0; rptxt[3][0] = 0;
T[3][1] = 150; m[3][1] = 90; rptxt[3][1] = 1;
T[3][2] = 180; m[3][2] = 90; rptxt[3][2] = 2;
T[3][3] = 219; m[3][3] = 30; rptxt[3][3] = 4;
T[3][4] = 180; m[3][4] = 30; rptxt[3][4] = 4;
T[3][5] = 20; m[3][5] = 90; rptxt[3][5] = 5;
T[3][6] = 20; m[3][6] = 0; rptxt[3][5] = 5;
// reflow curve
T[4][0] = 0; m[4][0] = 0; rptxt[4][0] = 0;
T[4][1] = 150; m[4][1] = 90; rptxt[4][1] = 1;
T[4][2] = 180; m[4][2] = 90; rptxt[4][2] = 2;
T[4][3] = 219; m[4][3] = 30; rptxt[4][3] = 4;
T[4][4] = 180; m[4][4] = 30; rptxt[4][4] = 4;
T[4][5] = 20; m[4][5] = 90; rptxt[4][5] = 5;
T[4][6] = 20; m[4][6] = 0; rptxt[4][5] = 5;
// reflow curve
T[5][0] = 0; m[5][0] = 0; rptxt[5][0] = 0;
T[5][1] = 150; m[5][1] = 90; rptxt[5][1] = 1;
T[5][2] = 180; m[5][2] = 90; rptxt[5][2] = 2;
T[5][3] = 219; m[5][3] = 30; rptxt[5][3] = 4;
T[5][4] = 180; m[5][4] = 30; rptxt[5][4] = 4;
T[5][5] = 20; m[5][5] = 90; rptxt[5][5] = 5;
T[5][6] = 20; m[5][6] = 0; rptxt[5][5] = 5;
store();
} else {
T[1][0] = 0; m[1][0] = 0; rptxt[1][0] = 0;
// Lead-Free
T[2][0] = 0; m[2][0] = 0; rptxt[2][0] = 0;
// Leaded
T[3][0] = 0; m[3][0] = 0; rptxt[3][0] = 0;
// reflow curve
T[4][0] = 0; m[4][0] = 0; rptxt[4][0] = 0;
// reflow curve
T[5][0] = 0; m[5][0] = 0; rptxt[5][0] = 0;
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//StatusRead = EEPROM.read(AddressWrite, &Data);
T[ir][iz] = Data;
}
}
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//StatusRead = EEPROM.read(AddressWrite, &Data);
m[ir][iz] = Data;
}
}
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//StatusRead = EEPROM.read(AddressWrite, &Data);
rptxt[ir][iz] = Data;
}
}
for (int ir = 1; ir < 5; ir++){
for (int iz = 0; iz < 9; iz=iz+2){
AddressWrite = AddressWrite + 16;
//StatusRead = EEPROM.read(AddressWrite, &Data);
rcptxt[ir][iz+1] = Data/256;
rcptxt[ir][iz] = Data - rcptxt[ir][iz+1]*256;
}
}
}
//StatusRead = EEPROM.read(AddressWrite, &Data);
recalc();
tft.fillWindow(BLACK);
tft.setTextColor(txtcolor, backcolor);
tft.setFont(&Monospaced_plain_22);
maxtemp.begin(); // initialize the temperature measure unit
drawbuttons(0); // Place the buttons on the bottom of the screen (parameter = 0)
tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor); // Place a rectangle above the buttons on screen 0
drawaxes(); // Draw the vertical and horizontal axes and the raster on screen 0
drawtraceline(); // Draw the recipe 0 trace line on screen 0
reflowtext(1); // Draw the current reflow zone text on the left top of the screen
recipetext(1, 335); // draw the recipe name on the right top of the screen
}
void loop() {
// measure temperature and chang setpoint
unsigned long measnow = millis();
if (measnow - meastime > measwindow) {
meastime = measnow;
oldtemperature = temperature; // save the previous temperature
temperature = maxtemp.readThermocoupleTemperature(); // read the new temperature
Setpoint = T[recipenr][stepcounter + 1]; // read the first step end setpoint
drawString(redrtop, 110, 20, ms22_spacing, 8, String(oldtemperature) + "C", String(temperature) + "C", 1, txtcolor, backcolor, Monospaced_plain_22); // print the new temperature at the top of the screen
if (redrtop == 1){redrtop = 0;} // next time only redraw the changes
if (rate >= 0 && temperature > Setpoint){// if the temperature goes from a lower to a higher setpoint and the setpoint is reached
if (stepcounter < 5){
oldrptext = zonetxt[rptxt[recipenr][stepcounter]]; // save the old reflow zone text
stepcounter++; // go to the next step
elapsedtime = 0; // reset the elapsed step time
rptext = zonetxt[rptxt[recipenr][stepcounter]]; // get the new reflow zone text
reflowtext(1); // print the new reflow zone text at th left top of the screen
}
}
if (rate < 0 && temperature < Setpoint){// if the temperature goes from a higher to a lower setpoint and the setpoint is reached
if (stepcounter < 5){
oldrptext = zonetxt[rptxt[recipenr][stepcounter]]; // save the old reflow zone text
stepcounter++; // go to the next step
elapsedtime = 0; // reset the elapsed step time
rptext = zonetxt[rptxt[recipenr][stepcounter]]; // get the new reflow zone text
reflowtext(1); // print the new reflow zone text at th left top of the screen
}
}
if(startcurve == 1){
rate = (T[recipenr][stepcounter + 1] - temperature) / (m[recipenr][stepcounter + 1] - elapsedtime); // recalculate the rate (pos or neg rise in degrees per second)
if (elapsedtime < m[recipenr][stepcounter + 1] - 1){elapsedtime++;} // if the total time between steps is not reached, increase the elapsed time
if (rate >= 0 && sp < Setpoint) {sp = sp + rate; if (sp > Setpoint){sp = Setpoint;}} // increase the sp with the positive rate until the setpoint is reached
if (rate < 0 && sp > Setpoint) {sp = sp + rate; if (sp < Setpoint){sp = Setpoint;}} // increase the sp with the negative rate until the setpoint is reached
}
}
// draw reflowcurve
unsigned long drawnow = millis();
if (drawnow - drawtime > drawwindow) {
drawtime = drawnow;
drawreflowcurve(); // redraw the temperature curve
}
// button touch delay
unsigned long touchnow = millis();
if (touchnow - touchtime > touchwindow) {
touchtime = touchnow;
readbutton(); // check if, and which button is pressed
if(screen == 1) {editrecipe(recipenr);} //print the edit recipe window on screen 1
if (starttimer == 1){touchwindow = touchwindow - 40; if(touchwindow < 0){touchwindow = 0;}} // if a repeat puls button is still pressed, lower the repeat time
}
Input = temperature; // connect the current temperature to the PID controller
myPID.Compute(); // recompute the PID output
if (millis() - windowStartTime > WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if (Output < millis() - windowStartTime) {digitalWrite(HEATER_PIN, LOW);} else { digitalWrite(HEATER_PIN, HIGH);} // send the PID output(0 or 1) to the heater
}
void recalc(){ // function to recalculate the trend time and temperature scale
mt = m[recipenr][0]+m[recipenr][1]+m[recipenr][2]+m[recipenr][3]+m[recipenr][4]+m[recipenr][5]+m[recipenr][6];
Tt = 0; for (int i = 1; i <= 6; i++) {if (Tt < T[recipenr][i]){Tt = T[recipenr][i];}}
mt = (mt+timediv-1)/timediv; // calculate the next rounded time value on the scale
Tt = (Tt+tempdiv-1)/tempdiv; // calculate the next rounded temperature value on the scale
drawwindow = (mt*timediv*1000)/(xend-xbegin);// calculate the redraw time interval per pixel
}
void fan_onoff(int pos){ // switch the fan on or off
if (pos == 0){//fan off
switchbutton(fan, 0); // switch the fan button symbol off
digitalWrite(FAN_PIN, LOW); // switch the fan output off
}
if (pos == 1){//fan on
switchbutton(fan, 1); // switch the fan button symbol on
digitalWrite(FAN_PIN, HIGH); // switch the fan output on
}
}
void buzzer_onoff(int pos){ // switch the buzzer on or off
if (pos == 0){//buzzer off
digitalWrite(BUZZER_PIN, LOW); // switch the buzzer output off
}
if (pos == 1){//buzzer on
digitalWrite(BUZZER_PIN, HIGH); // switch the buzzer output on
}
}
void on_off(int pos){ // start or stop the reflow
if (pos == 0){//off
oldrptext = zonetxt[rptxt[recipenr][stepcounter+1]]; // save the old reflow zone text
rptext = zonetxt[rptxt[recipenr][stepcounter]]; // get the new reflow zone text
reflowtext(1); // print the reflow zone text at the left top of the screen
T[recipenr][0] = 0; // make the first temperature of the recipe 0
elapsedtime = 0; // reset the elapsed time between zone steps
stepcounter = 0; // reset the zone step counter
sp = 0; // set the sp (PID setpoint) to zero
if(screen == 0){switchbutton(onoff, 0);} // switch the onoff button symbol off
scr[onoff].in = 0; // Set the onoff button.in parameter to zero
startcurve = 0; // stop the reflow curve
fan_onoff(1); // Start the cooling fan
}
if (pos == 1){//on
resettemperaturecurve(); // reset the themperature curve array (make all the elements zero)
oldrptext = zonetxt[rptxt[recipenr][stepcounter]]; // save the old reflow zone text
rptext = zonetxt[rptxt[recipenr][stepcounter+1]]; // get the new reflow zone text
rate = (T[recipenr][1] - temperature) / m[recipenr][1]; // calculate the first rate (rise in celcius per second)
elapsedtime = 0; // reset the elapsed time between zone steps
stepcounter = 0; // reset the zone step counter
sp = temperature; // set the sp (PID setpoint) to the current temperature
T[recipenr][0] = sp; // make the first temperature of the recipe the current temperature
switchbutton(onoff, 1); // switch the onoff button symbol on
scr[onoff].in = 1; // Set the onoff button.in parameter to one
startcurve = 1; // start the reflow curve
fan_onoff(0); // Stop the cooling fan
/* screen = 0;
fillScreen(backcolor);
tft.setTextColor(txtcolor);
drawbuttons(1);
tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor);
recalc();
drawaxes(); drawtraceline();
reflowtext(1);
recipetext(1, 350);
redrtop = 1;*/
}
}
void drawreflowcurve(){ // draw the temperature trend
if (startcurve == 1){ // only draw if the reflow has started
float pixelsgrd = (float(yend-ybegin) / (Tt*tempdiv)) * temperature; // calculate te pixels corresponding with the temperature
if (pixelsgrd > (yend-ybegin)){pixelsgrd = yend-ybegin;} // prefent the temperature from going off scale
xv[pointcounter] = pixelsgrd; // place the pixel value in the temperature array
if (screen == 0){ // only print the trend if the screen is the main screen
for (int i = 0; i < (xend-xbegin); i++) { // redraw the whole trend every new point
if (pixelsgrd > 0){tft.drawPixel(i+xbegin, yend - xv[i], trendcolor);} // only print a value if the temperature is larger then zero
}
}
pointcounter++; if (pointcounter > xend-xbegin){pointcounter = 0;} // set the pointer for the next value
}
}
void drawaxes(){
tft.setFont();
int Ttpix = (yend - ybegin) / Tt;
int mtpix = (xend - xbegin) / mt;
tft.fillRect(0, ybegin-5, 480, yend-ybegin+28, backcolor);
tft.drawLine(xbegin-1, ybegin, xbegin-1, yend+1, txtcolor); // draw the vertical axes
for (int i = 0; i <= Tt; i++) {
if (i == Tt){tft.setCursor(xbegin-25, yend - i*Ttpix + Ttpix/2 - 4); tft.print("(C)");} // print the temperature symbol in the trend
drawString(1, xbegin-25, yend-i*Ttpix - 4, 6, 3, "", String(i*tempdiv), 1, txtcolor, backcolor, 1); // print the numbers next to the vertical axis
tft.drawLine(xbegin - 6, yend-i*Ttpix , xbegin-1, yend-i*Ttpix, txtcolor); // print the division lines
}
tft.drawLine(xbegin-1, yend+1, xend, yend+1, txtcolor); // draw the horizontal axes
for (int i = 0; i <= mt; i++) {
if (i == mt){tft.setCursor(xbegin + i*mtpix - mtpix/2 - 9, yend+10); tft.print("(sec)");} // print the time symbol in the trend
drawString(1, xbegin+i*mtpix - 9, yend+10, 6, 3, "", String(i*timediv), 1, txtcolor, backcolor, 1); // print the numbers below the horizontal axis
tft.drawLine(xbegin+i*mtpix, yend+6 , xbegin+i*mtpix, yend+1, txtcolor); // print the division lines
}
drawraster(); // draw the raster lines
tft.setFont(&Monospaced_plain_22);
}
void drawraster(){ // draw the trend background and the rasterlines
int Ttpix = (yend - ybegin) / Tt; // pixels between two horizontal rasterlines
int mtpix = (xend - xbegin) / mt; // pixels between two vertical rasterlines
tft.fillRect(xbegin, ybegin, xend-xbegin, yend-ybegin, BLACK); // make a black trend background
for (int i = 0; i <= Tt; i++) {
tft.drawLine(xbegin, yend-i*Ttpix , xend, yend-i*Ttpix, rastcolor); // draw the horizontal rasterlines
}
for (int i = 0; i <= mt; i++) {
tft.drawLine(xbegin+i*mtpix, ybegin , xbegin+i*mtpix, yend, rastcolor); // draw the vertical rasterlines
}
}
void drawtraceline(){ // draw the recipe traceline in the trend
int Ttot0 = 0; int Ttot1 = 0;
int yrange = Tt*tempdiv; float pixpergrd = float(yend-ybegin)/yrange;
int xrange = mt*timediv; float pixpersec = float(xend-xbegin)/xrange;
for (int i = 1; i <= 6; i++) {
Ttot0 = Ttot0 + m[recipenr][i-1]*pixpersec;
Ttot1 = Ttot1 + m[recipenr][i]*pixpersec;
tft.drawLine(xbegin + Ttot0, yend - T[recipenr][i-1]*pixpergrd, xbegin + Ttot1, yend - T[recipenr][i]*pixpergrd, GREY);
}
}
void reflowtext(int tinit){
drawString(tinit, 10, 20, ms22_spacing, 8, oldrptext, rptext, 0, txtcolor, backcolor, Monospaced_plain_22); // draw reflow zone text at the left top of the screen
}
void recipetext(int tinit, int pos){
drawString(tinit, pos, 20, ms22_spacing, 10, rcptxt[oldrecipenr], rcptxt[recipenr], 1, txtcolor, backcolor, Monospaced_plain_22); // draw the recipe text at the right top of the screen
}
void fillScreen(int scolor){// fill the screen above the buttons at the bottom of the screen
tft.fillRect(0, 0, WIDTH, HEIGHT-BUTTONH, scolor);
}
void drawString(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol, const GFXfont &font){// draw a string or only the changes in a string on the screen
//&font is the gfx font + fontsize 1
tft.setFont(&font); tft.setTextSize(1);
drawStringHelper(pinit, px, py, pspacing, plength, oldpvalue, pvalue, pjust, txtcol, bckcol);
}
void drawString(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol, int fontsize){// draw a string or only the changes in a string on the screen
//Is the standard font fontsize
tft.setFont(); tft.setTextSize(fontsize);
drawStringHelper(pinit, px, py, pspacing, plength, oldpvalue, pvalue, pjust, txtcol, bckcol);
}
void drawStringHelper(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol){// draw a string or only the changes in a string on the screen
// pinit = 0 prints only changed characters, pinit = 1 prints all the characters
// px and py are the coordinates on the screen
// pspacing is the character spacing
// plength is de total length to print
// oldpvalue, pvalue is the string to print
// pjust = 0 is left justify, pjust = 1 is right justify
// txtcol is the text color
// bckcol is the text background color
String spaces = " "; // used for adding spaces in right and left justify
if (pjust == 0){// left justify
pvalue = pvalue + String(spaces.substring(0, plength - pvalue.length())); // add spaces to the right of the text until the string length = plength
oldpvalue = oldpvalue + String(spaces.substring(0, plength - oldpvalue.length())); // add spaces to the right of the text until the string length = plength
}
if (pjust == 1){// right justify
pvalue = String(spaces.substring(0, plength - pvalue.length())) + pvalue; // add spaces to the left of the text until the string length = plength
oldpvalue = String(spaces.substring(0, plength - oldpvalue.length())) + oldpvalue; // add spaces to the left of the text until the string length = plength
}
for (int i = 0; i < plength; i++) {
if (pvalue.substring(i, i+1) != oldpvalue.substring(i, i+1) or pinit == 1){// Only print, if de characters in de string are different than in the old string or if pinit =1
tft.setTextColor(bckcol); // set the font color the same as the background to erase the old character
tft.setCursor(px+i*pspacing, py);
tft.print(oldpvalue.substring(i, i+1)); // erase the old character
tft.setTextColor(txtcol); // set the font color the same as the foreground to print the new character
tft.setCursor(px+i*pspacing, py);
tft.print(pvalue.substring(i, i+1)); // print the new character
}
}
}
void editrecipe(int rnr){
// valinit = 0 --- reprint the complete editor window on the setup screen (screen 1)
// valinit = 1 --- print only the changes since the last time it was printed
tft.setFont(&Monospaced_plain_22);
tft.setTextColor(txtcolor);
if (valinit == 0){ //Print the fixed texts at the top of the values
tft.setCursor(10, 60); tft.print("Time(s)");
tft.setCursor(123, 60); tft.print("Temp(C)");
tft.setCursor(241, 60); tft.print("Zone");
}
for (int i = 1; i < 6; i++) {
curtemp = cur/3; curtemp2 = cur-curtemp*3;
if (curtemp2 == 0 || valinit == 0 || valinit == 2) {
if (valinit == 1 || valinit == 2){valueoldstrm[i] = valuestrm[i];} // save the time value from the parameter at the current position
if (valinit == 0){valueoldstrm[i] = "";} // clear the old time value to make it different from the new time value
valuestrm[i] = String(m[recipenr][i]); // get the new time value from the recipe parameter
drawString(0, 35, 85+i*25, ms22_spacing, 3, valueoldstrm[i], valuestrm[i], 1, txtcolor, backcolor, Monospaced_plain_22); // draw the new time value on the screen
}
if (curtemp2 == 1 || valinit == 0 || valinit == 2) {
if (valinit == 1 || valinit == 2){valueoldstrT[i] = valuestrT[i];} // save the temperature value from the parameter at the current position
if (valinit == 0){valueoldstrT[i] = "";} // clear the old temperature value to make it different from the new temperature value
valuestrT[i] = String(T[recipenr][i]); // get the new temperature value from the recipe parameter
drawString(0, 148, 85+i*25, ms22_spacing, 3, valueoldstrT[i], valuestrT[i], 1, txtcolor, backcolor, Monospaced_plain_22); // draw the new temperature value on the screen
}
if (curtemp2 == 2 || valinit == 0 || valinit == 2) {
if (valinit == 1 || valinit == 2){valueoldstrtxt[i] = valuestrtxt[i];} // save the temperature value from the parameter at the current position
if (valinit == 0){valueoldstrtxt[i] = "";} // clear the old temperature value to make it different from the new temperature value
valuestrtxt[i] = zonetxt[rptxt[recipenr][i]]; // get the new temperature value from the recipe parameter
drawString(0, 241, 85+i*25, ms22_spacing, 10, valueoldstrtxt[i], valuestrtxt[i], 0, txtcolor, backcolor, Monospaced_plain_22); // draw the new temperature value on the screen
}
}
valinit = 1;
}
// find the button number that is touched and change the looks of the touched button on the screen
int touchtft(){
tchd = ts.touched(); // 0 = not touched, 1 = touched
if (tchd && btnr == 999){blocked = 0;} // btnr == 999 is no button pressed, blocked = 0 is one puls button
TS_Point p = ts.getPoint(); // get values from the touchscreen
uint16_t xxn, yyn;
btnr = 999; // reset the button nr.
if (tchd) { // if touched
uint16_t X_Raw = p.x; // get the raw x coordinate from the touchscreen (0-4095)
uint16_t Y_Raw = p.y; // get the raw y coordinate from the touchscreen (0-4095)
xxn = map(X_Raw, HMAX, HMIN, 0, WIDTH); // convert the raw x coordinate to the screen width (0-480)
yyn = map(Y_Raw, VMIN, VMAX, 0, HEIGHT); // convert the raw y coordinate to the screen height (0-320)
if (screen == 0){ // the main screen
for (int i = 0; i <= 6; i++) {
int ii = scr0but[i];
if (xxn >= scr[ii].x & xxn <= scr[ii].x+scr[ii].w & yyn >= scr[ii].y & yyn <= scr[ii].y+scr[ii].h){ // compare the touchscreen coordinates with the button coordinates
btnr = ii; // if the coordinates match, save the button number
}
}
}
if (screen == 1){// the setup screen
for (int i = 1; i <= 9; i++) {
int ii = scr1but[i];
if (xxn >= scr[ii].x & xxn <= scr[ii].x+scr[ii].w & yyn >= scr[ii].y & yyn <= scr[ii].y+scr[ii].h){ // compare the touchscreen coordinates with the button coordinates
btnr = ii; // if the coordinates match, save the button number
}
}
}
}
return btnr;
}
void resettemperaturecurve(){// make every element of the temperature array zero
for (int i = 0; i < 480; i++) {
xv[i]=0;
}
pointcounter = 1; // reset the pointcounter
sp = 0; // reset the PID setpoint to zero
}
void readbutton(){
butnr = touchtft(); // get the button number from the touchscreen
if (blocked == 0 && btnr != 999 ){
switchbutton(btnr, 2);
if (scr[butnr].repeat == 1){blocked = 1;}
if (blocked == 0){if (starttimer == 0){touchwindow = 500;} starttimer = 1;}
tft.setFont(&Monospaced_plain_22);
if (butnr == gear){ // setup
valinit = 0;
screen = 1;
fillScreen(backcolor);
tft.setTextColor(txtcolor);
drawbuttons(1);
tft.drawRect(0, 0, WIDTH-BUTTONW, HEIGHT-BUTTONH, bordercolor);
tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
reflowtext(1);
// if (screen == 0){recipetext(1, 350);}
// if (screen == 1){recipetext(1, 270);}
recipetext(1, 255);
redrtop = 1;
butnr = 999;
rtxtcur = 0;
scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
}
if (butnr == backward){ // backward
store();
if (recipenr > 1){
oldrecipenr = recipenr;
recipenr--;
valinit = 2;
recalc();
resettemperaturecurve();
on_off(0);
if (screen == 0){drawaxes(); drawtraceline();}
if (screen == 0){recipetext(1, 335);}
if (screen == 1){recipetext(1, 255);}
}
}
if (butnr == forward){ // forward
store();
if (recipenr < 5){
oldrecipenr = recipenr;
recipenr++;
valinit = 2;
recalc();
resettemperaturecurve();
on_off(0);
if (screen == 0){drawaxes(); drawtraceline();}
if (screen == 0){recipetext(1, 335);}
if (screen == 1){recipetext(1, 255);}
}
}
if(butnr == fan){ // down
fan_onoff(scr[butnr].in);
}
if (butnr == onoff){ // onoff
startcurve = scr[butnr].in;
on_off(startcurve);
}
if(butnr == home){ // home
store();
screen = 0;
fillScreen(backcolor);
tft.setTextColor(txtcolor);
tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor);
recalc();
drawbuttons(0);
drawaxes(); drawtraceline();
reflowtext(1);
// if (screen == 0){recipetext(1, 350);}
// if (screen == 1){recipetext(1, 270);}
recipetext(1, 335);
redrtop = 1;
}
if(butnr == tab){ // tab
tft.setTextColor(backcolor, backcolor); tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
cur=cur+1; if (cur > 17){cur = 2;}
tft.setTextColor(txtcolor, backcolor); tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
if (cur == 2){
rtxtcur = 0;
scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
}
if (cur == 3){
drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, " -", "", 1, txtcolor, backcolor, Monospaced_plain_22);
}
}
if(butnr == right){ // right
rtxtcur++; if (rtxtcur > 9){rtxtcur = 0; drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 11, "-", " ", 1, txtcolor, backcolor, Monospaced_plain_22);}
scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
}
if(butnr == up){ // up
if (scr[onoff].in == 1){scr[onoff].in = 0; startcurve = scr[onoff].in; on_off(startcurve);}
if (ycursor[cur]>25){
curtemp = cur/3; curtemp2 = cur-curtemp*3;
if(curtemp2 == 0){ // time
if(m[recipenr][curtemp] < maxvaluem[curtemp]){
m[recipenr][curtemp]++;
}
}
if(curtemp2 == 1){ // temperature
if(T[recipenr][curtemp] < maxvalueT[curtemp]){
T[recipenr][curtemp]++;
}
}
if(curtemp2 == 2){ // temperature
if(rptxt[recipenr][curtemp] < 5){
rptxt[recipenr][curtemp]++;
}
}
}else{
String rcptxtemp = String(rcptxt[recipenr]);
scrltxt++; if(scrltxt>37){scrltxt=0;}
rcptxt[recipenr][rtxtcur] = alphabet[scrltxt];
drawString(0, 255, 20, ms22_spacing, 10, rcptxtemp, String(rcptxt[recipenr]), 1, txtcolor, backcolor, Monospaced_plain_22);
}
}
if(butnr == down){ // down
if (scr[onoff].in == 1){scr[onoff].in = 0; startcurve = scr[onoff].in; on_off(startcurve);}
if (ycursor[cur]>25){
curtemp = cur/3; curtemp2 = cur-curtemp*3;
if(curtemp2 == 0){ // time
if(m[recipenr][curtemp] > 0){
m[recipenr][curtemp]--;
}
}
if(curtemp2 == 1){ // temperature
if(T[recipenr][curtemp] > 0){
T[recipenr][curtemp]--;
}
}
if(curtemp2 == 2){ // temperature
if(rptxt[recipenr][curtemp] >0){
rptxt[recipenr][curtemp]--;
}
}
}else{
String rcptxtemp = String(rcptxt[recipenr]);
scrltxt--; if(scrltxt<0){scrltxt=37;}
rcptxt[recipenr][rtxtcur] = alphabet[scrltxt];
drawString(0, 255, 20, ms22_spacing, 10, rcptxtemp, String(rcptxt[recipenr]), 1, txtcolor, backcolor, Monospaced_plain_22);
}
}
}else{starttimer = 0; touchwindow = 0;}
}
void switchbutton(int btnr, int mod){
if (btnr<999 & scr[btnr].latch==0){button(scr[btnr]); button(scr[btnr]);}// switch button form positive to negative and back to positive (pushbutton)
if (btnr<999 & scr[btnr].latch>0){
if (mod == 0) {scr[btnr].in = 0; button(scr[btnr]);} // button = off
if (mod == 1) {scr[btnr].in = 1; button(scr[btnr]);} // button = on
if (mod == 2) {
scr[btnr].in = 1 - scr[btnr].in; button(scr[btnr]); // toggle button
}
}
}
void drawbuttons(int part){
if (part == 0 & screen == 0){button(scr[9]); for (int i = 1; i <= 5; i++) {button(scr[i]);}} // draw only the bottom row buttons
if (part == 0 & screen == 1){for (int i = 0; i <= 5; i++) {button(scr[i]);};} // draw only the left bottom row button (Home)
if (part == 1 & screen == 1){for (int i = 6; i <= 8; i++) {button(scr[i]);} button(scr[10]);} // draw the three right side butons
}
// draw a button on the screen
void button(but bx){
if (bx.draw == 1){// draw a button
uint8_t byte0 = pgm_read_byte(&bx.bm[0]); // get the button symbol width
uint8_t byte1 = pgm_read_byte(&bx.bm[1]); // get the button symbol height
if (bx.in == 0){ //pushbutton
tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor); // draw the button background (background color)
tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor); // draw the button border
//tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.color); // draw the button symbol (symbol color)
} else {
if (bx.latch == 1){ //pushbutton colors inverted
tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.color); // draw the button background (symbol color)
tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor); // draw the button border
//tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.bacolor); // draw the button symbol (background color)
}
if (bx.latch == 2){ //switch
tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor); // draw the button background (background color)
tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor); // draw the button border
//tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.swcolor); // draw the button symbol (switch color)
}
}
}
}
void store(){
//drawBitmap DataWrite;
uint16_t AddressWrite = 0x10;
uint16_t StatusWrite;
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//DataWrite = T[ir][iz];
//StatusWrite = EEPROM.write(AddressWrite, DataWrite);
}
}
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//DataWrite = m[ir][iz];
//StatusWrite = EEPROM.write(AddressWrite, DataWrite);
}
}
for (int ir = 1; ir <= 5; ir++){
for (int iz = 1; iz <= 6; iz++){
AddressWrite = AddressWrite + 16;
//DataWrite = rptxt[ir][iz];
//StatusWrite = EEPROM.write(AddressWrite, DataWrite);
}
}
for (int ir = 1; ir < 5; ir++){
for (int iz = 0; iz < 9; iz=iz+2){
AddressWrite = AddressWrite + 16;
//DataWrite = rcptxt[ir][iz]+rcptxt[ir][iz+1]*256;
// StatusWrite = EEPROM.write(AddressWrite, DataWrite);
}
}
}