updated control loop + draw target graph +temps
This commit is contained in:
@@ -88,10 +88,8 @@
|
|||||||
#define SMOOTH_FONT
|
#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)
|
#define SPI_READ_FREQUENCY 15000000 // Reads need a slower SPI clock, probably ends up at 13.75MHz (CPU clock/16)
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ monitor_speed = 115200
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
yuriisalimov/MAX6675_Thermocouple@^2.0.2
|
yuriisalimov/MAX6675_Thermocouple@^2.0.2
|
||||||
bodmer/TFT_eSPI@^2.3.70
|
bodmer/TFT_eSPI@^2.3.70
|
||||||
|
br3ttb/PID@^1.2.1
|
||||||
|
;siruli/MAX6675@^2.1.0
|
||||||
lib_ldf_mode = deep+
|
lib_ldf_mode = deep+
|
||||||
build_flags =
|
build_flags =
|
||||||
-D USER_SETUP_LOADED=1
|
-D USER_SETUP_LOADED=1
|
||||||
-include include/ILI9341_STM32.h
|
-include include/ILI9341_STM32.h
|
||||||
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||||
-D USBCON
|
|
||||||
-D PIO_FRAMEWORK_ARDUINO_USB_FULLSPEED_FULLMODE
|
-D PIO_FRAMEWORK_ARDUINO_USB_FULLSPEED_FULLMODE
|
||||||
|
|
||||||
|
|||||||
@@ -11,4 +11,12 @@
|
|||||||
#define THERM_SO PB4
|
#define THERM_SO PB4
|
||||||
#define THERM_CL PB6
|
#define THERM_CL PB6
|
||||||
|
|
||||||
#define HEAT_OUT PA2
|
#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
|
||||||
|
|||||||
@@ -1,10 +1,281 @@
|
|||||||
#include "button.h"
|
#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 initButton(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleButton(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;
|
||||||
}
|
}
|
||||||
@@ -4,4 +4,64 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
void initButton(void);
|
void initButton(void);
|
||||||
void handleButton(void);
|
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 <Arduino.h>
|
||||||
|
// #else
|
||||||
|
// #include <WProgram.h>
|
||||||
|
// #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
|
||||||
536
reflow_plate_fw/src/controlloop.cpp
Normal file
536
reflow_plate_fw/src/controlloop.cpp
Normal file
@@ -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();
|
||||||
|
}
|
||||||
79
reflow_plate_fw/src/controlloop.h
Normal file
79
reflow_plate_fw/src/controlloop.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <PID_v1.h>
|
||||||
|
#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);
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
#include "heater.h"
|
#include "heater.h"
|
||||||
|
|
||||||
|
uint16_t heatingProfile[] =
|
||||||
|
{
|
||||||
|
30,
|
||||||
|
50,
|
||||||
|
70,
|
||||||
|
90
|
||||||
|
};
|
||||||
|
|
||||||
void initHeater(void)
|
void initHeater(void)
|
||||||
{
|
{
|
||||||
|
pinMode(HEAT_OUT,OUTPUT);
|
||||||
|
digitalWrite(HEAT_OUT, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleHeater(void)
|
void handleHeater(void)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
|
||||||
#include "thermo.h"
|
#include "thermo.h"
|
||||||
|
#include "controlloop.h"
|
||||||
|
#include "button.h"
|
||||||
|
|
||||||
#include <TFT_eSPI.h> // Include the graphics library
|
#include <TFT_eSPI.h> // Include the graphics library
|
||||||
|
|
||||||
@@ -8,56 +10,190 @@ TFT_eSPI tft = TFT_eSPI(); // Create object "tft"
|
|||||||
TFT_eSprite looptime_spr = TFT_eSprite(&tft);
|
TFT_eSprite looptime_spr = TFT_eSprite(&tft);
|
||||||
|
|
||||||
//chart data
|
//chart data
|
||||||
TFT_eSprite chartbg_spr = TFT_eSprite(&tft);
|
TFT_eSprite chartXaxis_spr = TFT_eSprite(&tft);
|
||||||
TFT_eSprite chartActual_spr = TFT_eSprite(&tft);
|
TFT_eSprite chartYaxis_spr = TFT_eSprite(&tft);
|
||||||
TFT_eSprite chartTarget_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
|
//buttons
|
||||||
String buttonNames[] = {"START", "STOP", "SET"};
|
String buttonNames[] = {"START", "STOP", "SET"};
|
||||||
char buttonlabels[BUTTONS_N][10] = {"", "", ""};
|
char buttonlabels[BUTTONS_N][10] = {"", "", ""};
|
||||||
TFT_eSPI_Button key[BUTTONS_N];
|
TFT_eSPI_Button key[BUTTONS_N];
|
||||||
|
|
||||||
uint16_t calData[5] = {549, 3080, 343, 3159, 4};
|
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
|
//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
|
//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
|
//draw Y axis labels
|
||||||
uint16_t tickIndex = (CHART_H - CHART_X_AXIS_OFFSET) / CHART_Y_TICKS;
|
uint16_t tickIndex = (CHART_H - CHART_X_AXIS_OFFSET) / CHART_Y_TICKS;
|
||||||
chartbg_spr.setTextColor(CHART_TEXT_COLOR);
|
chartXaxis_spr.setTextColor(CHART_TEXT_COLOR);
|
||||||
for (int i = 0; i < CHART_Y_TICKS + 1; i++)
|
chartYaxis_spr.setTextColor(CHART_TEXT_COLOR);
|
||||||
|
|
||||||
|
for (int i = 0; i < CHART_Y_TICKS; i++)
|
||||||
{
|
{
|
||||||
//tick value
|
//tick value
|
||||||
uint16_t y_tick_step = CHART_TEMP_MAX - ((CHART_TEMP_MAX - CHART_TEMP_MIN) / CHART_Y_TICKS * i) - CHART_TEMP_MIN;
|
uint16_t y_tick_step = CHART_TEMP_MAX - ((CHART_TEMP_MAX - CHART_TEMP_MIN) / CHART_Y_TICKS * i + 1) + 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);
|
chartYaxis_spr.drawLine(CHART_Y_AXIS_OFFSET - 8, tickIndex * (i + 1), CHART_Y_AXIS_OFFSET, tickIndex * (i + 1), CHART_LINE_COLOR);
|
||||||
chartbg_spr.setTextDatum(BR_DATUM);
|
chartYaxis_spr.setTextDatum(BR_DATUM);
|
||||||
chartbg_spr.drawString(String(y_tick_step), CHART_Y_AXIS_OFFSET - 3, tickIndex * (i + 1), CHART_FONT);
|
chartYaxis_spr.drawString(String(y_tick_step), CHART_Y_AXIS_OFFSET - 3, tickIndex * (i + 1), CHART_FONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw X axis labels
|
//draw X axis labels
|
||||||
tickIndex = (CHART_W - CHART_Y_AXIS_OFFSET) / CHART_X_TICKS;
|
tickIndex = (CHART_W - CHART_Y_AXIS_OFFSET) / CHART_X_TICKS;
|
||||||
for (int i = 0; i < CHART_X_TICKS + 1; i++)
|
for (int i = 0; i < CHART_X_TICKS + 1; i++)
|
||||||
{
|
{
|
||||||
uint16_t x_tick_step = (CHART_TIME_MAX / CHART_Y_TICKS * i);
|
uint16_t x_tick_step = (CHART_TIME_MAX / CHART_X_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);
|
chartXaxis_spr.drawLine(tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 0, tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 8, CHART_LINE_COLOR);
|
||||||
chartbg_spr.setTextDatum(TR_DATUM);
|
chartXaxis_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);
|
chartXaxis_spr.drawString(String(x_tick_step), tickIndex * i + CHART_Y_AXIS_OFFSET - 1, 3, CHART_FONT);
|
||||||
}
|
}
|
||||||
|
chartXaxis_spr.pushSprite(CHART_X, CHART_Y + CHART_H - CHART_X_AXIS_OFFSET);
|
||||||
chartbg_spr.pushSprite(CHART_X, CHART_Y);
|
chartYaxis_spr.pushSprite(CHART_X, CHART_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prep_sprite(void)
|
void prepStatus(void)
|
||||||
{
|
{
|
||||||
looptime_spr.createSprite(20, tft.fontHeight(1) + 1);
|
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;
|
const uint32_t button_width = tft.width() / BUTTONS_N;
|
||||||
|
|
||||||
@@ -114,35 +250,44 @@ void touch_calibrate()
|
|||||||
|
|
||||||
void updateGUIButtons(void)
|
void updateGUIButtons(void)
|
||||||
{
|
{
|
||||||
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
|
uint32_t timeNow = millis();
|
||||||
bool pressed = tft.getTouch(&t_x, &t_y);
|
if (timeNow - lastButtonTime > BUTTON_INTERVAL)
|
||||||
|
|
||||||
for (uint8_t b = 0; b < BUTTONS_N; b++)
|
|
||||||
{
|
{
|
||||||
if (pressed && key[b].contains(t_x, t_y))
|
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
|
||||||
{
|
bool pressed = tft.getTouch(&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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any key has changed state
|
for (uint8_t b = 0; b < BUTTONS_N; b++)
|
||||||
for (uint8_t b = 0; b < BUTTONS_N; b++)
|
|
||||||
{
|
|
||||||
// If button was just pressed, redraw inverted button
|
|
||||||
if (key[b].justPressed())
|
|
||||||
{
|
{
|
||||||
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
|
// Check if any key has changed state
|
||||||
if (key[b].justReleased())
|
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);
|
tft.invertDisplay(false);
|
||||||
//touch_calibrate();
|
//touch_calibrate();
|
||||||
tft.setTouch(calData);
|
tft.setTouch(calData);
|
||||||
prep_sprite();
|
|
||||||
prep_buttons();
|
prepStatus();
|
||||||
prep_chart();
|
prepButtons();
|
||||||
|
prepChart();
|
||||||
|
prepReflowstate();
|
||||||
|
prepTargetChart();
|
||||||
|
prepOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Main loop
|
// Main loop
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
uint32_t lastLCDupdate = 0;
|
||||||
|
|
||||||
void handleLCD()
|
void handleLCD()
|
||||||
{
|
{
|
||||||
looptime_spr.fillSprite(TFT_BLACK);
|
updateStatus();
|
||||||
looptime_spr.setTextDatum(MC_DATUM);
|
|
||||||
looptime_spr.drawNumber(getLooptime(), looptime_spr.width() / 2, looptime_spr.height() / 2, 1);
|
uint32_t timeNow = millis();
|
||||||
looptime_spr.pushSprite(1, 1);
|
if (timeNow - lastLCDupdate > LCD_INTERVAL)
|
||||||
updateGUIButtons();
|
{
|
||||||
//tft.drawString(showValue("Temp", getTemperature(), "grC"), 10, 10);
|
updateGUIButtons();
|
||||||
|
updateReflowState();
|
||||||
|
updateTargetChart();
|
||||||
|
updateOutput();
|
||||||
|
lastLCDupdate = timeNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loopScreen(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
@@ -3,32 +3,77 @@
|
|||||||
|
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
|
|
||||||
// #define WIDTH 240
|
#define TFT_WIDTH 240
|
||||||
// #define HEIGHT 60
|
#define TFT_HEIGT 320
|
||||||
#define BUTTON_H 60
|
#define TFT_DEFAULT_R 4
|
||||||
#define BUTTON_W 240
|
|
||||||
#define BUTTONS_N 3
|
#define LCD_INTERVAL 100
|
||||||
#define BUTTON_PADDING 2
|
|
||||||
#define BUTTON_RADIUS 8
|
#define BUTTON_H 60
|
||||||
#define BUTTON_COLOR TFT_BLUE
|
#define BUTTON_W TFT_WIDTH
|
||||||
#define KEY_TEXTSIZE 1 // Font size multiplier
|
#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_X 0
|
||||||
#define CHART_Y 30
|
#define CHART_Y 40
|
||||||
#define CHART_W 240
|
|
||||||
#define CHART_H 200
|
|
||||||
#define CHART_FONT 1
|
|
||||||
#define CHART_Y_AXIS_OFFSET 24
|
#define CHART_Y_AXIS_OFFSET 24
|
||||||
#define CHART_X_AXIS_OFFSET 10
|
#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_MIN 20 //offset in degrees
|
||||||
#define CHART_TEMP_MAX 360 //degrees
|
#define CHART_TEMP_MAX 240 //degrees
|
||||||
#define CHART_Y_TICKS 10
|
#define CHART_Y_TICKS 11
|
||||||
#define CHART_X_TICKS 10
|
#define CHART_X_TICKS 7
|
||||||
#define CHART_LINE_COLOR TFT_WHITE
|
#define CHART_LINE_COLOR TFT_WHITE
|
||||||
#define CHART_TEXT_COLOR TFT_RED
|
#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 initLCD(void);
|
||||||
void handleLCD(void);
|
void handleLCD(void);
|
||||||
|
|
||||||
|
void loopScreen(void);
|
||||||
|
|||||||
@@ -6,26 +6,26 @@
|
|||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "heater.h"
|
#include "heater.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
|
#include "controlloop.h"
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
// put your setup code here, to run once:
|
|
||||||
initStatus();
|
initStatus();
|
||||||
initLCD();
|
initLCD();
|
||||||
initThermo();
|
initThermo();
|
||||||
initButton();
|
initButton();
|
||||||
initHeater();
|
initHeater();
|
||||||
|
initControlLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// put your main code here, to run repeatedly:
|
|
||||||
handleLCD();
|
handleLCD();
|
||||||
handleThermo();
|
handleThermo();
|
||||||
handleButton();
|
handleButton();
|
||||||
handleHeater();
|
handleHeater();
|
||||||
handleStatus();
|
handleStatus();
|
||||||
|
handleControlLoop();
|
||||||
}
|
}
|
||||||
@@ -6,14 +6,12 @@ uint32_t thermo_lastTime = 0;
|
|||||||
|
|
||||||
double lastTemperature = 0;
|
double lastTemperature = 0;
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
|
||||||
void initThermo()
|
void initThermo()
|
||||||
{
|
{
|
||||||
Thermocouple *originThermocouple = new MAX6675_Thermocouple(THERM_CL, THERM_CS, THERM_SO);
|
Thermocouple *originThermocouple = new MAX6675_Thermocouple(THERM_CL, THERM_CS, THERM_SO);
|
||||||
thermocouple = new SmoothThermocouple(originThermocouple, SMOOTHING_FACTOR);
|
thermocouple = new SmoothThermocouple(originThermocouple, SMOOTHING_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the loop function runs over and over again forever
|
|
||||||
void handleThermo(void)
|
void handleThermo(void)
|
||||||
{
|
{
|
||||||
// Reads temperature
|
// Reads temperature
|
||||||
@@ -21,13 +19,32 @@ void handleThermo(void)
|
|||||||
if (timeNow - thermo_lastTime > THERMO_INTERVAL)
|
if (timeNow - thermo_lastTime > THERMO_INTERVAL)
|
||||||
{
|
{
|
||||||
lastTemperature = thermocouple->readCelsius();
|
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)
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
#include <SmoothThermocouple.h>
|
#include <SmoothThermocouple.h>
|
||||||
|
|
||||||
#define THERMO_INTERVAL 200
|
#define THERMO_INTERVAL 200
|
||||||
#define SMOOTHING_FACTOR 5
|
#define SMOOTHING_FACTOR 2
|
||||||
|
|
||||||
void initThermo(void);
|
void initThermo(void);
|
||||||
void handleThermo(void);
|
void handleThermo(void);
|
||||||
double getTemperature(void);
|
double getTemperature(void);
|
||||||
|
bool getThermoCoupleFault(void);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user