Created generic template class for statechange.

This commit is contained in:
Andrea Baccega 2024-01-26 13:49:25 +01:00
parent e76fe26042
commit a7e9adbcf9
12 changed files with 175 additions and 103 deletions

View File

@ -1,52 +1,46 @@
#include "Button.h" #include "Button.h"
#include <Arduino.h> #include <Arduino.h>
// Constructor // Constructor
Button::Button(ButtonKind kind, uint8_t pin) : kind(kind), pin(pin), state(ButtonState::IDLE) { Button::Button(ButtonKind kind, uint8_t pin) : kind(kind), pin(pin), state(WrappedState<ButtonKind, ButtonState>(kind, ButtonState::IDLE))
{
pinMode(pin, INPUT_PULLUP); pinMode(pin, INPUT_PULLUP);
this->change = new ButtonStateChange(this->kind, ButtonState::IDLE, ButtonState::IDLE);
lastStateChangeTime = 0;
} }
ButtonKind Button::getKind() { ButtonKind Button::getKind()
{
return this->kind; return this->kind;
} }
uint8_t Button::getPin() { uint8_t Button::getPin()
{
return this->pin; return this->pin;
} }
ButtonState Button::getState() { StateChangeEvent<ButtonKind, ButtonState> *Button::lastChange()
return this->state; {
return this->state.lastChangeEvent;
} }
ButtonStateChange* Button::lastChange() { bool Button::loop()
return this->change; {
} StateChangeEvent<ButtonKind, ButtonState> *evt = NULL;
void Button::setState(ButtonState state) { if (digitalRead(this->pin) == LOW)
if (this->state != state) { {
delete this->change; // clear memory if (this->state.get() == ButtonState::IDLE && millis() - this->state.lastStateChangeTime > 50)
this->change = new ButtonStateChange(this->kind, this->state, state); {
lastStateChangeTime = millis(); evt = this->state.set(ButtonState::PRESSED);
this->state = state;
}
}
bool Button::loop() {
ButtonState prev = this->state;
if (digitalRead(this->pin) == LOW) {
if (this->state == ButtonState::IDLE && millis() - lastStateChangeTime > 50) {
this->setState(ButtonState::PRESSED);
} }
} else if (this->state == ButtonState::PRESSED) {
this->setState(ButtonState::RELEASED);
} }
if (this->state == ButtonState::RELEASED && millis() - lastStateChangeTime > 50) { else if (this->state.get() == ButtonState::PRESSED)
this->setState(ButtonState::IDLE); {
evt = this->state.set(ButtonState::RELEASED);
}
if (this->state.get() == ButtonState::RELEASED && millis() - this->state.lastStateChangeTime > 50)
{
evt = this->state.set(ButtonState::IDLE);
} }
// Return true if the state changed // Return true if the state changed
return prev != this->state; return evt != NULL;
} }

View File

@ -1,5 +1,6 @@
#include "base.h" #include "base.h"
#include <Arduino.h> #include <Arduino.h>
#include "../statechangeevent.h"
class Button class Button
{ {
@ -9,18 +10,13 @@ public:
ButtonKind getKind(); ButtonKind getKind();
uint8_t getPin(); uint8_t getPin();
ButtonState getState(); StateChangeEvent<ButtonKind, ButtonState> *lastChange();
ButtonStateChange* lastChange();
void setState(ButtonState state);
/// @brief Call this method in the main loop to update the button state. /// @brief Call this method in the main loop to update the button state.
/// @return true if the button state changed, false otherwise. /// @return true if the button state changed, false otherwise.
bool loop(); bool loop();
private : private:
unsigned long lastStateChangeTime; ButtonKind kind;
ButtonKind kind; uint8_t pin;
uint8_t pin; WrappedState<ButtonKind, ButtonState> state;
ButtonState state;
ButtonStateChange* change;
}; };

View File

@ -1,9 +1,7 @@
#include "Buttons.h" #include "Buttons.h"
Button *__buttons[4]; Button *__buttons[4];
void Buttons::setup() void Buttons::setup()
{ {
__buttons[ButtonKind::UP] = new Button(ButtonKind::UP, upButton); __buttons[ButtonKind::UP] = new Button(ButtonKind::UP, upButton);
@ -13,15 +11,16 @@ void Buttons::setup()
} }
/** /**
* Handle buttons state changes and return first button state change that occurred. * Handle buttons state changes and return first button state change that occurred.
*/ */
ButtonStateChange* Buttons::handleButtons() StateChangeEvent<ButtonKind, ButtonState> *Buttons::handleButtons()
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
// If a state change occurred, print it out and return the button that changed // If a state change occurred, print it out and return the button that changed
if ( __buttons[i]->loop()) if (__buttons[i]->loop())
{ {
ButtonStateChange *change = __buttons[i]->lastChange(); StateChangeEvent<ButtonKind, ButtonState> *change = __buttons[i]->lastChange();
Serial.println(STATECHANGE_STR((*change))); Serial.println(STATECHANGE_STR((*change)));
return change; return change;
} }

View File

