Skip to content

Instantly share code, notes, and snippets.

@SimonMerrett
Created May 22, 2020 11:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SimonMerrett/9b855fcd34bd837698b692378b8d4a5b to your computer and use it in GitHub Desktop.
Save SimonMerrett/9b855fcd34bd837698b692378b8d4a5b to your computer and use it in GitHub Desktop.
putting helper functions into headers
/* Actions library for thermometer
@created: 2020-05-16
@author: Simon Merrett
@version: 0.2
Source code link: #TODO: complete link when published
For changelog see actions.h
*/
#include "actions.h" // associated header file for this cpp file
// #include "numbersIn.h" // actions::alarmLowLimit() and two others need access to e.g. NumberInputSystem::render() and others
//#include "thermDisplay.h" // actions::coolDownState() needs access to member Display::showOnOff(bool)
void Actions::digits()
{
Serial.print(F("DISPLAY Current Temp = "));
disp.printTemperatureDiv10(currentTempx10);
char u = temperature.getUnitSymbol(unit);
Serial.println(u);
if (button1Pressed)
{
menuState = Option::graph;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::graph()
{
Serial.println(F("DISPLAY Graph"));
if (button1Pressed)
{
menuState = (coolDownState) ? Option::countdown : Option::digits;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::countdown()
{
Serial.print(F("DISPLAY Count down remaining = "));
Serial.println(countDownRemaining);
if (button1Pressed)
{
menuState = Option::digits;
}
if (button2Pressed)
{
menuState = Option::units;
}
}
void Actions::units()
{
// show the current setting
Serial.print(F("MENU Units: "));
Serial.println(printout = (static_cast<bool>(unit)) ? "Celsius" : "Farenheit");
if (button2Pressed)
{ //TODO: deal with toggling bool
unit = static_cast<TempUnit>(1 - static_cast<bool>(unit));//!temperatureUnits; // toggle the variable
}
if (button1Pressed)
{
menuState = Option::alarmOnOff;
}
}
void Actions::alarmOnOff()
{
// show the current setting
Serial.print(F("MENU Alarm: "));
disp.showOnOff(alarmState);
if (button2Pressed)
{
alarmState = !alarmState; // toggle the setting
}
if (button1Pressed)
{
menuState = (alarmState) ? Option::alarmLowLimit : Option::coolDownOnOff;
}
}
void Actions::alarmLowLimit()
{
lowerLimitAlarmInput.render();
if (button2Pressed)
lowerLimitAlarmInput.incrementDigit();
if (button1Pressed)
{
auto previous = lowerLimitAlarmInput.getDigit();
lowerLimitAlarmInput.cycleDigit();
auto current = lowerLimitAlarmInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::alarmHighLimit;
}
}
void Actions::alarmHighLimit()
{
higherLimitAlarmInput.render();
if (button2Pressed)
higherLimitAlarmInput.incrementDigit();
if (button1Pressed)
{
auto previous = higherLimitAlarmInput.getDigit();
higherLimitAlarmInput.cycleDigit();
auto current = higherLimitAlarmInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::coolDownOnOff;
}
}
void Actions::coolDownOnOff()
{
Serial.print(F("MENU Cooldown counter: ")); // show the current setting
disp.showOnOff(coolDownState);
if (button2Pressed)
{
coolDownState = !coolDownState; // toggle the setting
}
if (button1Pressed)
{
menuState = (coolDownState) ? Option::coolDownTarget : Option::digits ;
}
}
void Actions::coolDownTarget()
{
coolDownTargetInput.render();
if (button2Pressed)
coolDownTargetInput.incrementDigit();
if (button1Pressed)
{
auto previous = coolDownTargetInput.getDigit();
coolDownTargetInput.cycleDigit();
auto current = coolDownTargetInput.getDigit();
if((previous == Digit::Tenths) && (current == Digit::Tens))
menuState = Option::digits;
}
}
/* Actions library for thermometer
@created: 2020-05-16
@author: Simon Merrett
@version: 0.2
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Source code link: #TODO: complete link when published
Changelog:
- V0.2 works with thermDisplay.h and tempHelper.h to move some functions out of main.cpp
- capitalises class names for consistent C++ style
- V0.1 initial drafting, after moving to platformio
*/
#ifndef ACTIONS_H
#define ACTIONS_H
#include <Arduino.h> // required for uint8_t to be recognised as a type
#include "numbersIn.h" // Actions::alarmLowLimit() and two others need access to e.g. NumberInputSystem::render() and others
#include "tempHelper.h" // Actions::digits() needs access to tempHelper::getUnitsSymbol(bool)
#include "thermDisplay.h" // Actions::digits() needs access to Display::printTemperatureDiv10(uint16_t)
// declare classes initialised elsewhere
class NumberInputSystem; // numbersIn.h
class Display; // thermDisplay.h
class TempHelper; // tempHelper.h
enum class Option : uint8_t
{
digits,
graph,
countdown,
units,
alarmOnOff,
alarmLowLimit,
alarmHighLimit,
coolDownOnOff,
coolDownTarget,
};
extern uint16_t currentTempx10; // dummy number for displaying digits
extern Option menuState;
extern TempUnit unit;
extern bool button1Pressed;
extern bool button2Pressed;
extern bool alarmState; // initialises that the alarm is off
extern bool coolDownState; // initialises to not showing or activating the countdown
extern uint8_t countDownRemaining; // dummy countdown variable
extern uint16_t alarmLowLimit; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
extern uint16_t alarmHighLimit; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
extern uint16_t coolingTarget; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
extern const char* printout; // declare to hold values for printing later
extern NumberInputSystem lowerLimitAlarmInput; // declare instances that we want to use of the NumberInputSystem class
extern NumberInputSystem higherLimitAlarmInput;// declare instances that we want to use of the NumberInputSystem class
extern NumberInputSystem coolDownTargetInput; // declare instances that we want to use of the NumberInputSystem class
extern Display disp; // declare instances we want to use
extern TempHelper temperature; // declare instances we want to use
class Actions
{
public:
void digits();
void graph();
void countdown();
void units();
void alarmOnOff();
void alarmLowLimit();
void alarmHighLimit();
void coolDownOnOff();
void coolDownTarget();
} ;
#endif // ACTIONS_H
/* Menu Test for memory-limited microcontrollers
This aims to see how much memory is required to implement different techniques of providing a menu system
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Changelog:
- V07 makes some changes to put things in more logical file locations, outside main.cpp
- V06 moves more of the main file into header files for readability (and one day, maintainability)
- V05 is purely a transition to platformio (change to .cpp etc)
- V04 fixes some issues that Pharap pointed out (assignment inside an expression) and moves towards separate files
- V03 moves from one single enum class to two enum classes, moves functions out of cases, uses the ternary operator, removes the floats (saving 1700B!)
- V02 adds some simulated behaviour, such as a (constant) current temperature value and adds menu state change functionality
- V01 changes some names for better readability and removes conditional compilation
*/
#include <Arduino.h>
#include "actions.h"
#include "numbersIn.h"
#include "thermDisplay.h"
bool button1Pressed = false; // button state
bool button2Pressed = false; // button state
uint16_t currentTempx10 = 443; // dummy number for displaying digits
bool alarmState = false; // default that the alarm is off
bool coolDownState = false; // default to not showing or activating the countdown
uint8_t countDownRemaining = 255; // dummy countdown variable
uint16_t alarmLowLimit = 200; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
uint16_t alarmHighLimit = 210; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
uint16_t coolingTarget = 200; // equivalent to 10 * temperature, so 200 = 20.0 degrees Centigrade
const char* printout; // declare to hold values for printing later
// Initialise Arduino pin numbers
constexpr uint8_t button1 = 2;
constexpr uint8_t button2 = 3;
constexpr uint8_t led1 = 4;
constexpr uint8_t led2 = 5;
// Function prototypes
void buttonCheck();
void Blink(uint8_t led);
Option menuState = Option::digits; // initialise the first state
TempUnit unit = TempUnit::celsius; // initialise the first unit
Actions act; // initialise an instance of the class `actions`, called `act`
NumberInputSystem lowerLimitAlarmInput { /*F("MENU Alarm lower limit: "), */ alarmLowLimit/*, Digit::Tens*/ }; // initialise an instance of the class `NumberInputSystem`, called `lowerLimitAlarmInput`
NumberInputSystem higherLimitAlarmInput {/* F("MENU Alarm upper limit: "),*/ alarmHighLimit/*, Digit::Tens*/ };
NumberInputSystem coolDownTargetInput { /*F("MENU Cooldown target: "),*/ coolingTarget/*, Digit::Tens */};
Display disp; // initialise instance of class 'display'
TempHelper temperature; // initialise instance of class 'tempHelper'
void setup() {
// set up serial monitor for output and user input
Serial.begin(115200);
// set up real buttons and state LEDs
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
// set the messages for the input prompts
lowerLimitAlarmInput.setMessage(F("MENU Alarm lower limit: "));
higherLimitAlarmInput.setMessage(F("MENU Alarm upper limit: "));
coolDownTargetInput.setMessage(F("MENU Cooldown target: "));
}
void loop() {
switch (menuState)
{
// display current reading in digits
case Option::digits:
act.digits();
break;
// display graph of current and past readings
case Option::graph:
act.graph();
break;
// display countdown estimate to target temperature
case Option::countdown:
act.countdown();
break;
// let the user toggle between Centigrade and Farenheit
case Option::units:
act.units();
break;
// let the user toggle between on and off
case Option::alarmOnOff:
act.alarmOnOff();
break;
// set the value of the lower limit for the alarm
case Option::alarmLowLimit:
act.alarmLowLimit();
break;
// set the value of the upper limit for the alarm
case Option::alarmHighLimit:
act.alarmHighLimit();
break;
// let the user toggle between on and off
case Option::coolDownOnOff:
act.coolDownOnOff();
break;
// let the user increment and select the cooling target temperature
case Option::coolDownTarget:
act.coolDownTarget();
break;
}
buttonCheck();
delay(100);
}
void buttonCheck()
{
button1Pressed = 0; // reset so serial input can be used
button2Pressed = 0; // reset so serial input can be used
if ( Serial.available() )
{
char c = Serial.read();
if ( c == '1')
{
button1Pressed = 1;
Serial.println(F("Button 1 pressed"));
}
else if (c == '2')
{
button2Pressed = 2;
Serial.println(F("Button 2 pressed"));
}
}
else // read hardware buttons
{
button1Pressed = digitalRead(button1) == 0;
button2Pressed = digitalRead(button2) == 0;
}
if (button1Pressed)
{
Blink(led1);
Serial.println(F("Button 1 pressed"));
}
if (button2Pressed)
{
Blink(led2);
Serial.println(F("Button 2 pressed"));
}
}
void Blink(uint8_t led)
{
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
}
/* Value editing library for the thermometer. Handles the incrementing of digits in variables by using the buttons
@created: 2020-05-18
@author: Simon Merrett
@version: 0.2
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Source code link: #TODO: complete link when published
Changelog:
- V0.2 refinement of header and cpp file structures and moving some functions into header files
- V0.1 initial drafting, after moving to platformio
*/
#ifndef NUMBERSIN_H
#define NUMBERSIN_H
#include <Arduino.h> // required for uint8_t to be recognised as a type
#include "thermDisplay.h"
#include "tempHelper.h"
enum class Digit : uint8_t {
Tens,
Ones,
Tenths,
};
class Display;
extern Display disp; // declare instances we want to use
class TempHelper;
extern TempHelper temperature; // declare instances we want to use
class NumberInputSystem
{
private:
const __FlashStringHelper * message;
uint16_t & value;
Digit digit;
public:
NumberInputSystem(/*const __FlashStringHelper * message,*/ uint16_t & value) : /*message(message),*/ value(value), digit(Digit::Tens) {}
void setMessage(const __FlashStringHelper * m)
{
message = m;
}
Digit getDigit()
{
return this->digit;
}
void render()
{
Serial.print(message);
disp.printTemperatureDiv10(this->value);
Serial.println();
}
void incrementDigit()
{
switch(this->digit)
{
case Digit::Tens:
this->value = temperature.incrementTens(this->value);
break;
case Digit::Ones:
this->value = temperature.incrementOnes(this->value);
break;
case Digit::Tenths:
this->value = temperature.incrementTenths(this->value);
break;
}
}
void cycleDigit()
{
switch(this->digit)
{
case Digit::Tens:
this->digit = Digit::Ones;
break;
case Digit::Ones:
this->digit = Digit::Tenths;
break;
case Digit::Tenths:
this->digit = Digit::Tens;
break;
}
}
};
#endif // NUMBERSIN_H
/* TempHelper class to provide temperature units and increment temperatures by digit (base 10).
@created: 2020-05-20
@author: Simon Merrett
@version: 0.1
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
Changelog:
- V0.1 initial creation to move enum class and functions out of main.cpp
*/
#ifndef TEMPHELPER_H
#define TEMPHELPER_H
#include <Arduino.h> // required for uint8_t to be recognised as a type
enum class TempUnit : uint8_t
{
farenheit,
celsius
};
class TempHelper
{
public:
char getUnitSymbol(TempUnit Unit)
{
switch(Unit)
{
case TempUnit::farenheit:
return 'F';
case TempUnit::celsius:
return 'C';
default:
return '?';
}
};
uint16_t incrementTens(uint16_t tensToIncrease)
{
tensToIncrease = (tensToIncrease + 100) % 1000; // remember that 100 represents 10 degrees. Modulo keeps tensToIncrease in range
return tensToIncrease;
};
uint16_t incrementOnes(uint16_t onesToIncrease)
{
uint16_t strippedLimit = (onesToIncrease / 100) * 100 + onesToIncrease % 10; // take the 10's out of onesToIncrease, e.g 258 -> 208
onesToIncrease = strippedLimit + 10 * ((1 + (onesToIncrease / 10) ) % 10);
return onesToIncrease;
};
uint16_t incrementTenths(uint16_t tenthsToIncrease)
{
uint16_t strippedLimit = (tenthsToIncrease / 10) * 10; // take the 1's out of alarmLowLimit, e.g 258 -> 250
tenthsToIncrease = strippedLimit + ((1 + tenthsToIncrease ) % 10);
return tenthsToIncrease;
};
};
#endif //TEMPHELPER_H
/* The Display class contains functions to print the temperature out.
@created: 2020-05-20
@author: Simon Merrett
@version: 0.1
Credits: thanks to @Pharap who provided many of the elements of this code and coached Simon Merrett hugely
*/
#ifndef THERMDISPLAY_H
#define THERMDISPLAY_H
class Display
{
public :
void showOnOff(bool var)
{
String p = (var) ? F("ON") : F("OFF");
Serial.println(p);
};
void printTemperatureDiv10(uint16_t Tempx10)
{
Serial.print(Tempx10 / 10);
Serial.print(F("."));
Serial.print(Tempx10 % 10);
};
void displayUpdate()
{
// TODO: insert code to see if the screen needs to be changed
};
};
#endif // THERMDISPLAY_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment