mirror of
https://github.com/arwidcool/Solder-Plate.git
synced 2025-02-17 19:09:23 +01:00
Merge branch 'master' menu and working stuff.
This commit is contained in:
commit
5ce4ba6d5c
54
src/PID/PidController.cpp
Normal file
54
src/PID/PidController.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "PidController.h"
|
||||
#include "globals.h"
|
||||
#define MOSTFET_PIN 17
|
||||
|
||||
PidController::PidController(PidControllerData *data)
|
||||
{
|
||||
|
||||
this->data = data;
|
||||
kp = 5;
|
||||
kd = 10;
|
||||
ki = 1;
|
||||
|
||||
controller.begin(&(this->data->currentTemp), &(this->data->setPoint), &(this->data->targetTemp), kp, ki, kd);
|
||||
controller.reverse();
|
||||
controller.setOutputLimits(0, 255);
|
||||
controller.setSampleTime(20);
|
||||
controller.setWindUpLimits(-100, 185);
|
||||
}
|
||||
|
||||
double *PidController::compute()
|
||||
{
|
||||
|
||||
controller.compute();
|
||||
|
||||
return controller.output;
|
||||
}
|
||||
|
||||
void PidController::debug()
|
||||
{
|
||||
|
||||
controller.debug(&Serial, " ", PRINT_INPUT | // Can include or comment out any of these terms to print
|
||||
PRINT_OUTPUT | // in the Serial plotter
|
||||
PRINT_SETPOINT | PRINT_BIAS | PRINT_P | PRINT_I | PRINT_D);
|
||||
}
|
||||
|
||||
void PidController::loop() {
|
||||
pidControllerData.targetTemp = chosenReflowProfile.getTargetTemp();
|
||||
pidControllerData.currentTemp = thermistor1.getTemperature();
|
||||
compute();
|
||||
analogWrite(MOSTFET_PIN, data->setPoint);
|
||||
}
|
||||
|
||||
void PidController::stop()
|
||||
{
|
||||
// STOP
|
||||
digitalWrite(MOSTFET_PIN, LOW);
|
||||
controller.stop();
|
||||
controller.reset();
|
||||
}
|
||||
|
||||
void PidController::start()
|
||||
{
|
||||
controller.start();
|
||||
}
|
38
src/PID/PidController.h
Normal file
38
src/PID/PidController.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef PIDCONTROLLER_H
|
||||
#define PIDCONTROLLER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduPID.h>
|
||||
|
||||
|
||||
struct PidControllerData { double currentTemp; double setPoint; double targetTemp;};
|
||||
|
||||
class PidController
|
||||
{
|
||||
public:
|
||||
|
||||
PidController(PidControllerData* data);
|
||||
void setSetpoint(double setpoint);
|
||||
void setInput(double input);
|
||||
double* compute();
|
||||
void debug();
|
||||
void stop();
|
||||
void loop();
|
||||
void start();
|
||||
|
||||
boolean started = false;
|
||||
|
||||
private:
|
||||
ArduPID controller;
|
||||
double kp;
|
||||
double ki;
|
||||
double kd;
|
||||
PidControllerData *data;
|
||||
double integral;
|
||||
double previousError;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PIDCONTROLLER_H
|
@ -21,7 +21,7 @@ Pair<ButtonKind, StateChangeEvent<ButtonState>>* Buttons::handleButtons()
|
||||
{
|
||||
StateChangeEvent<ButtonState> *change = __buttons[i]->lastChange();
|
||||
|
||||
Serial.println(String("ButtonStateChange: kind=") + KIND_STR(__buttons[i]->kind) + ", " + STATECHANGE_STR((*change)));
|
||||
Serial.println(String("ButtonStateChange: kind=") + BTNKIND_STR(__buttons[i]->kind) + ", " + BTNSTATECHANGE_STR((*change)));
|
||||
return new Pair<ButtonKind, StateChangeEvent<ButtonState>>(__buttons[i]->kind, *change);
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ enum ButtonKind
|
||||
NONE
|
||||
};
|
||||
|
||||
#define KIND_STR(kind) (kind == ButtonKind::UP ? "UP" : kind == ButtonKind::DOWN ? "DOWN" \
|
||||
#define BTNKIND_STR(kind) (kind == ButtonKind::UP ? "UP" : kind == ButtonKind::DOWN ? "DOWN" \
|
||||
: kind == ButtonKind::BACK ? "BACK" \
|
||||
: kind == ButtonKind::SELECT ? "SELECT" \
|
||||
: "NONE")
|
||||
#define STATE_STR(state) (state == ButtonState::IDLE ? "IDLE" : state == ButtonState::PRESSED ? "PRESSED" \
|
||||
#define BTNSTATE_STR(state) (state == ButtonState::IDLE ? "IDLE" : state == ButtonState::PRESSED ? "PRESSED" \
|
||||
: "RELEASED")
|
||||
#define STATECHANGE_STR(change) (String(STATE_STR(change.from)) + " -> " + STATE_STR(change.to))
|
||||
#define BTNSTATECHANGE_STR(change) (String(BTNSTATE_STR(change.from)) + " -> " + BTNSTATE_STR(change.to))
|
||||
|
||||
#endif
|
@ -7,6 +7,8 @@
|
||||
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
||||
#define MENUID_DEBUG 2
|
||||
#define MENUITEM_THERMISTOR_START 150
|
||||
#define MENUID_PICK_PROFILE 100
|
||||
#define MENUITEM_PROFILE_START 100
|
||||
|
||||
unsigned long lastProcessedReflowState = 0;
|
||||
OledDisplay::OledDisplay()
|
||||
@ -24,10 +26,28 @@ void OledDisplay::handleButtonStateChange(Pair<ButtonKind, StateChangeEvent<Butt
|
||||
{
|
||||
if (change.first == ButtonKind::SELECT)
|
||||
{
|
||||
OledMenu *selectedMenu = curMenu->getNextMenu();
|
||||
if (selectedMenu != NULL)
|
||||
if (curMenu->identifier == MENUID_PICK_PROFILE)
|
||||
{
|
||||
curMenu = selectedMenu;
|
||||
int profileIndex = curMenu->getCurItem().identifier - MENUITEM_PROFILE_START;
|
||||
if (profileIndex >= 0 && profileIndex < nReflowProfiles)
|
||||
{
|
||||
chosenReflowProfile = reflowProfiles[profileIndex];
|
||||
reflowProcessState.set(PREHEAT);
|
||||
Serial.println("Chosen profile: " + String(chosenReflowProfile.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Invalid profile index: " + String(profileIndex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
OledMenu *selectedMenu = curMenu->getNextMenu();
|
||||
if (selectedMenu != NULL)
|
||||
{
|
||||
curMenu = selectedMenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (change.first == ButtonKind::BACK)
|
||||
@ -96,11 +116,11 @@ void OledDisplay::setup()
|
||||
},
|
||||
3);
|
||||
|
||||
OledMenu *pickProfilesMenu = new OledMenu(1);
|
||||
OledMenu *pickProfilesMenu = new OledMenu(MENUID_PICK_PROFILE);
|
||||
OledMenuItem *pickProfilesMenuItems = new OledMenuItem[nReflowProfiles];
|
||||
for (int i = 0; i < nReflowProfiles; i++)
|
||||
{
|
||||
pickProfilesMenuItems[i] = OledMenuItem(reflowProfiles[i].name, 100 + 1);
|
||||
pickProfilesMenuItems[i] = OledMenuItem(reflowProfiles[i].name, MENUITEM_PROFILE_START + i);
|
||||
}
|
||||
pickProfilesMenu->setElements(pickProfilesMenuItems, nReflowProfiles);
|
||||
|
||||
@ -156,7 +176,7 @@ void OledDisplay::loop()
|
||||
{
|
||||
handleUserInputState();
|
||||
}
|
||||
else if (state >= REFLOW && state <= DONE)
|
||||
else if (state >= PREHEAT && state <= DONE)
|
||||
{
|
||||
handleReflowState();
|
||||
}
|
||||
@ -193,12 +213,23 @@ void OledDisplay::displayIndicators()
|
||||
display.setCursor(SCREEN_HEIGHT - 14, SCREEN_WIDTH / 2 - 5);
|
||||
display.print(">");
|
||||
}
|
||||
void OledDisplay::centerText(const char *txt)
|
||||
void OledDisplay::centerText(const char *txt, DisplayTextAlignment horizontal, DisplayTextAlignment vertical)
|
||||
{
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
display.getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
display.setCursor(display.width() / 2 - w / 2, display.height() / 2 - h / 2);
|
||||
int cursorX = (horizontal == DisplayTextAlignment::CENTER ? display.width() / 2 - w / 2 : 0);
|
||||
if (horizontal == DisplayTextAlignment::END)
|
||||
{
|
||||
cursorX = display.width() - w;
|
||||
}
|
||||
int cursorY = (vertical == DisplayTextAlignment::CENTER ? display.height() / 2 - h / 2 : 0);
|
||||
if (vertical == DisplayTextAlignment::END)
|
||||
{
|
||||
cursorY = display.height() - h;
|
||||
}
|
||||
|
||||
display.setCursor(cursorX, cursorY);
|
||||
|
||||
display.println(txt);
|
||||
}
|
||||
@ -231,8 +262,21 @@ void OledDisplay::handleUserInputState()
|
||||
void OledDisplay::handleReflowState()
|
||||
{
|
||||
display.clearDisplay();
|
||||
display.setRotation(0);
|
||||
display.setCursor(0, 0);
|
||||
display.setTextSize(2);
|
||||
ReflowProcessState state = reflowProcessState.get();
|
||||
centerText(STATE_STR(state));
|
||||
centerText(STATE_STR(state), DisplayTextAlignment::CENTER, DisplayTextAlignment::START);
|
||||
|
||||
|
||||
display.setTextSize(1, 2);
|
||||
uint32_t elapsedStep = chosenReflowProfile.getCurrentStepRelativeTime();
|
||||
centerText("Remaining", DisplayTextAlignment::START, DisplayTextAlignment::CENTER);
|
||||
centerText((String(chosenReflowProfile.curReflowStep().duration - elapsedStep) + "s").c_str(), DisplayTextAlignment::START, DisplayTextAlignment::END);
|
||||
|
||||
uint8_t curTemp = thermistor1.getTemperature();
|
||||
uint8_t targetTemp = pidControllerData.targetTemp;
|
||||
centerText(("Curr.: " + String(curTemp)).c_str(), DisplayTextAlignment::END, DisplayTextAlignment::CENTER);
|
||||
centerText(("Target: " + String(targetTemp)).c_str(), DisplayTextAlignment::END, DisplayTextAlignment::END);
|
||||
display.display();
|
||||
}
|
||||
|
@ -3,7 +3,11 @@
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include "../reflow.h"
|
||||
#include "menustatemachine.h"
|
||||
|
||||
enum DisplayTextAlignment {
|
||||
START,
|
||||
CENTER,
|
||||
END
|
||||
};
|
||||
class OledDisplay {
|
||||
public:
|
||||
OledDisplay();
|
||||
@ -18,12 +22,12 @@ class OledDisplay {
|
||||
void drawDebug();
|
||||
void handleUserInputState();
|
||||
void handleReflowState();
|
||||
|
||||
void centerText(const char * text);
|
||||
void centerText(const char * text) {
|
||||
centerText(text, DisplayTextAlignment::CENTER, DisplayTextAlignment::CENTER);
|
||||
}
|
||||
void centerText(const char * text, DisplayTextAlignment horizontal, DisplayTextAlignment vertical);
|
||||
void displayIndicators();
|
||||
void handleDrawThermistorMenu(OledMenuItem item);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -14,23 +14,23 @@ Thermistor thermistor6(THERMISTOR6_PIN, 9000);
|
||||
Thermistor thermistors[6] = {thermistor1, thermistor2, thermistor3, thermistor4, thermistor5, thermistor6};
|
||||
|
||||
ReflowProfile reflowProfiles[] = {
|
||||
ReflowProfile(new ReflowStep[5] {
|
||||
ReflowStep(ReflowProcessState::PREHEAT, 2, 150),
|
||||
ReflowStep(ReflowProcessState::SOAK, 3, 180),
|
||||
ReflowStep(ReflowProcessState::REFLOW, 3, 220, EASE_IN_OUT),
|
||||
ReflowStep(ReflowProcessState::COOL, 3, 100),
|
||||
ReflowStep(ReflowProcessState::DONE, 0, 0)
|
||||
}, "Test\0"),
|
||||
ReflowProfile(new ReflowStep[5] {
|
||||
ReflowStep(ReflowProcessState::PREHEAT, 2, 150),
|
||||
ReflowStep(ReflowProcessState::SOAK, 3, 180),
|
||||
ReflowStep(ReflowProcessState::REFLOW, 3, 220, EASE_IN_OUT),
|
||||
ReflowStep(ReflowProcessState::COOL, 3, 100),
|
||||
ReflowStep(ReflowProcessState::DONE, 0, 0)
|
||||
}, "Test2\0"),
|
||||
//138c profile Sn42Bi58
|
||||
ReflowProfile(new ReflowStep[5]{
|
||||
ReflowStep(ReflowProcessState::PREHEAT, 60, 100, EASE_OUT),
|
||||
ReflowStep(ReflowProcessState::SOAK, 90, 155),
|
||||
ReflowStep(ReflowProcessState::REFLOW, 45, 185, EASE_OUT),
|
||||
ReflowStep(ReflowProcessState::COOL, 45, 155, EASE_OUT),
|
||||
ReflowStep(ReflowProcessState::DONE, 0, 0)},
|
||||
"138c Sn42Bi58\0"),
|
||||
ReflowProfile(new ReflowStep[5]{ReflowStep(ReflowProcessState::PREHEAT, 2, 150), ReflowStep(ReflowProcessState::SOAK, 3, 180), ReflowStep(ReflowProcessState::REFLOW, 3, 220, EASE_IN_OUT), ReflowStep(ReflowProcessState::COOL, 3, 100), ReflowStep(ReflowProcessState::DONE, 0, 0)}, "Test2\0"),
|
||||
};
|
||||
|
||||
ReflowProfile chosenReflowProfile = reflowProfiles[0];
|
||||
|
||||
int nReflowProfiles = 2;
|
||||
|
||||
uint16_t plateResistanceOhm = 0;
|
||||
EEPROMDataManager eepromDataManager = EEPROMDataManager();
|
||||
|
||||
PidControllerData pidControllerData = {0 /*currentTemp*/, 60 /*TargetTemp*/, 255 /*PWM*/};
|
||||
PidController pidController = PidController(&pidControllerData);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "./thermistors/Thermistor.h"
|
||||
#include "./reflow.h"
|
||||
#include "./EEPROMDataManager.h"
|
||||
#include "./PID/PidController.h"
|
||||
|
||||
extern WrappedState<ReflowProcessState> reflowProcessState;
|
||||
extern AnalogRef analogRef;
|
||||
@ -15,11 +16,12 @@ extern Thermistor thermistor5;
|
||||
extern Thermistor thermistor6;
|
||||
extern Thermistor thermistors[6];
|
||||
extern ReflowProfile reflowProfiles[];
|
||||
extern ReflowProfile chosenReflowProfile;
|
||||
extern uint16_t plateResistanceOhm;
|
||||
// EEPROM data manager is in its own file
|
||||
extern int nReflowProfiles;
|
||||
|
||||
|
||||
extern PidControllerData pidControllerData;
|
||||
extern PidController pidController;
|
||||
extern EEPROMDataManager eepromDataManager;
|
||||
|
||||
#endif
|
83
src/main.cpp
83
src/main.cpp
@ -9,7 +9,8 @@
|
||||
#include "leds/leds.h"
|
||||
#include "reflow.h"
|
||||
#include "displays/oled.h"
|
||||
#include "globals.h"
|
||||
#include "PID/PidController.h"
|
||||
#include "globals.h"
|
||||
#include "EEPROMDataManager.h"
|
||||
|
||||
// LCD display pins
|
||||
@ -21,6 +22,11 @@
|
||||
// Create an instance of the Adafruit ST7789 class using the custom SPI pins
|
||||
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST);
|
||||
|
||||
#define MOSTFET_PIN 17
|
||||
|
||||
double currentTemp = 0;
|
||||
double targetTemp = 60;
|
||||
double pwmValue = 255;
|
||||
|
||||
Buttons buttons = Buttons();
|
||||
LEDS leds = LEDS();
|
||||
@ -29,9 +35,13 @@ ArduPID PID;
|
||||
OledDisplay oled = OledDisplay();
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
pinMode(MOSTFET_PIN, OUTPUT);
|
||||
analogWrite(MOSTFET_PIN, 255); // VERY IMPORTANT, DONT CHANGE!
|
||||
|
||||
Serial.begin(38400);
|
||||
|
||||
Serial.println("Starting OLED");
|
||||
@ -41,43 +51,66 @@ void setup()
|
||||
leds.setup();
|
||||
oled.setup();
|
||||
eepromDataManager.setup();
|
||||
|
||||
reflowProcessState = USER_INPUT;
|
||||
|
||||
}
|
||||
|
||||
reflowProcessState.set(USER_INPUT);
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
|
||||
// Return the button that changed state
|
||||
Pair<ButtonKind, StateChangeEvent<ButtonState>> *k = buttons.handleButtons();
|
||||
|
||||
if (k != NULL) {
|
||||
ReflowProcessState state = reflowProcessState.get();
|
||||
if (k != NULL)
|
||||
{
|
||||
leds.handleButtonStateChange(*k);
|
||||
oled.handleButtonStateChange(*k);
|
||||
|
||||
// if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::SELECT, ButtonState::PRESSED)) {
|
||||
// reflowProcessState.set(ReflowProcessState::PREHEAT);
|
||||
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::BACK, ButtonState::PRESSED)) {
|
||||
// reflowProcessState.set(ReflowProcessState::USER_INPUT);
|
||||
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::UP, ButtonState::PRESSED)) {
|
||||
// reflowProcessState.set(ReflowProcessState::COOL);
|
||||
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::DOWN, ButtonState::PRESSED)) {
|
||||
// reflowProcessState.set(ReflowProcessState::REFLOW);
|
||||
// }
|
||||
if (state == USER_INPUT)
|
||||
{
|
||||
oled.handleButtonStateChange(*k);
|
||||
}
|
||||
else if (state >= PREHEAT && state <= COOL)
|
||||
{
|
||||
if (k->first == ButtonKind::BACK && k->second.to == ButtonState::PRESSED)
|
||||
{
|
||||
// STOP REFLOW and restart
|
||||
reflowProcessState.set(USER_INPUT);
|
||||
pidControllerData.targetTemp = 0; // should not be needed but why not?
|
||||
pidController.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
ReflowProcessState newState = reflowProcessState.get();
|
||||
if (newState != state) {
|
||||
Serial.println("State changed from " + String(STATE_STR(state)) + " to " + String(STATE_STR(newState)));
|
||||
// State changed from state to newState (user input or wifi input needs to be above here)
|
||||
if (newState == PREHEAT) {
|
||||
chosenReflowProfile.start();
|
||||
pidController.start();
|
||||
}
|
||||
}
|
||||
|
||||
// ReflowStep step = profile.curReflowStep();
|
||||
// if (step.state != reflowProcessState.get()) {
|
||||
// reflowProcessState.set(step.state);
|
||||
// }
|
||||
oled.loop();
|
||||
|
||||
if (state >= PREHEAT && state <= COOL)
|
||||
{
|
||||
pidController.loop();
|
||||
ReflowStep step = chosenReflowProfile.curReflowStep();
|
||||
|
||||
if (step.state != newState)
|
||||
{
|
||||
reflowProcessState.set(step.state);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == DONE)
|
||||
{
|
||||
// TODO: BUZZER
|
||||
reflowProcessState.set(USER_INPUT);
|
||||
}
|
||||
|
||||
|
||||
oled.loop();
|
||||
// if (step.state == ReflowProcessState::DONE) {
|
||||
// profile.start();
|
||||
// return;
|
||||
// }
|
||||
// Serial.print(String(STATE_STR(step.state)) + " " + String(step.duration) + " " + String(step.targetTempAtEnd) + " " + String(profile.getTargetTemp())+"\r");
|
||||
|
||||
}
|
||||
|
||||
|
260
src/reflow.h
260
src/reflow.h
@ -3,7 +3,10 @@
|
||||
#include "./common.h"
|
||||
#include <EEPROM.h>
|
||||
#include "StopWatch.h"
|
||||
#include "thermistors/Thermistor.h"
|
||||
#include "displays/oled.h"
|
||||
|
||||
extern Thermistor thermistor1;
|
||||
|
||||
// STATE MACHINE
|
||||
enum ReflowProcessState
|
||||
@ -18,13 +21,13 @@ enum ReflowProcessState
|
||||
};
|
||||
|
||||
#define STATE_STR(state) (state == INITIALIZING ? "INITIALIZING" \
|
||||
: state == USER_INPUT ? "USER_INPUT" \
|
||||
: state == PREHEAT ? "PREHEAT" \
|
||||
: state == SOAK ? "SOAK" \
|
||||
: state == REFLOW ? "REFLOW" \
|
||||
: state == COOL ? "COOL" \
|
||||
: state == DONE ? "DONE" \
|
||||
: "UNKNOWN")
|
||||
: state == USER_INPUT ? "USER_INPUT" \
|
||||
: state == PREHEAT ? "PREHEAT" \
|
||||
: state == SOAK ? "SOAK" \
|
||||
: state == REFLOW ? "REFLOW" \
|
||||
: state == COOL ? "COOL" \
|
||||
: state == DONE ? "DONE" \
|
||||
: "UNKNOWN")
|
||||
|
||||
enum ReflowStepEaseFunction
|
||||
{
|
||||
@ -55,10 +58,14 @@ public:
|
||||
{
|
||||
case LINEAR:
|
||||
return startTemp + (this->targetTempAtEnd - startTemp) * percentage;
|
||||
|
||||
case EASE_IN_OUT:
|
||||
return startTemp + (this->targetTempAtEnd - startTemp) * -(cos(percentage * PI) - 1) / (double)2;
|
||||
|
||||
Serial.println(this->targetTempAtEnd);
|
||||
case EASE_IN:
|
||||
return startTemp + (this->targetTempAtEnd - startTemp) * (1 - cos(percentage * PI / (double)2));
|
||||
|
||||
case EASE_OUT:
|
||||
return startTemp + (this->targetTempAtEnd - startTemp) * (sin(percentage * PI / (double)2));
|
||||
}
|
||||
@ -67,13 +74,31 @@ public:
|
||||
|
||||
#define PROFILE_SERIALIZED_SIZE 40
|
||||
#define PROFILE_SERIALIZED_NAME_SIZE 20
|
||||
|
||||
class ReflowProfile
|
||||
{
|
||||
public:
|
||||
uint8_t preheatEndTime;
|
||||
uint8_t soakEndTime;
|
||||
uint8_t reflowEndTime;
|
||||
uint8_t coolEndTime;
|
||||
int totalDuration;
|
||||
|
||||
float targetTempReflow;
|
||||
|
||||
float percentage;
|
||||
|
||||
ReflowProfile(ReflowStep steps[5], char name[20])
|
||||
{
|
||||
memcpy(this->steps, steps, 5 * sizeof(steps[0]));
|
||||
memcpy(this->name, name, PROFILE_SERIALIZED_NAME_SIZE);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
this->steps[i] = steps[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
this->name[i] = name[i];
|
||||
}
|
||||
}
|
||||
ReflowStep steps[5];
|
||||
char name[20];
|
||||
@ -81,54 +106,207 @@ public:
|
||||
|
||||
void start()
|
||||
{
|
||||
timer = StopWatch(StopWatch::Resolution::MILLIS);
|
||||
timer = StopWatch(StopWatch::Resolution::SECONDS);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the current reflow step based on the elapsed time
|
||||
*/
|
||||
ReflowStep curReflowStep() {
|
||||
int8_t reflowStep = curReflowStepIndexAt(timer.elapsed());
|
||||
if (reflowStep == -1) {
|
||||
return steps[4]; // DONE
|
||||
}
|
||||
return steps[reflowStep];
|
||||
calculateEndTimes();
|
||||
}
|
||||
|
||||
|
||||
int8_t curReflowStepIndexAt(uint32_t elapsed) {
|
||||
for (int i = 0; i < 5; i++)
|
||||
void calculateEndTimes()
|
||||
{
|
||||
|
||||
preheatEndTime = steps[0].duration;
|
||||
int soakEnd = steps[1].duration;
|
||||
soakEndTime = preheatEndTime + soakEnd;
|
||||
reflowEndTime = soakEndTime + steps[2].duration;
|
||||
coolEndTime = reflowEndTime + steps[3].duration;
|
||||
|
||||
// reflowEndTime = soakEndTime + (steps[2].duration*1000);
|
||||
// coolEndTime = reflowEndTime + (steps[3].duration*1000);
|
||||
|
||||
Serial.print("preheatEndTime: ");
|
||||
Serial.println(preheatEndTime);
|
||||
Serial.print("soakEndTime: ");
|
||||
Serial.println(soakEndTime);
|
||||
Serial.print("reflowEndTime: ");
|
||||
Serial.println(reflowEndTime);
|
||||
Serial.print("coolEndTime: ");
|
||||
Serial.println(coolEndTime);
|
||||
|
||||
totalDuration = coolEndTime + steps[4].duration;
|
||||
|
||||
Serial.print("totalDuration: ");
|
||||
Serial.println(totalDuration);
|
||||
}
|
||||
|
||||
ReflowStep curReflowStep()
|
||||
{
|
||||
uint8_t elapsed = timer.elapsed();
|
||||
|
||||
if (elapsed <= preheatEndTime)
|
||||
{
|
||||
if (elapsed < steps[i].duration * 1000)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
elapsed -= steps[i].duration * 1000;
|
||||
}
|
||||
return steps[0];
|
||||
}
|
||||
else if (elapsed < soakEndTime)
|
||||
{
|
||||
return steps[1];
|
||||
}
|
||||
else if (elapsed < reflowEndTime)
|
||||
{
|
||||
return steps[2];
|
||||
}
|
||||
else if (elapsed < coolEndTime)
|
||||
{
|
||||
return steps[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
return steps[4];
|
||||
timer.stop();
|
||||
timer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
ReflowStep getPreviousSetep(ReflowStep step)
|
||||
{
|
||||
if (step.state == PREHEAT)
|
||||
{
|
||||
return steps[0];
|
||||
}
|
||||
else if (step.state == SOAK)
|
||||
{
|
||||
return steps[1];
|
||||
}
|
||||
else if (step.state == REFLOW)
|
||||
{
|
||||
return steps[2];
|
||||
}
|
||||
else if (step.state == COOL)
|
||||
{
|
||||
return steps[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return steps[4];
|
||||
}
|
||||
return -1; // we are done
|
||||
}
|
||||
|
||||
float getTargetTemp()
|
||||
{
|
||||
uint32_t elapsedTime = timer.elapsed();
|
||||
uint8_t startTemp = 20; // always assume 20 degrees at the start
|
||||
int curStep = curReflowStepIndexAt(elapsedTime);
|
||||
if (curStep == -1) {
|
||||
// uint8_t startTemp=thermistor1.getTemperature();
|
||||
|
||||
ReflowStep curStep = curReflowStep();
|
||||
ReflowStep prevStep = getPreviousSetep(curStep);
|
||||
|
||||
int currenStepIndex = getCurrentStepIndex(curStep);
|
||||
int previousStepIndex = getCurrentStepIndex(prevStep);
|
||||
|
||||
float relativeTIme = calculateCurrentStepRelativeTime(curStep);
|
||||
|
||||
if (currenStepIndex == -1)
|
||||
{
|
||||
timer.reset();
|
||||
timer.stop();
|
||||
return startTemp; // We are done return 20 degrees
|
||||
}
|
||||
uint32_t relativeElapsedTime = elapsedTime;
|
||||
for (int i=0; i<curStep; i++) {
|
||||
relativeElapsedTime -= steps[i].duration * 1000;
|
||||
for (int i = 0; i < currenStepIndex; i++)
|
||||
{
|
||||
relativeElapsedTime -= steps[i].duration;
|
||||
startTemp = steps[i].targetTempAtEnd;
|
||||
}
|
||||
|
||||
// Calculate percentage of current step
|
||||
float percentage = (float)relativeElapsedTime / (float)(steps[curStep].duration * 1000);
|
||||
return steps[curStep].calcTempAtPercentage(startTemp, percentage);
|
||||
// float temp = curStep.calcTempAtPercentage(startTemp, percentage);
|
||||
|
||||
// Serial.print("relativeElapsedTime: ");
|
||||
// Serial.println(relativeElapsedTime);
|
||||
// Serial.print("relativeTIme: ");
|
||||
// Serial.println(relativeTIme);
|
||||
// Serial.print("startTemp: ");
|
||||
// Serial.println(startTemp);
|
||||
|
||||
percentage = (float)relativeElapsedTime / (float)(steps[currenStepIndex].duration);
|
||||
|
||||
targetTempReflow = steps[currenStepIndex].calcTempAtPercentage(startTemp, percentage);
|
||||
|
||||
return targetTempReflow;
|
||||
}
|
||||
|
||||
int getCurrentStepIndex()
|
||||
{
|
||||
uint8_t elapsed = timer.elapsed();
|
||||
|
||||
if (elapsed <= preheatEndTime)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (elapsed < soakEndTime)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (elapsed < reflowEndTime)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (elapsed < coolEndTime)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
int getCurrentStepIndex(ReflowStep step)
|
||||
{
|
||||
if (step.state == PREHEAT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (step.state == SOAK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (step.state == REFLOW)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (step.state == COOL)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getCurrentStepRelativeTime()
|
||||
{
|
||||
return calculateCurrentStepRelativeTime(curReflowStep());
|
||||
};
|
||||
|
||||
uint8_t calculateCurrentStepRelativeTime(ReflowStep step)
|
||||
{
|
||||
|
||||
uint32_t elapsed = timer.elapsed();
|
||||
|
||||
switch (step.state)
|
||||
{
|
||||
case PREHEAT:
|
||||
return elapsed;
|
||||
case SOAK:
|
||||
return elapsed - preheatEndTime;
|
||||
case REFLOW:
|
||||
return elapsed - soakEndTime;
|
||||
case COOL:
|
||||
return elapsed - reflowEndTime;
|
||||
case DONE:
|
||||
return elapsed - coolEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
void toBuffer(uint8_t *b)
|
||||
@ -161,7 +339,7 @@ public:
|
||||
(ReflowProcessState)(i + PREHEAT),
|
||||
b[PROFILE_SERIALIZED_NAME_SIZE + i * 3],
|
||||
b[PROFILE_SERIALIZED_NAME_SIZE + 1 + i * 3],
|
||||
(ReflowStepEaseFunction) b[PROFILE_SERIALIZED_NAME_SIZE + 2 + i * 3]);
|
||||
(ReflowStepEaseFunction)b[PROFILE_SERIALIZED_NAME_SIZE + 2 + i * 3]);
|
||||
}
|
||||
return ReflowProfile(steps, name);
|
||||
}
|
||||
|
BIN
src/reflow.rar
Normal file
BIN
src/reflow.rar
Normal file
Binary file not shown.
BIN
src/reflow2.rar
Normal file
BIN
src/reflow2.rar
Normal file
Binary file not shown.
@ -1,11 +1,11 @@
|
||||
#include "Thermistor.h"
|
||||
|
||||
|
||||
int Thermistor::getTemperature()
|
||||
float Thermistor::getTemperature()
|
||||
{
|
||||
|
||||
// Get an average of 5 readings
|
||||
int temp = 0;
|
||||
float temp = 0;
|
||||
|
||||
uint8_t samples = 5;
|
||||
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
int getTemperature();
|
||||
float getTemperature();
|
||||
float getResistance();
|
||||
void setPotentiometerResistance(uint16_t resistance) { setRes = resistance; };
|
||||
uint16_t getPotentiometerResistance() { return setRes; };
|
||||
|
49
src/tools/ExecutionTimer.h
Normal file
49
src/tools/ExecutionTimer.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef EXECUTIONTIMER_H
|
||||
#define EXECUTIONTIMER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
class ExecutionTimer {
|
||||
private:
|
||||
unsigned long startTime;
|
||||
unsigned long endTime;
|
||||
bool isRunning;
|
||||
|
||||
public:
|
||||
ExecutionTimer() {
|
||||
startTime = 0;
|
||||
endTime = 0;
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
void start() {
|
||||
startTime = millis(); // Use micros() for microsecond precision
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
unsigned long stop() {
|
||||
if (isRunning) {
|
||||
endTime = millis(); // Use micros() for microsecond precision
|
||||
isRunning = false;
|
||||
|
||||
Serial.print("Execution time: ");
|
||||
Serial.print(endTime - startTime);
|
||||
Serial.println(" ms");
|
||||
return endTime - startTime;
|
||||
} else {
|
||||
return 0; // or retain the last execution time
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Function to get the elapsed time without stopping
|
||||
unsigned long elapsed() const {
|
||||
if (isRunning) {
|
||||
return millis() - startTime; // Use micros() for microsecond precision
|
||||
} else {
|
||||
return endTime - startTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXECUTIONTIMER_H
|
Loading…
x
Reference in New Issue
Block a user