@ -5,23 +5,21 @@
#include <Arduino.h> #include <Arduino.h>
#include "Button.h" #include "Button.h"
#include "leds/leds.h" #include "leds/leds.h"
#include "../statechangeevent.h"
// Button pins // Button pins
#define upButton 21 #define upButton 21
#define downButton 22 #define downButton 22
#define backButton 23 #define backButton 23
#define selectButton 24 #define selectButton 24
class Buttons class Buttons
{ {
public: public:
// Constructor // Constructor
Buttons() {}; Buttons(){};
ButtonStateChange* handleButtons(); StateChangeEvent<ButtonKind, ButtonState> *handleButtons();
void setup(); void setup();
}; };
#endif // BUTTONS_H #endif // BUTTONS_H

View File

@ -22,13 +22,4 @@ enum ButtonKind
#define STATE_STR(state) (state == ButtonState::IDLE ? "IDLE" : state == ButtonState::PRESSED ? "PRESSED" : "RELEASED") #define STATE_STR(state) (state == ButtonState::IDLE ? "IDLE" : state == ButtonState::PRESSED ? "PRESSED" : "RELEASED")
#define STATECHANGE_STR(change) (String("ButtonStateChange: kind=") + KIND_STR(change.kind) + ", " + STATE_STR(change.from) + " -> " + STATE_STR(change.to)) #define STATECHANGE_STR(change) (String("ButtonStateChange: kind=") + KIND_STR(change.kind) + ", " + STATE_STR(change.from) + " -> " + STATE_STR(change.to))
class ButtonStateChange {
public:
ButtonStateChange(ButtonKind kind, ButtonState from, ButtonState to) : kind(kind), from(from), to(to) {}
ButtonKind kind;
ButtonState from;
ButtonState to;
};
#endif #endif

49
src/displays/oled.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "./oled.h"
#include <Arduino.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
OledDisplay::OledDisplay() {
display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT);
}
void OledDisplay::setup() {
// Setup implementation
bool initialized = display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
if (!initialized) {
Serial.println("OLED Display failed to initialize");
} else {
Serial.println("OLED Display initialized");
}
display.setRotation(0);
}
void OledDisplay::loop() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
if (reflowProcessState == INITIALIZING) {
display.println("INITIALIZING");
} else if (reflowProcessState == USER_INPUT) {
display.println("USER_INPUT");
} else if (reflowProcessState == PREHEAT) {
display.println("PREHEAT");
} else if (reflowProcessState == SOAK) {
display.println("SOAK");
} else if (reflowProcessState == REFLOW) {
display.println("REFLOW");
} else if (reflowProcessState == COOL) {
display.println("COOL");
} else if (reflowProcessState == DONE) {
display.println("DONE");
}
display.println("zz");
display.display();
// Loop implementation
}
void OledDisplay::teardown() {
// delete display;
}

18
src/displays/oled.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __oled_h
#define __oled_h
#include <Adafruit_SSD1306.h>
#include "../reflow.h"
class OledDisplay {
public:
OledDisplay();
void setup();
void loop();
void teardown();
private:
Adafruit_SSD1306 display;
};
#endif

View File

