diff --git a/reflow_plate_fw/platformio.ini b/reflow_plate_fw/platformio.ini index cd42862..0c7f493 100644 --- a/reflow_plate_fw/platformio.ini +++ b/reflow_plate_fw/platformio.ini @@ -16,10 +16,10 @@ upload_protocol = stlink debug_tool = stlink monitor_speed = 115200 lib_deps = - yuriisalimov/MAX6675_Thermocouple@^2.0.2 bodmer/TFT_eSPI@^2.3.70 br3ttb/PID@^1.2.1 ;siruli/MAX6675@^2.1.0 + zhenek-kreker/MAX6675 with hardware SPI@^1.0.0 lib_ldf_mode = deep+ build_flags = -D USER_SETUP_LOADED=1 diff --git a/reflow_plate_fw/src/board.h b/reflow_plate_fw/src/board.h index d3085e4..72dfa56 100644 --- a/reflow_plate_fw/src/board.h +++ b/reflow_plate_fw/src/board.h @@ -7,9 +7,11 @@ // #define LCD_DC PB1 // #define LCD_CS PB0 -#define THERM_CS PB5 -#define THERM_SO PB4 -#define THERM_CL PB6 +#define THERM_SS PB12 +#define THERM_MISO PB13 +#define THERM_CLK PB14 +#define THERM_MOSI PB15 //not used + #define HEAT_OUT PA2 diff --git a/reflow_plate_fw/src/controlloop.cpp b/reflow_plate_fw/src/controlloop.cpp index e8f6772..167e507 100644 --- a/reflow_plate_fw/src/controlloop.cpp +++ b/reflow_plate_fw/src/controlloop.cpp @@ -4,13 +4,9 @@ #include "button.h" #include "lcd.h" - - // Button AXIS_Y = Button(BUTTON_AXIS_Y, true, DEBOUNCE_MS); // Button AXIS_X = Button(BUTTON_AXIS_X, true, DEBOUNCE_MS); - - /******************************************************************************* Title: Reflow Oven Controller Version: 1.20 @@ -157,20 +153,22 @@ int oldTemp = 0; byte state; bool disableMenu; bool profileIsOn; +uint32_t processStartTime = 0; // Specify PID control interface & it must be here, after all declaration PID reflowOvenPID(&input, &output, &setpoint, kp, ki, kd, DIRECT); void initControlLoop(void) { - // Set window size + // Set window size windowSize = 2000; // Initialize time keeping variable nextCheck = millis(); // Initialize thermocouple reading variable nextRead = millis(); -} + pinMode(HEAT_OUT, OUTPUT); +} String getReflowStatus_str(void) { @@ -258,6 +256,59 @@ bool getOutputState(void) return outputState; } +uint32_t safetyTimer = 0; +#define SAFETYTIMEOUT 5000 //ms +double oldinput = 0; +#define SAFETYMARGIN 5 //degrees C +bool SafetyError = false; + +bool getSafetyCheck(void) +{ + uint32_t timeNow = millis(); + if (!outputState) + { + safetyTimer = timeNow; + oldinput = input; + return true; + } + else + { + if (timeNow - safetyTimer > SAFETYTIMEOUT) + { + if (input - oldinput < SAFETYMARGIN) + { + setReflowStatus(false); + return false; + } + else + { + return true; + oldinput = input; + } + } + } + return true; +} + +float getProcessTime(void) +{ + if ((reflowStatus == REFLOW_STATUS_ON) && (processStartTime > 0)) + { + float retval = (millis() - processStartTime); + retval /= 1000; + return retval; + } + else + { + return 0; + } +} + +bool getOverheating(void) +{ + return (reflowState == REFLOW_STATE_TOO_HOT); +} + void handleReflowStatemachine(void) { // Reflow oven controller state machine @@ -265,6 +316,7 @@ void handleReflowStatemachine(void) { case REFLOW_STATE_IDLE: activeStatus = "Idle"; + processStartTime = 0; // If oven temperature is still above room temperature if (input >= TEMPERATURE_ROOM) { @@ -284,7 +336,7 @@ void handleReflowStatemachine(void) // Initialize PID control window starting time windowStartTime = millis(); // Ramp up to minimum soaking temperature - setpoint = TEMPERATURE_SOAK_MIN; + setpoint = TEMPERATURE_SOAK_MIN + 5; // Tell the PID to range between 0 and the full window size reflowOvenPID.SetOutputLimits(0, windowSize); reflowOvenPID.SetSampleTime(PID_SAMPLE_TIME); @@ -292,6 +344,8 @@ void handleReflowStatemachine(void) reflowOvenPID.SetMode(AUTOMATIC); // Proceed to preheat stage reflowState = REFLOW_STATE_PREHEAT; + // log process start time + processStartTime = millis(); } } break; @@ -440,7 +494,7 @@ void handleReflowPID(void) void handleTemperatureReadings(void) { - unsigned long now; + unsigned long now; // Time to read thermocouple? if (millis() > nextRead) @@ -520,7 +574,6 @@ void handleTemperatureReadings(void) } } - /* ---- REFLOW MAIN LOOP ---- */ void handleControlLoop() { @@ -529,7 +582,7 @@ void handleControlLoop() Serial.println("handlecontrolloop: ERROR state"); return; } - + getSafetyCheck(); handleTemperatureReadings(); handleReflowStatemachine(); handleReflowPID(); diff --git a/reflow_plate_fw/src/controlloop.h b/reflow_plate_fw/src/controlloop.h index 6d56b11..63989c5 100644 --- a/reflow_plate_fw/src/controlloop.h +++ b/reflow_plate_fw/src/controlloop.h @@ -77,3 +77,5 @@ reflowStatus_t getReflowStatus(void); void setReflowStatus(bool newStatus); double getReflowTargetTemp(void); bool getOutputState(void); +float getProcessTime(void); +bool getOverheating(void); \ No newline at end of file diff --git a/reflow_plate_fw/src/heater.cpp b/reflow_plate_fw/src/heater.cpp deleted file mode 100644 index 65fabda..0000000 --- a/reflow_plate_fw/src/heater.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "heater.h" - -uint16_t heatingProfile[] = -{ - 30, - 50, - 70, - 90 -}; - -void initHeater(void) -{ - pinMode(HEAT_OUT,OUTPUT); - digitalWrite(HEAT_OUT, LOW); -} - -void handleHeater(void) -{ - -} \ No newline at end of file diff --git a/reflow_plate_fw/src/heater.h b/reflow_plate_fw/src/heater.h deleted file mode 100644 index ac51586..0000000 --- a/reflow_plate_fw/src/heater.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "Arduino.h" -#include "board.h" - -void initHeater(void); -void handleHeater(void); \ No newline at end of file diff --git a/reflow_plate_fw/src/lcd.cpp b/reflow_plate_fw/src/lcd.cpp index 2674dcb..73e5579 100644 --- a/reflow_plate_fw/src/lcd.cpp +++ b/reflow_plate_fw/src/lcd.cpp @@ -3,6 +3,7 @@ #include "thermo.h" #include "controlloop.h" #include "button.h" +#include #include // Include the graphics library @@ -27,11 +28,11 @@ uint32_t lastButtonTime = 0; void updateTemperature(void) { //draw actualTemperature - chartArea_spr.fillRoundRect(TEMP_X, 0, 60-TEMP_R, TEMP_H, TEMP_R, TEMP_BG_COLOR); + chartArea_spr.fillRoundRect(TEMP_X, 0, 60 - TEMP_R, TEMP_H, TEMP_R, TEMP_BG_COLOR); chartArea_spr.drawString("A:", TEMP_X + TEMP_LABEL_X, TEMP_H / 4); chartArea_spr.drawString("T:", TEMP_X + TEMP_LABEL_X, TEMP_H / 4 * 3); - chartArea_spr.drawNumber(getTemperature(), TEMP_X + TEMP_VALUE_X, TEMP_H / 4); + chartArea_spr.drawFloat(getTemperature(), 1, TEMP_X + TEMP_VALUE_X, TEMP_H / 4); if (getReflowStatus() == REFLOW_STATUS_OFF) { chartArea_spr.drawString("--", TEMP_X + TEMP_VALUE_X, TEMP_H / 4 * 3); @@ -45,7 +46,12 @@ void updateTemperature(void) uint32_t calcTemp(double temp) { //map(long x, long in_min, long in_max, long out_min, long out_max) - return CHART_H - map(temp, CHART_TEMP_MIN, CHART_TEMP_MAX, CHART_Y_AXIS_OFFSET, CHART_H) + CHART_X_AXIS_OFFSET; + return CHART_H - map(temp, CHART_TEMP_MIN, CHART_TEMP_MAX, CHART_X_AXIS_OFFSET, CHART_H) + CHART_X_AXIS_OFFSET; +} + +uint32_t calcTempY(uint32_t inputY) +{ + return map(inputY, CHART_H, CHART_X_AXIS_OFFSET, CHART_TEMP_MIN, CHART_TEMP_MAX); } uint32_t calcTime(uint32_t timeMs) @@ -53,6 +59,40 @@ uint32_t calcTime(uint32_t timeMs) return map((timeMs / 1000), 0, CHART_TIME_MAX, 0, CHART_W - CHART_Y_AXIS_OFFSET); } +std::vector temperatureReading; +uint32_t lastReading = 0; +#define TEMPINTERVAL 1000 + +void updateRealtimeGraph(void) +{ + if(getReflowStatus() == REFLOW_STATUS_OFF) + { + temperatureReading.clear(); + return; + } + //record temperature + uint32_t timeNow = millis(); + if (timeNow - lastReading > TEMPINTERVAL) + { + temperatureReading.push_back(getTemperature()); + lastReading = timeNow; + } + + //draw graph + uint32_t timeIndex = 0; + uint32_t lastX = 0; + uint32_t lastY = 0; + for (auto &&sample : temperatureReading) + { + uint32_t nowX = calcTime(timeIndex * TEMPINTERVAL); + uint32_t nowY = calcTemp(sample); + chartArea_spr.drawLine(lastX,lastY, nowX, nowY, CHART_ACTUAL_COLOR); + lastX = nowX; + lastY = nowY; + timeIndex ++; + } +} + void updateTargetChart(void) { @@ -93,6 +133,8 @@ void updateTargetChart(void) calcTemp(TEMPERATURE_ROOM), CHART_TARGET_COLOR); + updateRealtimeGraph(); + updateTemperature(); chartArea_spr.pushSprite(CHART_X + CHART_Y_AXIS_OFFSET, CHART_Y); } @@ -108,7 +150,12 @@ void prepTargetChart(void) void updateReflowState(void) { - reflowstate_spr.fillRoundRect(STATE_OFFSET, 0, (STATE_W / 2) - (2 * STATE_OFFSET), STATE_H, STATE_R, STATE_BG_COLOR); + uint32_t statusColor = STATE_BG_COLOR; + if(getOverheating()) + { + statusColor = TFT_RED; + } + reflowstate_spr.fillRoundRect(STATE_OFFSET, 0, (STATE_W / 2) - (2 * STATE_OFFSET), STATE_H, STATE_R, statusColor); reflowstate_spr.fillRoundRect(STATE_W / 2 + STATE_OFFSET, 0, (STATE_W / 2) - (2 * STATE_OFFSET), STATE_H, STATE_R, STATE_BG_COLOR); reflowstate_spr.drawString(getReflowState_str(), STATE_W / 4, STATE_H / 2); reflowstate_spr.drawString(getReflowStatus_str(), STATE_W / 4 * 3, STATE_H / 2); @@ -161,7 +208,7 @@ void prepChart(void) for (int i = 0; i < CHART_Y_TICKS; i++) { //tick value - uint16_t y_tick_step = CHART_TEMP_MAX - ((CHART_TEMP_MAX - CHART_TEMP_MIN) / CHART_Y_TICKS * i + 1) + CHART_TEMP_MIN; + uint16_t y_tick_step = calcTempY( tickIndex * (i +1));//CHART_TEMP_MAX - ((CHART_TEMP_MAX - CHART_TEMP_MIN) / CHART_Y_TICKS * i + 1) + CHART_TEMP_MIN; chartYaxis_spr.drawLine(CHART_Y_AXIS_OFFSET - 8, tickIndex * (i + 1), CHART_Y_AXIS_OFFSET, tickIndex * (i + 1), CHART_LINE_COLOR); chartYaxis_spr.setTextDatum(BR_DATUM); chartYaxis_spr.drawString(String(y_tick_step), CHART_Y_AXIS_OFFSET - 3, tickIndex * (i + 1), CHART_FONT); @@ -182,14 +229,17 @@ void prepChart(void) void prepStatus(void) { - looptime_spr.createSprite(20, tft.fontHeight(1) + 1); + looptime_spr.createSprite(80, tft.fontHeight(1) + 1); } void updateStatus(void) { looptime_spr.fillSprite(TFT_BLACK); - looptime_spr.setTextDatum(MC_DATUM); - looptime_spr.drawNumber(getLooptime(), looptime_spr.width() / 2, looptime_spr.height() / 2, 1); + looptime_spr.setTextDatum(TL_DATUM); + looptime_spr.setTextColor(TFT_WHITE); + looptime_spr.drawNumber(getLooptime(), 1, 1, 1); + looptime_spr.drawFloat(getProcessTime(), 2, 20, 1, 1); + looptime_spr.pushSprite(1, 1); } diff --git a/reflow_plate_fw/src/lcd.h b/reflow_plate_fw/src/lcd.h index ae55cf1..9dda2e3 100644 --- a/reflow_plate_fw/src/lcd.h +++ b/reflow_plate_fw/src/lcd.h @@ -30,11 +30,11 @@ #define CHART_TIME_MAX 140 //time scale in seconds #define CHART_TEMP_MIN 20 //offset in degrees #define CHART_TEMP_MAX 240 //degrees -#define CHART_Y_TICKS 11 +#define CHART_Y_TICKS 10 #define CHART_X_TICKS 7 #define CHART_LINE_COLOR TFT_WHITE #define CHART_TEXT_COLOR TFT_RED -#define CHART_TARGET_COLOR TFT_WHITE +#define CHART_TARGET_COLOR TFT_LIGHTGREY #define CHART_ACTUAL_COLOR TFT_RED #define CHART_BG_COLOR TFT_BLACK @@ -58,7 +58,7 @@ #define TEMP_BG_COLOR TFT_BLUE #define TEMP_R TFT_DEFAULT_R #define TEMP_LABEL_X 2 -#define TEMP_VALUE_X 30 +#define TEMP_VALUE_X 20 #define OUTPUT_W 12 #define OUTPUT_H 12 diff --git a/reflow_plate_fw/src/main.cpp b/reflow_plate_fw/src/main.cpp index d18f8a4..ae9a742 100644 --- a/reflow_plate_fw/src/main.cpp +++ b/reflow_plate_fw/src/main.cpp @@ -4,7 +4,6 @@ #include "lcd.h" #include "thermo.h" #include "button.h" -#include "heater.h" #include "status.h" #include "controlloop.h" @@ -14,7 +13,6 @@ void setup() initLCD(); initThermo(); initButton(); - initHeater(); initControlLoop(); } @@ -25,7 +23,6 @@ void loop() handleLCD(); handleThermo(); handleButton(); - handleHeater(); handleStatus(); handleControlLoop(); } \ No newline at end of file diff --git a/reflow_plate_fw/src/status.cpp b/reflow_plate_fw/src/status.cpp index 51a487e..9b53b38 100644 --- a/reflow_plate_fw/src/status.cpp +++ b/reflow_plate_fw/src/status.cpp @@ -1,5 +1,6 @@ #include "status.h" +#include "controlloop.h" uint64_t timelast = 0; uint64_t blinkrate = 500; @@ -32,4 +33,9 @@ void handleStatus(void) uint32_t getLooptime(void) { return looptime; +} + +double getReflowTime(void) +{ + return getProcessTime(); } \ No newline at end of file diff --git a/reflow_plate_fw/src/thermo.cpp b/reflow_plate_fw/src/thermo.cpp index 0028bc4..bb6eb03 100644 --- a/reflow_plate_fw/src/thermo.cpp +++ b/reflow_plate_fw/src/thermo.cpp @@ -1,31 +1,57 @@ #include "thermo.h" +#include "controlloop.h" -Thermocouple *thermocouple = NULL; +MAX6675 thermocouple(THERM_SS, THERM_MISO, THERM_CLK); uint32_t thermo_lastTime = 0; double lastTemperature = 0; +bool simulation = true; +#define SIM_TEMP_STEP 1 +#define SIM_TEMP_COOL 0.08 +#define SIM_INTERVAL 100 +uint32_t simTimer = 0; + void initThermo() { - Thermocouple *originThermocouple = new MAX6675_Thermocouple(THERM_CL, THERM_CS, THERM_SO); - thermocouple = new SmoothThermocouple(originThermocouple, SMOOTHING_FACTOR); + if(simulation) + { + lastTemperature = TEMPERATURE_ROOM-20; + } } void handleThermo(void) { - // Reads temperature - uint32_t timeNow = millis(); - if (timeNow - thermo_lastTime > THERMO_INTERVAL) + if(simulation) { - lastTemperature = thermocouple->readCelsius(); - thermo_lastTime = timeNow; + uint32_t timeNow = millis(); + if(timeNow - simTimer > SIM_INTERVAL) + { + if(getOutputState()) + { + lastTemperature += SIM_TEMP_STEP; + } + else + { + if(lastTemperature > TEMPERATURE_ROOM-20) + { + lastTemperature -= SIM_TEMP_COOL; + } + } + simTimer = timeNow; + } + } + else + { + lastTemperature = thermocouple.readTempC(); + } } double getTemperature(void) { - return 23;//lastTemperature; + return lastTemperature; //lastTemperature; } bool getThermoCoupleFault(void) diff --git a/reflow_plate_fw/src/thermo.h b/reflow_plate_fw/src/thermo.h index 588c874..e4197c2 100644 --- a/reflow_plate_fw/src/thermo.h +++ b/reflow_plate_fw/src/thermo.h @@ -2,9 +2,8 @@ #include "Arduino.h" #include "board.h" -#include -#include -#include + +#include "max6675.h" #define THERMO_INTERVAL 200 #define SMOOTHING_FACTOR 2