From d0fbc713a59e7c2876a88e15db8a5a155f62511b Mon Sep 17 00:00:00 2001 From: Willem Oldemans Date: Sat, 21 Aug 2021 22:15:43 +0200 Subject: [PATCH] updated control loop + draw target graph +temps --- reflow_plate_fw/include/ILI9341_STM32.h | 6 +- reflow_plate_fw/platformio.ini | 8 +- reflow_plate_fw/src/board.h | 10 +- reflow_plate_fw/src/button.cpp | 275 +++++++++++- reflow_plate_fw/src/button.h | 62 ++- reflow_plate_fw/src/controlloop.cpp | 536 ++++++++++++++++++++++++ reflow_plate_fw/src/controlloop.h | 79 ++++ reflow_plate_fw/src/heater.cpp | 10 +- reflow_plate_fw/src/lcd.cpp | 267 +++++++++--- reflow_plate_fw/src/lcd.h | 83 +++- reflow_plate_fw/src/main.cpp | 6 +- reflow_plate_fw/src/thermo.cpp | 29 +- reflow_plate_fw/src/thermo.h | 4 +- 13 files changed, 1280 insertions(+), 95 deletions(-) create mode 100644 reflow_plate_fw/src/controlloop.cpp create mode 100644 reflow_plate_fw/src/controlloop.h diff --git a/reflow_plate_fw/include/ILI9341_STM32.h b/reflow_plate_fw/include/ILI9341_STM32.h index 3ac2bf3..16d4a74 100644 --- a/reflow_plate_fw/include/ILI9341_STM32.h +++ b/reflow_plate_fw/include/ILI9341_STM32.h @@ -88,10 +88,8 @@ #define SMOOTH_FONT -// Nucleo-F767ZI has a ~216MHZ CPU clock, this is divided by 4, 8, 16 etc - -//#define SPI_FREQUENCY 27000000 // 27MHz SPI clock -#define SPI_FREQUENCY 55000000 // 55MHz is over-clocking ILI9341 but seems to work reliably! +#define SPI_FREQUENCY 27000000 // 27MHz SPI clock +//#define SPI_FREQUENCY 55000000 // 55MHz is over-clocking ILI9341 but seems to work reliably! #define SPI_READ_FREQUENCY 15000000 // Reads need a slower SPI clock, probably ends up at 13.75MHz (CPU clock/16) diff --git a/reflow_plate_fw/platformio.ini b/reflow_plate_fw/platformio.ini index 23170b5..cd42862 100644 --- a/reflow_plate_fw/platformio.ini +++ b/reflow_plate_fw/platformio.ini @@ -18,11 +18,11 @@ 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 lib_ldf_mode = deep+ -build_flags = +build_flags = -D USER_SETUP_LOADED=1 - -include include/ILI9341_STM32.h + -include include/ILI9341_STM32.h -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC - -D USBCON -D PIO_FRAMEWORK_ARDUINO_USB_FULLSPEED_FULLMODE - diff --git a/reflow_plate_fw/src/board.h b/reflow_plate_fw/src/board.h index e2a4161..d3085e4 100644 --- a/reflow_plate_fw/src/board.h +++ b/reflow_plate_fw/src/board.h @@ -11,4 +11,12 @@ #define THERM_SO PB4 #define THERM_CL PB6 -#define HEAT_OUT PA2 \ No newline at end of file +#define HEAT_OUT PA2 + +#define BUZZER A4 + +#define BUTTON_SELECT 0 +#define BUTTON_AXIS_Y 0 +#define BUTTON_AXIS_X 0 +#define BUTTON_MENU 0 +#define BUTTON_BACK 0 diff --git a/reflow_plate_fw/src/button.cpp b/reflow_plate_fw/src/button.cpp index 660e566..d598040 100644 --- a/reflow_plate_fw/src/button.cpp +++ b/reflow_plate_fw/src/button.cpp @@ -1,10 +1,281 @@ #include "button.h" +#include "controlloop.h" + +#define DEBOUNCE_MS 100 +Button start_btn(0, false, DEBOUNCE_MS, true); +Button stop_btn(0, false, DEBOUNCE_MS, true); +Button set_btn(0, false, DEBOUNCE_MS, true); + +Button *buttons[] = {&start_btn, &stop_btn, &set_btn}; + +void setButton(uint8_t index, bool state) +{ + buttons[index]->setButton(state); +} + +void readAllButtons(void) +{ + for (auto &&button : buttons) + { + button->read(); + } +} + void initButton(void) { - } + void handleButton(void) { - + readAllButtons(); + + if (start_btn.isPressed()) + { + setReflowStatus(true); + } + if (stop_btn.isPressed()) + { + setReflowStatus(false); + } + if (set_btn.isPressed()) + { + //enter menu + } +} + +/*----------------------------------------------------------------------* + * Arduino Button Library v1.0 * + * Jack Christensen May 2011, published Mar 2012 * + * * + * Library for reading momentary contact switches like tactile button * + * switches. Intended for use in state machine constructs. * + * Use the read() function to read all buttons in the main loop, * + * which should execute as fast as possible. * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 171 Second Street, Suite 300, * + * San Francisco, California, 94105, USA. * + *----------------------------------------------------------------------*/ + +#include "Button.h" + +/*----------------------------------------------------------------------* + * Button(pin, puEnable, invert, dbTime) instantiates a button object. * + * pin Is the Arduino pin the button is connected to. * + * puEnable Enables the AVR internal pullup resistor if != 0 (can also * + * use true or false). * + * invert If invert == 0, interprets a high state as pressed, low as * + * released. If invert != 0, interprets a high state as * + * released, low as pressed (can also use true or false). * + * dbTime Is the debounce time in milliseconds. * + * * + * (Note that invert cannot be implied from puEnable since an external * + * pullup could be used.) * + *----------------------------------------------------------------------*/ +Button::Button(uint8_t pin, uint8_t invert, uint32_t dbTime, bool isTouch) : _isTouchButton(isTouch) +{ + if (!_isTouchButton) + { + _pin = pin; + pinMode(_pin, INPUT_PULLUP); + _state = digitalRead(_pin); + } + _invert = invert; + _dbTime = dbTime; + if (_invert != 0) + _state = !_state; + _time = millis(); + _lastState = _state; + _changed = 0; + _lastTime = _time; + _lastChange = _time; +} + +/*----------------------------------------------------------------------* + * read() returns the state of the button, 1==pressed, 0==released, * + * does debouncing, captures and maintains times, previous states, etc. * + *----------------------------------------------------------------------*/ +uint8_t Button::read(void) +{ + static uint32_t ms; + static uint8_t pinVal; + + ms = millis(); + if (_isTouchButton) + { + pinVal = _touchState; + } + else + { + pinVal = digitalRead(_pin); + } + + if (_invert != 0) + pinVal = !pinVal; + if (ms - _lastChange < _dbTime) + { + _lastTime = _time; + _time = ms; + _changed = 0; + return _state; + Serial.println("State is: " + _state); + } + else + { + _lastTime = _time; + _lastState = _state; + _state = pinVal; + _time = ms; + if (_state != _lastState) + { + _lastChange = ms; + _changed = 1; + } + else + { + _changed = 0; + } + return _state; +#ifdef DEBUG + Serial.println("State is: " + _state); +#endif + } +} + +void Button::setButton(bool state) +{ + _touchState = state; +} + +uint8_t Button::readAxis() +{ + static uint32_t ms; + static uint8_t pinVal; + static uint16_t val; + + ms = millis(); + val = analogRead(_pin); + + if (val > 3900) + { + pinVal = 1; + _axis = DPAD_V_FULL; +#ifdef DEBUG + Serial.println("Value is: " + val); +#endif + } + else if (val > 1500 && val < 2000) + { + pinVal = 1; + _axis = DPAD_V_HALF; +#ifdef DEBUG + Serial.println("Value is: " + val); +#endif + } + else + { + pinVal = 0; + _axis = DPAD_V_NONE; + } + + if (_invert == 0) + pinVal = !pinVal; + if (ms - _lastChange < _dbTime) + { + _lastTime = _time; + _time = ms; + _changed = 0; + return _state; + } + else + { + _lastTime = _time; + _lastState = _state; + _state = pinVal; + _time = ms; + if (_state != _lastState) + { + _lastChange = ms; + _changed = 1; + } + else + { + _changed = 0; + } + return _state; + } + return _state && _changed; +} + +/*----------------------------------------------------------------------* + * isPressed() and isReleased() check the button state when it was last * + * read, and return false (0) or true (!=0) accordingly. * + * These functions do not cause the button to be read. * + *----------------------------------------------------------------------*/ +uint8_t Button::isPressed(void) +{ + return _state == 0 ? 0 : 1; +} + +uint8_t Button::isAxisPressed(void) +{ + if (_state) + return _axis; + else + return 0; +} + +uint8_t Button::isReleased(void) +{ + return _state == 0 ? 1 : 0; +} + +/*----------------------------------------------------------------------* + * wasPressed() and wasReleased() check the button state to see if it * + * changed between the last two reads and return false (0) or * + * true (!=0) accordingly. * + * These functions do not cause the button to be read. * + *----------------------------------------------------------------------*/ +uint8_t Button::wasPressed(void) +{ + return _state && _changed; +} + +uint8_t Button::wasAxisPressed(void) +{ + if (_state && _changed) + return _axis; + else + return 0; +} + +uint8_t Button::wasReleased(void) +{ + return !_state && _changed; +} +/*----------------------------------------------------------------------* + * pressedFor(ms) and releasedFor(ms) check to see if the button is * + * pressed (or released), and has been in that state for the specified * + * time in milliseconds. Returns false (0) or true (1) accordingly. * + * These functions do not cause the button to be read. * + *----------------------------------------------------------------------*/ +uint8_t Button::pressedFor(uint32_t ms) +{ + return (_state == 1 && _time - _lastChange >= ms) ? 1 : 0; +} + +uint8_t Button::releasedFor(uint32_t ms) +{ + return (_state == 0 && _time - _lastChange >= ms) ? 1 : 0; +} +/*----------------------------------------------------------------------* + * lastChange() returns the time the button last changed state, * + * in milliseconds. * + *----------------------------------------------------------------------*/ +uint32_t Button::lastChange(void) +{ + return _lastChange; } \ No newline at end of file diff --git a/reflow_plate_fw/src/button.h b/reflow_plate_fw/src/button.h index c1c4b25..766ed58 100644 --- a/reflow_plate_fw/src/button.h +++ b/reflow_plate_fw/src/button.h @@ -4,4 +4,64 @@ #include "board.h" void initButton(void); -void handleButton(void); \ No newline at end of file +void handleButton(void); +void setButton(uint8_t index, bool state); + + +/*----------------------------------------------------------------------* + * Arduino Button Library v1.0 * + * Jack Christensen Mar 2012 * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 171 Second Street, Suite 300, * + * San Francisco, California, 94105, USA. * + *----------------------------------------------------------------------*/ +#ifndef Button_h +#define Button_h +// #if ARDUINO >= 100 +#include +// #else +// #include +// #endif + + +#define DPAD_V_FULL 2 +#define DPAD_V_HALF 1 +#define DPAD_V_NONE 0 + +class Button +{ + public: + Button(uint8_t pin, uint8_t invert, uint32_t dbTime, bool isTouch); + uint8_t read(); + uint8_t readAxis(); + uint8_t isPressed(); + uint8_t isAxisPressed(); + uint8_t isReleased(); + uint8_t wasPressed(); + uint8_t wasAxisPressed(); + uint8_t wasReleased(); + uint8_t pressedFor(uint32_t ms); + uint8_t releasedFor(uint32_t ms); + uint32_t lastChange(); + void setButton(bool state); + + + private: + uint8_t _pin; //arduino pin number + uint8_t _puEnable; //internal pullup resistor enabled + uint8_t _invert; //if 0, interpret high state as pressed, else interpret low state as pressed + uint8_t _state; //current button state + uint8_t _lastState; //previous button state + uint8_t _changed; //state changed since last read + uint8_t _axis; //state changed since last read + uint32_t _time; //time of current state (all times are in ms) + uint32_t _lastTime; //time of previous state + uint32_t _lastChange; //time of last state change + uint32_t _dbTime; //debounce time + const bool _isTouchButton; + bool _touchState; +}; +#endif \ No newline at end of file diff --git a/reflow_plate_fw/src/controlloop.cpp b/reflow_plate_fw/src/controlloop.cpp new file mode 100644 index 0000000..e8f6772 --- /dev/null +++ b/reflow_plate_fw/src/controlloop.cpp @@ -0,0 +1,536 @@ +#include "controlloop.h" + +#include "thermo.h" +#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 + Date: 26-11-2012 + Company: Rocket Scream Electronics + Author: Lim Phang Moh + Website: www.rocketscream.com + + Brief + ===== + This is an example firmware for our Arduino compatible reflow oven controller. + The reflow curve used in this firmware is meant for lead-free profile + (it's even easier for leaded process!). You'll need to use the MAX31855 + library for Arduino if you are having a shield of v1.60 & above which can be + downloaded from our GitHub repository. Please check our wiki + (www.rocketscream.com/wiki) for more information on using this piece of code + together with the reflow oven controller shield. + + Temperature (Degree Celcius) Magic Happens Here! + 245-| x x + | x x + | x x + | x x + 200-| x x + | x | | x + | x | | x + | x | | + 150-| x | | + | x | | | + | x | | | + | x | | | + | x | | | + | x | | | + | x | | | + 30 -| x | | | + |< 60 - 90 s >|< 90 - 120 s >|< 90 - 120 s >| + | Preheat Stage | Soaking Stage | Reflow Stage | Cool + 0 |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + Time (Seconds) + + This firmware owed very much on the works of other talented individuals as + follows: + ========================================== + Brett Beauregard (www.brettbeauregard.com) + ========================================== + Author of Arduino PID library. On top of providing industry standard PID + implementation, he gave a lot of help in making this reflow oven controller + possible using his awesome library. + + ========================================== + Limor Fried of Adafruit (www.adafruit.com) + ========================================== + Author of Arduino MAX6675 library. Adafruit has been the source of tonnes of + tutorials, examples, and libraries for everyone to learn. + + Disclaimer + ========== + Dealing with high voltage is a very dangerous act! Please make sure you know + what you are dealing with and have proper knowledge before hand. Your use of + any information or materials on this reflow oven controller is entirely at + your own risk, for which we shall not be liable. + + Licences + ======== + This reflow oven controller hardware and firmware are released under the + Creative Commons Share Alike v3.0 license + http://creativecommons.org/licenses/by-sa/3.0/ + You are free to take this piece of code, use it and modify it. + All we ask is attribution including the supporting libraries used in this + firmware. + + Required Libraries + ================== + - Arduino PID Library: + >> https://github.com/br3ttb/Arduino-PID-Library + - MAX31855 Library (for board v1.60 & above): + >> https://github.com/rocketscream/MAX31855 + - MAX6675 Library (for board v1.50 & below): + >> https://github.com/adafruit/MAX6675-library + + Revision Description + ======== =========== + 1.20 Adds supports for v1.60 (and above) of Reflow Oven Controller + Shield: + - Uses MAX31855KASA+ chip and pin reassign (allowing A4 & A5 (I2C) + to be used for user application). + - Uses analog based switch (allowing D2 & D3 to be used for user + application). + Adds waiting state when temperature too hot to start reflow process. + Corrected thermocouple disconnect error interpretation (MAX6675). + 1.10 Arduino IDE 1.0 compatible. + 1.00 Initial public release. +*******************************************************************************/ +// Comment either one the following #define to select your board revision +// Newer board version starts from v1.60 using MAX31855KASA+ chip + +// ***** LCD MESSAGES ***** +const char *lcdMessagesReflowStatus[] = { + "Ready", + "Preheat", + "Soaking", + "Reflow", + "Cooling", + "Done", + "Warning, HOT!", + "Error"}; + +// ***** DEGREE SYMBOL FOR LCD ***** +unsigned char degree[8] = { + 140, 146, 146, 140, 128, 128, 128, 128}; + +// ***** PID CONTROL VARIABLES ***** +double setpoint; +double input; +double output; +double kp = PID_KP_PREHEAT; +double ki = PID_KI_PREHEAT; +double kd = PID_KD_PREHEAT; +int windowSize; +int inputInt; +unsigned long windowStartTime; +unsigned long nextCheck; +unsigned long nextRead; +unsigned long timerSoak; +unsigned long buzzerPeriod; +// Reflow oven controller state machine state variable +reflowState_t reflowState; +// Reflow oven controller status +reflowStatus_t reflowStatus; +// Switch debounce state machine state variable +debounceState_t debounceState; +// Switch debounce timer +long lastDebounceTime; +// Switch press status +switch_t switchStatus; +// Seconds timer +int timerSeconds; +//output state +bool outputState = false; + +bool isFault; +String activeStatus; +int oldTemp = 0; +byte state; +bool disableMenu; +bool profileIsOn; + +// 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 + windowSize = 2000; + // Initialize time keeping variable + nextCheck = millis(); + // Initialize thermocouple reading variable + nextRead = millis(); +} + + +String getReflowStatus_str(void) +{ + switch (reflowStatus) + { + case REFLOW_STATUS_OFF: + { + return String("Reflow OFF"); + } + break; + case REFLOW_STATUS_ON: + { + return String("Reflow ON"); + } + break; + default: + { + return String("Unknow State"); + } + break; + } +} + +String getReflowState_str(void) +{ + switch (reflowState) + { + case REFLOW_STATE_IDLE: + return String("Idle"); + break; + case REFLOW_STATE_PREHEAT: + return String("Preheating"); + break; + case REFLOW_STATE_SOAK: + return String("Soaking"); + break; + case REFLOW_STATE_REFLOW: + return String("Reflowing"); + break; + case REFLOW_STATE_COOL: + return String("Cooling"); + break; + case REFLOW_STATE_COMPLETE: + return String("Completed"); + break; + case REFLOW_STATE_TOO_HOT: + return String("OVERHEATING!"); + break; + case REFLOW_STATE_ERROR: + return String("Error"); + break; + default: + return String("Unknow State"); + break; + } +} + +void setReflowStatus(bool newStatus) +{ + if (newStatus) + { + profileIsOn = true; + } + else + { + profileIsOn = false; + reflowStatus = REFLOW_STATUS_OFF; + // Reinitialize state machine + reflowState = REFLOW_STATE_IDLE; + } +} + +reflowStatus_t getReflowStatus(void) +{ + return reflowStatus; +} + +double getReflowTargetTemp(void) +{ + return setpoint; +} + +bool getOutputState(void) +{ + return outputState; +} + +void handleReflowStatemachine(void) +{ + // Reflow oven controller state machine + switch (reflowState) + { + case REFLOW_STATE_IDLE: + activeStatus = "Idle"; + // If oven temperature is still above room temperature + if (input >= TEMPERATURE_ROOM) + { + reflowState = REFLOW_STATE_TOO_HOT; + Serial.println("Status: Too hot to start"); + } + else + { + // If switch is pressed to start reflow process + //if (switchStatus == SWITCH_1) + if (profileIsOn != 0) + { + // Send header for CSV file + Serial.println("Time Setpoint Input Output"); + // Intialize seconds timer for serial debug information + timerSeconds = 0; + // Initialize PID control window starting time + windowStartTime = millis(); + // Ramp up to minimum soaking temperature + setpoint = TEMPERATURE_SOAK_MIN; + // Tell the PID to range between 0 and the full window size + reflowOvenPID.SetOutputLimits(0, windowSize); + reflowOvenPID.SetSampleTime(PID_SAMPLE_TIME); + // Turn the PID on + reflowOvenPID.SetMode(AUTOMATIC); + // Proceed to preheat stage + reflowState = REFLOW_STATE_PREHEAT; + } + } + break; + + case REFLOW_STATE_PREHEAT: + activeStatus = "Preheat"; + reflowStatus = REFLOW_STATUS_ON; + // If minimum soak temperature is achieve + if (input >= TEMPERATURE_SOAK_MIN) + { + // Chop soaking period into smaller sub-period + timerSoak = millis() + SOAK_MICRO_PERIOD; + // Set less agressive PID parameters for soaking ramp + reflowOvenPID.SetTunings(PID_KP_SOAK, PID_KI_SOAK, PID_KD_SOAK); + // Ramp up to first section of soaking temperature + setpoint = TEMPERATURE_SOAK_MIN + SOAK_TEMPERATURE_STEP; + // Proceed to soaking state + reflowState = REFLOW_STATE_SOAK; + } + break; + + case REFLOW_STATE_SOAK: + activeStatus = "Soak"; + // If micro soak temperature is achieved + if (millis() > timerSoak) + { + timerSoak = millis() + SOAK_MICRO_PERIOD; + // Increment micro setpoint + setpoint += SOAK_TEMPERATURE_STEP; + if (setpoint > TEMPERATURE_SOAK_MAX) + { + // Set agressive PID parameters for reflow ramp + reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW); + // Ramp up to first section of soaking temperature + setpoint = TEMPERATURE_REFLOW_MAX; + // Proceed to reflowing state + reflowState = REFLOW_STATE_REFLOW; + } + } + break; + + case REFLOW_STATE_REFLOW: + activeStatus = "Reflow"; + // We need to avoid hovering at peak temperature for too long + // Crude method that works like a charm and safe for the components + if (input >= (TEMPERATURE_REFLOW_MAX - 5)) + { + // Set PID parameters for cooling ramp + reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW); + // Ramp down to minimum cooling temperature + setpoint = TEMPERATURE_COOL_MIN; + // Proceed to cooling state + reflowState = REFLOW_STATE_COOL; + } + break; + + case REFLOW_STATE_COOL: + activeStatus = "Cool"; + // If minimum cool temperature is achieve + if (input <= TEMPERATURE_COOL_MIN) + { + // Retrieve current time for buzzer usage + buzzerPeriod = millis() + 1000; + // Turn on buzzer and green LED to indicate completion + digitalWrite(BUZZER, HIGH); + // Turn off reflow process + reflowStatus = REFLOW_STATUS_OFF; + // Proceed to reflow Completion state + reflowState = REFLOW_STATE_COMPLETE; + } + break; + + case REFLOW_STATE_COMPLETE: + activeStatus = "Complete"; + if (millis() > buzzerPeriod) + { + // Turn off buzzer and green LED + digitalWrite(BUZZER, LOW); + // Reflow process ended + reflowState = REFLOW_STATE_IDLE; + profileIsOn = 0; + Serial.println("Profile is OFF"); + } + break; + + case REFLOW_STATE_TOO_HOT: + // If oven temperature drops below room temperature + if (input < TEMPERATURE_ROOM) + { + // Ready to reflow + reflowState = REFLOW_STATE_IDLE; + } + break; + + case REFLOW_STATE_ERROR: + // If thermocouple problem is still present + + if (input == 0) // || (input == FAULT_SHORT_GND) || + // (input == FAULT_SHORT_VCC)) + { + // Wait until thermocouple wire is connected + reflowState = REFLOW_STATE_ERROR; + } + else + { + // Clear to perform reflow process + reflowState = REFLOW_STATE_IDLE; + } + break; + } +} + +void handleReflowPID(void) +{ + unsigned long now; + // PID computation and SSR control + if (reflowStatus == REFLOW_STATUS_ON) + { + now = millis(); + + reflowOvenPID.Compute(); + + if ((now - windowStartTime) > windowSize) + { + // Time to shift the Relay Window + windowStartTime += windowSize; + } + if (output > (now - windowStartTime)) + { + digitalWrite(HEAT_OUT, HIGH); + outputState = true; + } + else + { + digitalWrite(HEAT_OUT, LOW); + outputState = false; + } + } + // Reflow oven process is off, ensure oven is off + else + { + digitalWrite(HEAT_OUT, LOW); + outputState = false; + } +} + +void handleTemperatureReadings(void) +{ + unsigned long now; + + // Time to read thermocouple? + if (millis() > nextRead) + { + + // Read thermocouple next sampling period + nextRead += SENSOR_SAMPLING_TIME; + // Read current temperature + + input = getTemperature(); + // Check and print any faults + uint8_t fault = getThermoCoupleFault(); + // inputInt = (int) input; + // if ((input <= inputInt) || (input >= inputInt)) { + // loopScreen(); + // } + if ((((int)input) < inputInt) || (((int)input) > inputInt)) + { + //loopScreen(); + } + inputInt = input / 1; + + if (oldTemp != inputInt) + { + if (state == 0) + { + loopScreen(); + } +#ifdef Serial + if ((input > 0) && (input <= 500)) + { + Serial.print("Float temp: " + String(input)); + Serial.print(" ; "); + Serial.println("Integer temp: " + String(inputInt)); + } +#endif + } + // If thermocouple problem detected + if (input == 0) + { + // Illegal operation + reflowState = REFLOW_STATE_ERROR; + reflowStatus = REFLOW_STATUS_OFF; + } + oldTemp = inputInt; + } + + if (millis() > nextCheck) + { + // Check input in the next seconds + nextCheck += 1000; + // If reflow process is on going + if (reflowStatus == REFLOW_STATUS_ON) + { + // Increase seconds timer for reflow curve analysis + timerSeconds++; + // Send temperature and time stamp to serial + Serial.print(timerSeconds); + Serial.print(" "); + Serial.print(setpoint); + Serial.print(" "); + Serial.print(input); + Serial.print(" "); + Serial.println(output); + } + else + { + // Turn off red LED + digitalWrite(LED_BUILTIN, LOW); + } + // If currently in error state + if (reflowState == REFLOW_STATE_ERROR) + { + // No thermocouple wire connected + Serial.println("TC Error!"); + } + } +} + + +/* ---- REFLOW MAIN LOOP ---- */ +void handleControlLoop() +{ + if (state == 9) + { + Serial.println("handlecontrolloop: ERROR state"); + return; + } + + handleTemperatureReadings(); + handleReflowStatemachine(); + handleReflowPID(); +} \ No newline at end of file diff --git a/reflow_plate_fw/src/controlloop.h b/reflow_plate_fw/src/controlloop.h new file mode 100644 index 0000000..6d56b11 --- /dev/null +++ b/reflow_plate_fw/src/controlloop.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include "Arduino.h" + +// ***** CONSTANTS ***** +#define TEMPERATURE_ROOM 50 +#define TEMPERATURE_SOAK_MIN 150 +#define TEMPERATURE_SOAK_MAX 185 +#define TEMPERATURE_REFLOW_MAX 220 +#define TEMPERATURE_COOL_MIN 100 +#define SENSOR_SAMPLING_TIME 1000 +#define SOAK_TEMPERATURE_STEP 5 +#define SOAK_MICRO_PERIOD 9000 +#define DEBOUNCE_PERIOD_MIN 50 +#define PREHEAT_PERIOD 12000 +#define REFLOW_PERIOD 12000 +#define COOLDOWN_PERIOD 30000 + +// ***** PID PARAMETERS ***** +// ***** PRE-HEAT STAGE ***** +#define PID_KP_PREHEAT 100 +#define PID_KI_PREHEAT 0.025 +#define PID_KD_PREHEAT 20 +// ***** SOAKING STAGE ***** +#define PID_KP_SOAK 300 +#define PID_KI_SOAK 0.05 +#define PID_KD_SOAK 250 +// ***** REFLOW STAGE ***** +#define PID_KP_REFLOW 300 +#define PID_KI_REFLOW 0.05 +#define PID_KD_REFLOW 350 +#define PID_SAMPLE_TIME 1000 +// This is for testing on different board +// #define LCD_PIN 14 +// #define ODROID + + +// ***** TYPE DEFINITIONS ***** +typedef enum REFLOW_STATE +{ + REFLOW_STATE_IDLE, + REFLOW_STATE_PREHEAT, + REFLOW_STATE_SOAK, + REFLOW_STATE_REFLOW, + REFLOW_STATE_COOL, + REFLOW_STATE_COMPLETE, + REFLOW_STATE_TOO_HOT, + REFLOW_STATE_ERROR +} reflowState_t; + +typedef enum REFLOW_STATUS +{ + REFLOW_STATUS_OFF, + REFLOW_STATUS_ON +} reflowStatus_t; + +typedef enum SWITCH +{ + SWITCH_NONE, + SWITCH_1, + SWITCH_2 +} switch_t; + +typedef enum DEBOUNCE_STATE +{ + DEBOUNCE_STATE_IDLE, + DEBOUNCE_STATE_CHECK, + DEBOUNCE_STATE_RELEASE +} debounceState_t; + +void initControlLoop(void); +void handleControlLoop(void); + +String getReflowStatus_str(void); +String getReflowState_str(void); +reflowStatus_t getReflowStatus(void); +void setReflowStatus(bool newStatus); +double getReflowTargetTemp(void); +bool getOutputState(void); diff --git a/reflow_plate_fw/src/heater.cpp b/reflow_plate_fw/src/heater.cpp index 48f7bab..65fabda 100644 --- a/reflow_plate_fw/src/heater.cpp +++ b/reflow_plate_fw/src/heater.cpp @@ -1,9 +1,17 @@ #include "heater.h" +uint16_t heatingProfile[] = +{ + 30, + 50, + 70, + 90 +}; void initHeater(void) { - + pinMode(HEAT_OUT,OUTPUT); + digitalWrite(HEAT_OUT, LOW); } void handleHeater(void) diff --git a/reflow_plate_fw/src/lcd.cpp b/reflow_plate_fw/src/lcd.cpp index 4215764..2674dcb 100644 --- a/reflow_plate_fw/src/lcd.cpp +++ b/reflow_plate_fw/src/lcd.cpp @@ -1,6 +1,8 @@ #include "lcd.h" #include "thermo.h" +#include "controlloop.h" +#include "button.h" #include // Include the graphics library @@ -8,56 +10,190 @@ TFT_eSPI tft = TFT_eSPI(); // Create object "tft" TFT_eSprite looptime_spr = TFT_eSprite(&tft); //chart data -TFT_eSprite chartbg_spr = TFT_eSprite(&tft); -TFT_eSprite chartActual_spr = TFT_eSprite(&tft); -TFT_eSprite chartTarget_spr = TFT_eSprite(&tft); +TFT_eSprite chartXaxis_spr = TFT_eSprite(&tft); +TFT_eSprite chartYaxis_spr = TFT_eSprite(&tft); +TFT_eSprite chartArea_spr = TFT_eSprite(&tft); +TFT_eSprite reflowstate_spr = TFT_eSprite(&tft); +TFT_eSprite output_spr = TFT_eSprite(&tft); //buttons String buttonNames[] = {"START", "STOP", "SET"}; char buttonlabels[BUTTONS_N][10] = {"", "", ""}; TFT_eSPI_Button key[BUTTONS_N]; - uint16_t calData[5] = {549, 3080, 343, 3159, 4}; -void prep_chart(void) +uint32_t lastButtonTime = 0; + +void updateTemperature(void) { - chartbg_spr.createSprite(CHART_W, CHART_H); + //draw actualTemperature + 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); + if (getReflowStatus() == REFLOW_STATUS_OFF) + { + chartArea_spr.drawString("--", TEMP_X + TEMP_VALUE_X, TEMP_H / 4 * 3); + } + else + { + chartArea_spr.drawNumber(getReflowTargetTemp(), TEMP_X + TEMP_VALUE_X, TEMP_H / 4 * 3); + } +} + +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; +} + +uint32_t calcTime(uint32_t timeMs) +{ + return map((timeMs / 1000), 0, CHART_TIME_MAX, 0, CHART_W - CHART_Y_AXIS_OFFSET); +} + +void updateTargetChart(void) +{ + + chartArea_spr.fillSprite(CHART_BG_COLOR); + + //draw preheat + uint32_t stepTimeStart = 0; + uint32_t stepTimeStop = calcTime(PREHEAT_PERIOD); + chartArea_spr.drawLine(stepTimeStart, + CHART_H - CHART_X_AXIS_OFFSET, + stepTimeStop, + calcTemp(TEMPERATURE_SOAK_MIN), + CHART_TARGET_COLOR); + //draw soak + stepTimeStart = stepTimeStop; + stepTimeStop += calcTime(SOAK_MICRO_PERIOD * (((TEMPERATURE_SOAK_MAX - TEMPERATURE_SOAK_MIN) / SOAK_TEMPERATURE_STEP) - 1)); + chartArea_spr.drawLine(stepTimeStart, + calcTemp(TEMPERATURE_SOAK_MIN), + stepTimeStop, + calcTemp(TEMPERATURE_SOAK_MAX), + CHART_TARGET_COLOR); + + //draw reflow + stepTimeStart = stepTimeStop; + stepTimeStop += calcTime(REFLOW_PERIOD); + chartArea_spr.drawLine(stepTimeStart, + calcTemp(TEMPERATURE_SOAK_MAX), + stepTimeStop, + calcTemp(TEMPERATURE_REFLOW_MAX), + CHART_TARGET_COLOR); + + //draw cool + stepTimeStart = stepTimeStop; + stepTimeStop += calcTime(COOLDOWN_PERIOD); + chartArea_spr.drawLine(stepTimeStart, + calcTemp(TEMPERATURE_REFLOW_MAX), + stepTimeStop, + calcTemp(TEMPERATURE_ROOM), + CHART_TARGET_COLOR); + + updateTemperature(); + chartArea_spr.pushSprite(CHART_X + CHART_Y_AXIS_OFFSET, CHART_Y); +} + +void prepTargetChart(void) +{ + chartArea_spr.createSprite(CHART_W - CHART_Y_AXIS_OFFSET, CHART_H - CHART_X_AXIS_OFFSET); + chartArea_spr.setTextFont(TEMP_FONT); + chartArea_spr.setTextColor(TEMP_F_COLOR); + chartArea_spr.setTextDatum(CL_DATUM); + updateTargetChart(); +} + +void updateReflowState(void) +{ + reflowstate_spr.fillRoundRect(STATE_OFFSET, 0, (STATE_W / 2) - (2 * STATE_OFFSET), STATE_H, STATE_R, STATE_BG_COLOR); + 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); + reflowstate_spr.pushSprite(STATE_X, STATE_Y); +} + +void prepReflowstate(void) +{ + reflowstate_spr.createSprite(STATE_W, STATE_H); + reflowstate_spr.setTextFont(STATE_FONT); + reflowstate_spr.setTextColor(STATE_F_COLOR); + reflowstate_spr.setTextDatum(MC_DATUM); + updateReflowState(); +} + +void updateOutput(void) +{ + output_spr.fillSprite(OUTPUT_BG); + if (getOutputState()) + { + output_spr.fillCircle(OUTPUT_W / 2, OUTPUT_H / 2, OUTPUT_R, OUTPUT_ON_COLOR); + } + else + { + output_spr.drawCircle(OUTPUT_W / 2, OUTPUT_H / 2, OUTPUT_R, OUTPUT_OFF_COLOR); + } + output_spr.pushSprite(OUTPUT_X, OUTPUT_Y); +} + +void prepOutput(void) +{ + output_spr.createSprite(OUTPUT_W, OUTPUT_H); + updateOutput(); +} + +void prepChart(void) +{ + chartXaxis_spr.createSprite(CHART_W, CHART_X_AXIS_OFFSET); + chartYaxis_spr.createSprite(CHART_Y_AXIS_OFFSET, CHART_H); //draw X-axis - chartbg_spr.drawLine(0, CHART_H - CHART_X_AXIS_OFFSET, CHART_W, CHART_H - CHART_X_AXIS_OFFSET, CHART_LINE_COLOR); + chartXaxis_spr.drawLine(0, 0, CHART_W, 0, CHART_LINE_COLOR); //draw Y-axis - chartbg_spr.drawLine(CHART_Y_AXIS_OFFSET, 0, CHART_Y_AXIS_OFFSET, CHART_H, CHART_LINE_COLOR); + chartYaxis_spr.drawLine(CHART_Y_AXIS_OFFSET - 1, 0, CHART_Y_AXIS_OFFSET - 1, CHART_H, CHART_LINE_COLOR); //draw Y axis labels uint16_t tickIndex = (CHART_H - CHART_X_AXIS_OFFSET) / CHART_Y_TICKS; - chartbg_spr.setTextColor(CHART_TEXT_COLOR); - for (int i = 0; i < CHART_Y_TICKS + 1; i++) + chartXaxis_spr.setTextColor(CHART_TEXT_COLOR); + chartYaxis_spr.setTextColor(CHART_TEXT_COLOR); + + 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) - CHART_TEMP_MIN; - chartbg_spr.drawLine(CHART_Y_AXIS_OFFSET - 2, tickIndex * (i + 1), CHART_Y_AXIS_OFFSET + 2, tickIndex * (i + 1), CHART_LINE_COLOR); - chartbg_spr.setTextDatum(BR_DATUM); - chartbg_spr.drawString(String(y_tick_step), CHART_Y_AXIS_OFFSET - 3, tickIndex * (i + 1), CHART_FONT); + uint16_t y_tick_step = 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); } //draw X axis labels tickIndex = (CHART_W - CHART_Y_AXIS_OFFSET) / CHART_X_TICKS; for (int i = 0; i < CHART_X_TICKS + 1; i++) { - uint16_t x_tick_step = (CHART_TIME_MAX / CHART_Y_TICKS * i); - chartbg_spr.drawLine(tickIndex * i + CHART_Y_AXIS_OFFSET, CHART_H - CHART_X_AXIS_OFFSET + 2, tickIndex * i + CHART_Y_AXIS_OFFSET, CHART_H - CHART_X_AXIS_OFFSET - 2, CHART_LINE_COLOR); - chartbg_spr.setTextDatum(TR_DATUM); - chartbg_spr.drawString(String(x_tick_step),tickIndex * i + CHART_Y_AXIS_OFFSET,CHART_H - CHART_X_AXIS_OFFSET + 3,CHART_FONT); + uint16_t x_tick_step = (CHART_TIME_MAX / CHART_X_TICKS * (i)); + chartXaxis_spr.drawLine(tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 0, tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 8, CHART_LINE_COLOR); + chartXaxis_spr.setTextDatum(TR_DATUM); + chartXaxis_spr.drawString(String(x_tick_step), tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 3, CHART_FONT); } - - chartbg_spr.pushSprite(CHART_X, CHART_Y); + chartXaxis_spr.pushSprite(CHART_X, CHART_Y + CHART_H - CHART_X_AXIS_OFFSET); + chartYaxis_spr.pushSprite(CHART_X, CHART_Y); } -void prep_sprite(void) +void prepStatus(void) { looptime_spr.createSprite(20, tft.fontHeight(1) + 1); } -void prep_buttons(void) +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.pushSprite(1, 1); +} + +void prepButtons(void) { const uint32_t button_width = tft.width() / BUTTONS_N; @@ -114,35 +250,44 @@ void touch_calibrate() void updateGUIButtons(void) { - uint16_t t_x = 0, t_y = 0; // To store the touch coordinates - bool pressed = tft.getTouch(&t_x, &t_y); - - for (uint8_t b = 0; b < BUTTONS_N; b++) + uint32_t timeNow = millis(); + if (timeNow - lastButtonTime > BUTTON_INTERVAL) { - if (pressed && key[b].contains(t_x, t_y)) - { - key[b].press(true); // tell the button it is pressed - } - else - { - key[b].press(false); // tell the button it is NOT pressed - } - } + uint16_t t_x = 0, t_y = 0; // To store the touch coordinates + bool pressed = tft.getTouch(&t_x, &t_y); - // Check if any key has changed state - for (uint8_t b = 0; b < BUTTONS_N; b++) - { - // If button was just pressed, redraw inverted button - if (key[b].justPressed()) + for (uint8_t b = 0; b < BUTTONS_N; b++) { - key[b].drawButton(true, buttonNames[b]); + if (pressed && key[b].contains(t_x, t_y)) + { + //Serial.println("key pressed"); + key[b].press(true); // tell the button it is pressed + setButton(b, true); + } + else + { + //Serial.println("key released"); + key[b].press(false); // tell the button it is NOT pressed + setButton(b, false); + } } - // If button was just released, redraw normal color button - if (key[b].justReleased()) + // Check if any key has changed state + for (uint8_t b = 0; b < BUTTONS_N; b++) { - key[b].drawButton(false, buttonNames[b]); + // If button was just pressed, redraw inverted button + if (key[b].justPressed()) + { + key[b].drawButton(true, buttonNames[b]); + } + + // If button was just released, redraw normal color button + if (key[b].justReleased()) + { + key[b].drawButton(false, buttonNames[b]); + } } + lastButtonTime = timeNow; } } @@ -158,20 +303,36 @@ void initLCD(void) tft.invertDisplay(false); //touch_calibrate(); tft.setTouch(calData); - prep_sprite(); - prep_buttons(); - prep_chart(); + + prepStatus(); + prepButtons(); + prepChart(); + prepReflowstate(); + prepTargetChart(); + prepOutput(); } // ------------------------------------------------------------------------- // Main loop // ------------------------------------------------------------------------- + +uint32_t lastLCDupdate = 0; + void handleLCD() { - 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.pushSprite(1, 1); - updateGUIButtons(); - //tft.drawString(showValue("Temp", getTemperature(), "grC"), 10, 10); + updateStatus(); + + uint32_t timeNow = millis(); + if (timeNow - lastLCDupdate > LCD_INTERVAL) + { + updateGUIButtons(); + updateReflowState(); + updateTargetChart(); + updateOutput(); + lastLCDupdate = timeNow; + } +} + +void loopScreen(void) +{ } \ No newline at end of file diff --git a/reflow_plate_fw/src/lcd.h b/reflow_plate_fw/src/lcd.h index d3edc3f..ae55cf1 100644 --- a/reflow_plate_fw/src/lcd.h +++ b/reflow_plate_fw/src/lcd.h @@ -3,32 +3,77 @@ #include "status.h" -// #define WIDTH 240 -// #define HEIGHT 60 -#define BUTTON_H 60 -#define BUTTON_W 240 -#define BUTTONS_N 3 -#define BUTTON_PADDING 2 -#define BUTTON_RADIUS 8 -#define BUTTON_COLOR TFT_BLUE -#define KEY_TEXTSIZE 1 // Font size multiplier +#define TFT_WIDTH 240 +#define TFT_HEIGT 320 +#define TFT_DEFAULT_R 4 + +#define LCD_INTERVAL 100 + +#define BUTTON_H 60 +#define BUTTON_W TFT_WIDTH +#define BUTTONS_N 3 +#define BUTTON_PADDING 2 +#define BUTTON_RADIUS 8 +#define BUTTON_COLOR TFT_BLUE +#define BUTTON_INTERVAL 20 + +#define KEY_TEXTSIZE 1 // Font size multiplier #define CHART_X 0 -#define CHART_Y 30 -#define CHART_W 240 -#define CHART_H 200 -#define CHART_FONT 1 +#define CHART_Y 40 #define CHART_Y_AXIS_OFFSET 24 #define CHART_X_AXIS_OFFSET 10 -#define CHART_TIME_MAX 360 //time scale in seconds +#define CHART_W TFT_WIDTH - 5 +#define CHART_H 200 +#define CHART_FONT 1 + +#define CHART_TIME_MAX 140 //time scale in seconds #define CHART_TEMP_MIN 20 //offset in degrees -#define CHART_TEMP_MAX 360 //degrees -#define CHART_Y_TICKS 10 -#define CHART_X_TICKS 10 -#define CHART_LINE_COLOR TFT_WHITE -#define CHART_TEXT_COLOR TFT_RED +#define CHART_TEMP_MAX 240 //degrees +#define CHART_Y_TICKS 11 +#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_ACTUAL_COLOR TFT_RED +#define CHART_BG_COLOR TFT_BLACK +#define STATE_X 0 +#define STATE_Y 13 +#define STATE_W TFT_WIDTH +#define STATE_H 24 +#define STATE_FONT 2 +#define STATE_OFFSET 3 +#define STATE_F_COLOR TFT_BLACK +#define STATE_R TFT_DEFAULT_R +#define STATE_BG_COLOR TFT_GREEN + +#define TEMP_W 60 +#define TEMP_H 40 +#define TEMP_X CHART_W - TEMP_W - 20//allign right +#define TEMP_Y 40 +#define TEMP_FONT 2 +#define TEMP_F_COLOR TFT_WHITE +#define TEMP_BG_COLOR TFT_BLUE +#define TEMP_R TFT_DEFAULT_R +#define TEMP_LABEL_X 2 +#define TEMP_VALUE_X 30 + +#define OUTPUT_W 12 +#define OUTPUT_H 12 +#define OUTPUT_R 5 +#define OUTPUT_Y 0 +#define OUTPUT_X TFT_WIDTH - OUTPUT_W - 2 +#define OUTPUT_ON_COLOR TFT_RED +#define OUTPUT_OFF_COLOR TFT_WHITE +#define OUTPUT_BG TFT_BLACK + + + +#define DEBOUNCE_MS 100 void initLCD(void); void handleLCD(void); + +void loopScreen(void); diff --git a/reflow_plate_fw/src/main.cpp b/reflow_plate_fw/src/main.cpp index 8a20718..d18f8a4 100644 --- a/reflow_plate_fw/src/main.cpp +++ b/reflow_plate_fw/src/main.cpp @@ -6,26 +6,26 @@ #include "button.h" #include "heater.h" #include "status.h" +#include "controlloop.h" void setup() { - // put your setup code here, to run once: initStatus(); initLCD(); initThermo(); initButton(); initHeater(); - + initControlLoop(); } void loop() { - // put your main code here, to run repeatedly: handleLCD(); handleThermo(); handleButton(); handleHeater(); handleStatus(); + handleControlLoop(); } \ No newline at end of file diff --git a/reflow_plate_fw/src/thermo.cpp b/reflow_plate_fw/src/thermo.cpp index c61c048..0028bc4 100644 --- a/reflow_plate_fw/src/thermo.cpp +++ b/reflow_plate_fw/src/thermo.cpp @@ -6,14 +6,12 @@ uint32_t thermo_lastTime = 0; double lastTemperature = 0; -// the setup function runs once when you press reset or power the board void initThermo() { Thermocouple *originThermocouple = new MAX6675_Thermocouple(THERM_CL, THERM_CS, THERM_SO); thermocouple = new SmoothThermocouple(originThermocouple, SMOOTHING_FACTOR); } -// the loop function runs over and over again forever void handleThermo(void) { // Reads temperature @@ -21,13 +19,32 @@ void handleThermo(void) if (timeNow - thermo_lastTime > THERMO_INTERVAL) { lastTemperature = thermocouple->readCelsius(); - Serial.printf("Thermocouple = %d\n",lastTemperature); + thermo_lastTime = timeNow; } - - //delay(100); // optionally, only to delay the output of information in the example. } double getTemperature(void) { - return lastTemperature; + return 23;//lastTemperature; +} + +bool getThermoCoupleFault(void) +{ +#ifdef MAX31856 + uint8_t fault = thermocouple.readFault(); + if (fault) + { + if (fault & MAX6675_FAULT_CJRANGE) //Serial.println("Cold Junction Range Fault"); + if (fault & MAX31856_FAULT_TCRANGE) //Serial.println("Thermocouple Range Fault"); + if (fault & MAX31856_FAULT_CJHIGH) //Serial.println("Cold Junction High Fault"); + if (fault & MAX31856_FAULT_CJLOW) //Serial.println("Cold Junction Low Fault"); + if (fault & MAX31856_FAULT_TCHIGH) //Serial.println("Thermocouple High Fault"); + if (fault & MAX31856_FAULT_TCLOW) //Serial.println("Thermocouple Low Fault"); + if (fault & MAX31856_FAULT_OVUV) //Serial.println("Over/Under Voltage Fault"); + if (fault & MAX31856_FAULT_OPEN) //Serial.println("Thermocouple Open Fault"); + return true; + } +#else + return false; +#endif } diff --git a/reflow_plate_fw/src/thermo.h b/reflow_plate_fw/src/thermo.h index 3e890c3..588c874 100644 --- a/reflow_plate_fw/src/thermo.h +++ b/reflow_plate_fw/src/thermo.h @@ -7,8 +7,10 @@ #include #define THERMO_INTERVAL 200 -#define SMOOTHING_FACTOR 5 +#define SMOOTHING_FACTOR 2 void initThermo(void); void handleThermo(void); double getTemperature(void); +bool getThermoCoupleFault(void); +