@ -14,7 +14,7 @@ void LEDS::setup()
pinMode(greenLED, OUTPUT); pinMode(greenLED, OUTPUT);
pinMode(redLED, OUTPUT); pinMode(redLED, OUTPUT);
} }
void LEDS::handleButtonStateChange(ButtonStateChange change) void LEDS::handleButtonStateChange(StateChangeEvent<ButtonKind, ButtonState> change)
{ {
switch (change.kind) { switch (change.kind) {
case ButtonKind::UP: case ButtonKind::UP:

View File

@ -1,6 +1,7 @@
#ifndef __leds_h__ #ifndef __leds_h__
#define __leds_h__ #define __leds_h__
#include "../buttons/base.h" #include "../buttons/base.h"
#include "../statechangeevent.h"
//If you didnt solder the LEDS in order, change the order here //If you didnt solder the LEDS in order, change the order here
#define yellowLED 18 #define yellowLED 18
@ -12,7 +13,7 @@ class LEDS
public: public:
LEDS(); LEDS();
void setup(); void setup();
void handleButtonStateChange(ButtonStateChange change); void handleButtonStateChange(StateChangeEvent<ButtonKind, ButtonState> change);
}; };
#endif #endif

View File

@ -3,11 +3,15 @@
#include <Adafruit_ST7789.h> // Include the ST7789 library #include <Adafruit_ST7789.h> // Include the ST7789 library
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <voltageReference/AnalogRef.h> #include <voltageReference/AnalogRef.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h> #include <Wire.h>
#include <thermistors/Thermistor.h> #include <thermistors/Thermistor.h>
#include "buttons/Buttons.h" #include "buttons/Buttons.h"
#include "leds/leds.h" #include "leds/leds.h"
#include "reflow.h"
#include "displays/oled.h"
#include "statechangeevent.h"
ReflowProcessState reflowProcessState = INITIALIZING;
// Define the analog ref used for the system voltage // Define the analog ref used for the system voltage
AnalogRef analogRef(5.0); AnalogRef analogRef(5.0);
@ -24,11 +28,6 @@ TempCalibration calibration_100K_3950 = {25, 100000, 86, 10000, 170, 1000};
// Create an instance of the Adafruit ST7789 class using the custom SPI pins // 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); Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST);
// OLED display width and height, for a typical 128x64 display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Initalize the 3950 100K thermistors with ACTUAL reference resistor measurnment(Measured between Left pin and GND when the board is powered off) using the default calibration data for 100K thermistor // Initalize the 3950 100K thermistors with ACTUAL reference resistor measurnment(Measured between Left pin and GND when the board is powered off) using the default calibration data for 100K thermistor
Thermistor thermistor1(THERMISTOR1_PIN, 2500); Thermistor thermistor1(THERMISTOR1_PIN, 2500);
@ -43,6 +42,7 @@ Buttons buttons = Buttons();
LEDS leds = LEDS(); LEDS leds = LEDS();
// Declare the PID // Declare the PID
ArduPID PID; ArduPID PID;
OledDisplay oled = OledDisplay();
void setup() void setup()
{ {
@ -50,13 +50,11 @@ void setup()
Serial.begin(9600); Serial.begin(9600);
Serial.println("Starting OLED"); Serial.println("Starting OLED");
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setRotation(3);
// Set PWM frequency to 64 kHz // Set PWM frequency to 64 kHz
analogWriteFrequency(64); analogWriteFrequency(64);
buttons.setup(); buttons.setup();
leds.setup(); leds.setup();
oled.setup();
Serial.println("Starting LCD"); Serial.println("Starting LCD");
@ -85,13 +83,14 @@ void setup()
// // // Print text to screen // // // Print text to screen
// tft.print(text); // tft.print(text);
Serial.println("Ready!"); Serial.println("Ready!");
reflowProcessState = USER_INPUT;
} }
void loop() void loop()
{ {
// Return the button that was pressed // Return the button that was pressed
ButtonStateChange* k = buttons.handleButtons(); StateChangeEvent<ButtonKind, ButtonState>* k = buttons.handleButtons();
if (k != NULL) { if (k != NULL) {
leds.handleButtonStateChange(*k); leds.handleButtonStateChange(*k);
@ -100,38 +99,9 @@ void loop()
float sysVoltage = analogRef.calculateSystemVoltage(); float sysVoltage = analogRef.calculateSystemVoltage();
float inputVoltage = analogRef.calculateInputVoltage(); float inputVoltage = analogRef.calculateInputVoltage();
int thermistor1Temp = thermistor1.getTemperature(); int thermistor1Temp = thermistor1.getTemperature();
oled.loop();
// Print the system voltage on the tft // Print the system voltage on the tft
return;
display.clearDisplay();
Serial.print("Thermistor 1: ");
Serial.println(thermistor1Temp);
char *text = "Sys V: ";
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println(text);
display.setCursor(0, 40);
display.println(sysVoltage);
char *text2 = "In V: ";
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 60);
display.println(text2);
display.setCursor(0, 80);
display.println(inputVoltage);
char *text3 = "C:";
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 100);
display.println(text3);
display.setCursor(25, 100);
display.println(thermistor1Temp);
display.display();
// Serial.println("System voltage: ");
// Serial.print("Output voltage: "); // Serial.print("Output voltage: ");
// Serial.println(sysVoltage); // Serial.println(sysVoltage);

19
src/reflow.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __reflow_h__
#define __reflow_h__
// STATE MACHINE
enum ReflowProcessState {
INITIALIZING, // default. This is the state the reflow oven/PCB is in when it is first turned on
USER_INPUT, // The user is selecting a profile to use for the reflow process
PREHEAT, // The oven/PCB is heating up to the preheat temperature
SOAK, // The oven/PCB is heating up to the soak temperature
REFLOW, // The oven/PCB is heating up to the reflow temperature
COOL, // The oven/PCB is cooling down to the cool temperature
DONE // The reflow process is complete
};
// Holds current reflow process state to be used by other classes
// Such as the menu class to display the current state
extern ReflowProcessState reflowProcessState;
#endif

37
src/statechangeevent.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __basestatechange_h__
#define __basestatechange_h__
#include <Arduino.h>
template <typename Kind, typename State>
class StateChangeEvent {
public:
StateChangeEvent(Kind kind, State from, State to) : kind(kind), from(from), to(to) {}
Kind kind;
State from;
State to;
};
template <typename Kind, typename State>
class WrappedState {
public:
WrappedState(Kind kind, State defaultState) : kind(kind), state(defaultState), lastChangeEvent(new StateChangeEvent<Kind, State>(kind, defaultState, defaultState)) {}
Kind kind;
StateChangeEvent<Kind, State> * set(State state) {
if (this->state == state) {
return NULL;
}
delete this->lastChangeEvent;
lastChangeEvent = new StateChangeEvent<Kind, State>(kind, this->state, state);
this->state = state;
this->lastStateChangeTime = millis();
return lastChangeEvent;
}
State get() {
return this->state;
}
State state;
unsigned long lastStateChangeTime = 0;
StateChangeEvent<Kind, State> * lastChangeEvent;
};
#endif