Skip to content

Instantly share code, notes, and snippets.

@SimonMerrett
Created May 19, 2020 14:12
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/ae4fad1020020ef2e58c03b3475a48a1 to your computer and use it in GitHub Desktop.
Save SimonMerrett/ae4fad1020020ef2e58c03b3475a48a1 to your computer and use it in GitHub Desktop.
current state of thermometer menu
/* Actions library for thermometer
@created: 2020-05-16
@author: Simon Merrett
@version: 0.1
Source code link: #TODO: complete link when published
For changelog see actions.h
*/
#include "actions.h"
#include "numbersIn.h"
void actions::digits()
{
Serial.print(F("DISPLAY Current Temp = "));
printTemperatureDiv10(currentTempx10);
char u = 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: "));
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
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.1
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.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
class NumberInputSystem; // declare the class which is initialised elsewhere (numbersIn.h)
enum class Option : uint8_t
{
digits,
graph,
countdown,
units,
alarmOnOff,
alarmLowLimit,
alarmHighLimit,
coolDownOnOff,
coolDownTarget,
};
enum class TempUnit : uint8_t
{
farenheit,
celsius
};
extern uint16_t currentTempx10; // dummy number for displaying digits
extern void printTemperatureDiv10(uint16_t tempx10);
extern char getUnitSymbol(TempUnit unit);
extern void showOnOff(bool var);
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
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:
- 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"
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;
void showOnOff(bool var);
uint16_t incrementTens(uint16_t tensToIncrease);
uint16_t incrementOnes(uint16_t onesToIncrease);
uint16_t incrementTenths(uint16_t tenthsToIncrease);
void printTemperatureDiv10(uint16_t tempx10);
void displayUpdate();
void buttonCheck();
void Blink(uint8_t led);
char getUnitSymbol(TempUnit unit);
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 */};
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)
{
case Option::digits: // code to display current reading in digits
act.digits(); // test that the function is run
break;
case Option::graph: // code to display graph of current and past readings
act.graph(); // test that the function is run
break;
case Option::countdown: // code to display countdown estimate to target temperature
act.countdown();
break;
case Option::units: // code to toggle between Centigrade and Farenheit
act.units();
break;
case Option::alarmOnOff: // code to toggle between on and off
act.alarmOnOff();
break;
case Option::alarmLowLimit:
act.alarmLowLimit();
break;
case Option::alarmHighLimit:
act.alarmHighLimit();
break;
case Option::coolDownOnOff: // code to toggle between on and off
act.coolDownOnOff();
break;
case Option::coolDownTarget: // code to increment and select the tens unit of cooling target temperature
act.coolDownTarget();
break;
}
buttonCheck();
delay(100);
}
void showOnOff(bool var)
{
String p = (var) ? F("ON") : F("OFF");
Serial.println(p);
}
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;
}
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
}
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);
}
char getUnitSymbol(TempUnit unit)
{
switch(unit)
{
case TempUnit::farenheit:
return 'F';
case TempUnit::celsius:
return 'C';
default:
return '?';
}
}
/* 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.1
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.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 "actions.h"
// declare external variables and functions
extern uint16_t currentTempx10; // dummy number for displaying digits
extern void printTemperatureDiv10(uint16_t tempx10);
extern char getUnitSymbol(TempUnit unit);
extern Option menuState;
extern TempUnit unit;
extern bool button1Pressed;
extern bool button2Pressed;
extern uint16_t incrementTens(uint16_t tensToIncrease);
extern uint16_t incrementOnes(uint16_t onesToIncrease);
extern uint16_t incrementTenths(uint16_t tenthsToIncrease);
enum class Digit : uint8_t {
Tens,
Ones,
Tenths,
};
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);
printTemperatureDiv10(this->value);
Serial.println();
}
void incrementDigit()
{
switch(this->digit)
{
case Digit::Tens:
this->value = incrementTens(this->value);
break;
case Digit::Ones:
this->value = incrementOnes(this->value);
break;
case Digit::Tenths:
this->value = 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment