/*
Forum: https://forum.arduino.cc/t/need-beginner-help-with-debounce-logic/1425853
Wokwi: https://wokwi.com/projects/456759421371767809
duplicate Wokwi with diagram for the Nano is here:
https://wokwi.com/projects/455415060881775617
It's intended mostly for pinout verification.
Make no code changes there. Make changes here, then copy (if needed)
Presettable six digit counter / "totalizer" with debounced inputs
and persistent onboard memory
Accel Button class and EEPROM wear leveling class by ec2021
Copied from https://wokwi.com/projects/454412444481892353 created by ec2021
Example for reading buttons with "acceleration" of returned (btn.down() == True)
Supersedes previous version https://wokwi.com/projects/454183828831326209
Generous assistance from the forum contributors
ec2021, alto777, J-M-L, dougp, many others
The six digit counter / "totalizer" can be preset up or down
by pressing either of two buttons. So as to rapidly preset a desired
count start value, the increment and decrement values are calculated
based on the duration of time the respective button is held down.
Count on / set switch distinguishes the active counting state
vs presetting the count value.
While in that state, the prox sw input is ignored.
Setting the count value is processor-intensive.
The totalizer will be mostly at rest when the slide switch is "on"
which will be its usual, actual counting state.
While in that state, the prox sw will be used to increment
the count value (increment only, decrement could easily be added).
While in that state, the up / down switches are ignored.
While in that state, addional time-consuming actions can be performed
because the machine can only cycle so fast
2026/2/12 implemented power on reset count option
invoke by holding the count "down" toggle switch on boot
******************************************************
*** it should NOT be easy to reset counter to zero ***
******************************************************
User must confirm or cancel to continue.
Or, just release the button and reboot.
2026/2/18 implemented EEPROM dump easter egg
invoke by holding the count "up" toggle switch on boot
implemented software reboot option
reorganized program (again)
moved some functions out of loop()
moved AccelBtnClass to a separate library
added prox sw state indicator
control LCD backlight with PWM pin 9
Certain features such as serial USB read / write are temporary,
for debugging or personal development purposes,
and will eventually be removed.
notes / comments added / updated 2026/02/19
The following notes / comments added / updated 2026/02/23:
* EEPROM dump routine changed to dump byte wise
* orgStruct added in EEClass to align the offset to 8 byte
(see EEClass for further information)
Example dump (first three lines)
0 EF BE AD DE 00 00 FF FF
8 00 00 00 00 00 00 00 0
16 FF FF FF FF FF FF FF FF
...
with 0, 8, 16 etc. -> EEPROM address of the first hex byte in
a line
*/
#include <LiquidCrystal_I2C.h>
#include "AccelBtnClass.h" // ec2021 Accel Button Class
#include "EEClass.h" // which includes <EEPROM.h>
#include <DallasTemperature.h> // which includes <OneWire.h>
// Declare the myEE class
EEClass myEE;
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
#define ONE_WIRE_BUS 6
// Create a new instance of the oneWire class to communicate with any OneWire device:
OneWire oneWire(ONE_WIRE_BUS);
// Pass the oneWire reference to DallasTemperature library:
DallasTemperature sensors(&oneWire);
// define LCD parameters
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
char countTxt[16]; // specific for this particular 2 line x 16 char LCD
char lcdTemp[17]; // specific for this particular 2 line x 16 char LCD
constexpr uint32_t maxWriteCount{ 1 }; // set absurdly low for testing porpoises
constexpr uint32_t maxCount{ 999999 }; // unsure about this
const String buildDate = "02232026 0";
constexpr int buttons = sizeof(param) / sizeof(param[0]);
constexpr byte countSetIndex{ buttons - 1 }; // Addresses the parameters of the count on / set toggle sw in the array
long Count; // the count value, signed so that < 0 can be detected
long increment = 1; // separate increment / decrement values can be implemented
long decrement = 1;
const long EEdelayTime = 10; // EEPROM write delay time in millis
const long maxDelta = 2047; // max accel rate
const long blinkinterval = 1000; // interval at which to blink the onboard LED (milliseconds)
const int ledOnboard = LED_BUILTIN; // onboard LED pin designation
unsigned long previousMillis = 0; // will store last time onboard LED was updated
long lastCount = -1; // effectively a flag to indicate count change (it's never negative)
long lastStoredCount; // the last Count value stored in EEPROM
const byte rebootPin = 8; // to be used for software reset (not implemented yet) (won't be used)
const byte blPin = 9; // PWM pin used to control LCD backlight brightness (connect it to I2C LED)
const byte blBrightness = 64; // backlight brightness (64 = about halfway)
bool led0State = LOW; // led0State used to set the onboard LED
const int proxPin = 2; // the magnetic prox sw input input pin
const int countUpPin = 3; // the "count up preset" toggle sw input pin
int countUpState = HIGH;
const int countDownPin = 4; // the "count down preset" toggle sw input pin
int countDownState = HIGH;
const int counterOnPin = 5; // the counter "on" / "set" slide sw
int counterOnState = HIGH;
unsigned long eepromTimer; // An idle timer. Write updates to EEPROM after a delay.
bool updateEEPROM = false; // flag to indicate Count needs to be written to EEPROM
const byte bell[8] = { 0x04, 0x0e, 0x0e, 0x0e, 0x1f, 0x00, 0x04 }; // we can only use 8 custom characters
const byte note[8] = { 0x02, 0x03, 0x02, 0x0e, 0x1e, 0xc0, 0x00 }; // so some of these have to go
const byte clock[8] = { 0x00, 0x0e, 0x15, 0x17, 0x11, 0x0e, 0x00 };
const byte heart[8] = { 0x00, 0x0a, 0x1f, 0x1f, 0x0e, 0x04, 0x00 };
const byte duck[8] = { 0x00, 0x0c, 0x1d, 0x0f, 0x0f, 0x06, 0x00 };
const byte check[8] = { 0x00, 0x01, 0x03, 0x16, 0x1c, 0x08, 0x00 };
const byte cross[8] = { 0x00, 0x1b, 0x0e, 0x04, 0x0e, 0x1b, 0x00 };
const byte retarrow[8] = { 0x01, 0x01, 0x05, 0x09, 0x1f, 0x08, 0x04 };
const byte upArrow[8] = { 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 }; // up arrow
const byte dnArrow[8] = { 0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04, 0x00 }; // down arrow
const byte smiley[8] = { 0x00, 0x0A, 0x0A, 0x00, 0x11, 0x0E, 0x00, 0x00 }; // smiley
/*******************************************************
// ec2021 comments
// The following declaration creates a pointer to an AccelBtnClass object
// The pointer will be set to the instance of the button[] array that
// belongs to the slide switch so that it's easier to read the code
// It's meant as an example: The same could be done for the other buttons as well ...
/*******************************************************
*/
AccelBtnClass button[buttons];
AccelBtnClass *CountSetBtn;
void setup() {
digitalWrite(rebootPin, HIGH); // set a benign state before configuring it as output (will prolly be removed)
// initialize digital I/O and choose the internal pullup resistor for inputs
pinMode(proxPin, INPUT_PULLUP);
pinMode(countUpPin, INPUT_PULLUP);
pinMode(countDownPin, INPUT_PULLUP);
pinMode(counterOnPin, INPUT_PULLUP);
pinMode(ledOnboard, OUTPUT);
pinMode(blPin, OUTPUT);
pinMode(rebootPin, OUTPUT); // pin to be used for software reboot (will prolly be removed)
// LCD Initialization
lcd.init();
// create those up and down arrow emoji
lcd.createChar(0, upArrow); // ↑
lcd.createChar(1, dnArrow); // ↓
lcd.createChar(2, smiley); // ☺
lcd.createChar(3, heart); // ♥
lcd.createChar(4, duck); // it quacks like a ____
lcd.createChar(5, check); // ✓
lcd.createChar(6, cross); // ×
lcd.createChar(7, retarrow); // ↲
// turn it on slowly
lcd.backlight();
for (int n = 0; n < blBrightness; n++) {
analogWrite(blPin, n);
delay(15);
}
// init the myEE class
myEE.init(maxCount, maxWriteCount);
// retrieve the stored Count
Count = myEE.readActCount();
// the following only matters after a reboot, otherwise it will cause a
// needless EEPROM write if the count / set sw is in the "set" position on boot
// and neither up / down button is pressed (their normal resting state).
// The code considers that state to indicate user inactivity, which is
// when we write to EEPROM if the count changed and timer expired...
lastCount = Count;
lastStoredCount = Count;
Serial.begin(9600);
// debugging stuff
Serial.print(F("Build: "));
Serial.println(buildDate);
Serial.print(F("Count: "));
Serial.print(myEE.readActCount(), DEC);
Serial.print(F(" at Index: "));
Serial.println(myEE.getIndex(), DEC);
sensors.begin();
// setResolution(9) = 12 bits = about 0.5°C
// I believe 9 is the default anyway so this is probably superfluous
sensors.setResolution(12);
// don't wait for conversion
// temperature is not that important
sensors.setWaitForConversion(false);
/*
With paramType struct this initialization can be used
for (int i= 0; i<buttons;i++){
button[i].init(param[i].pinNo,
param[i].minIntv,
param[i].maxIntv,
param[i].decr
);
}
or as an alternative one can call the init function that
directly reads the struct as its parameter.
CountSetBtn is set to the corresponding array entry.
These calls can be used alternatively:
button[3].getDebouncedState()
button[countSetIndex].getDebouncedState()
CountSetBtn->getDebouncedState()
*/
for (int i = 0; i < buttons; i++) {
button[i].init(param[i]);
}
CountSetBtn = &button[countSetIndex];
// Detect an unlikely count up / down button input state on boot
//
// The count up / down switch is a spring return to center toggle switch,
// so if is determined to be pressed on boot it was intentional.
// It cannot be left in that position on its own. It has to be held there.
// The count "up" condition in which button[0] is determined to have been
// held down will be explained first.
//
// This condition will offer the opportunity to show all saved count values
// in sequence. The sequence will repeat forever until the user presses
// the "down" button[1], which cancels. The program loop() then continues.
//
// To implement "the user changes his mind" all he has to do is momentarily press
// the count "down" switch. Nothing will change and Count will remain unaffected.
// A brief confirmation message will be provided. If the switch is kept down
// for over one second instead of just being momentarily depressed, the next
// input state detection routine will be the option to reset the counter.
//
// Another way of backing out would simply to reboot without holding any buttons.
// However, if you reboot while the EEPROM contents are actively being retrieved,
// there is a significant likelihood a corrupt / invalid Count value will result.
//
if (button[0].down()) { // That's the "up" button / toggle sw
Serial.println(F("Display EEPROM contents?")); //
Serial.println(F("To confirm, press the UP switch again. ")); //
Serial.println(F("To cancel, press the DOWN switch. ")); //
Serial.println(F("Waiting for you to decide."));
lcd.clear();
lcd.print(F("Build "));
lcd.print(buildDate);
delay(1000);
lcd.clear();
lcd.print(F("Display EEPROM?"));
lcd.setCursor(2, 1); // write the text, up arrow, down arrow, etc to LCD
lcd.print(F("Yes"));
lcd.setCursor(10, 1);
lcd.print(F("No"));
lcd.setCursor(0, 1);
lcd.write(byte(0)); // ↑
lcd.setCursor(8, 1);
lcd.write(byte(1)); // ↓
while (true) { // stop here and wait patiently for user to contemplate his life choices
if (button[0].pressed()) { // That's the "increment" button. User intent to reset counter confirmed.
Serial.println(F("EEPROM Dump"));
EEdump();
break; // bang out of setup()
}
if (button[1].pressed()) { // That's the "decrement" button. User cancels dump
Serial.println(F("EEPROM Dump cancelled"));
lcd.setCursor(0, 1); // write to LCD so user can see some kind of confirmation...
lcd.print(F("Cancelled "));
lcd.setCursor(10, 1);
lcd.write(byte(3)); // ♥
delay(1000); // wait a moment for the user to read the message.
break; // bang out of setup()
}
}
}
// If we get here the first Easter egg was either bypassed or cancelled.
// In either case, the previous Count value will have been restored.
startLCD(); // show the static Count: text and the Count value
// If we get here as a result of a hardware reset while the EEPROM contents
// were actively being retrieved in the above Easter egg, then the retrieved
// Count value will not be valid. In that case Count: will now display -000001
// (all bits high, 0xFFFFFFFF), or a previously stored but expired and
// equally invalid count.
// The count "down" condition in which button[0] is determined to have been
// held down will be explained next.
//
// If that condition is detected, the user is presented with two choices:
// reset the count value to zero, cancel, or (thrid of two choices) reboot.
//
// To confirm the user really wanted to reset the counter, all he has to do is
// release and then momentarily press the count "down" switch again. Count will be reset.
// A brief confirmation message will be provided, and loop() runs as it always has.
//
// To implement "the user changes his mind" all he has to do is momentarily press
// the count "up" switch. Nothing will change and Count will remain unaffected.
// A brief confirmation message will be provided, and loop() runs as it always has.
//
// In either case we will wait for one of those two actions before proceeding to loop().
// Note: If that button press persists for longer than one second the counter will
// actually register an increment or decrement, but maybe that's ok. Undecided.
// Another way of backing out would simply to reboot without holding any buttons.
//
if (button[1].down()) { // That's the "down" button / toggle sw
Serial.println(F("Reset counter?")); //
Serial.println(F("To confirm, press the UP switch again. ")); //
Serial.println(F("To cancel, press the DOWN switch. ")); //
Serial.println(F("Waiting for you to decide."));
lcd.setCursor(2, 1); // write the text, up arrow, down arrow, etc to LCD
lcd.print(F("Reset"));
lcd.setCursor(10, 1);
lcd.print(F("Cancel"));
lcd.setCursor(0, 1);
lcd.write(byte(0));
lcd.setCursor(8, 1);
lcd.write(byte(1));
while (true) { // stop here and wait patiently for user to contemplate his life choices
if (button[0].pressed()) { // That's the "increment" button. User intent to reset counter confirmed.
Serial.println(F("Reset confirmed"));
resetCount(); // erase counter but wait another moment for user to release the up / down button.
lcd.setCursor(0, 1); // write to LCD so user can see some kind of confirmation...
lcd.print(F("Counter reset! ")); //
delay(1000); // wait a moment for the user to read the message.
return; // bang out of setup()
}
if (button[1].pressed()) { // That's the "decrement" button. User changes his mind.
Serial.println(F("Reset counter cancelled"));
lcd.setCursor(0, 1); // write to LCD so user can see some kind of confirmation...
lcd.print(F("Cancelled "));
lcd.setCursor(10, 1);
lcd.write(byte(2)); // :-)
delay(1000);
startLCD();
return; // bang out of setup()
}
}
}
} // ***** end of setup() *****
void loop() {
/*
The function getDebouncedState() returns .... the debounced state of course ... ;-)
It can be used here alternatively as
if (button[3].getDebouncedState()){}
if (button[countSetIndex].getDebouncedState()){} or
if (CountSetBtn->getDebouncedState()) {}
jg1: I reverted to the below for debugging purposes
Besides, I'm not too concerned about that switch bouncing.
Nothing bad will happen if it does.
Extraneous counts, etc can't happen unless an up / down button is pressed
at the same time the switch moves, and that's unlikely given the hardware.
Tested in hardware... if you hold an up / down sw at the same time you move
the count on / off switch, the existing delta value remains the same,
which is pretty cool. I don't want to change that.
If you hold the prox switch down at the same time you move the count
on / off switch, exactly nothing happens. That's good.
jg1: 2/18/2026: I think this is causing unintended consequences so I reverted.
It only manifests when invoking the "easter egg" routine to reset the counter, and
the "cancel" button is held for more than a second. That causes the count to spuriously
decrement (or increment, if the "cancel" / down option is immediately followed by
pressing the "up" button.) The EEPROM is not affected, only the displayed Count value.
As edge cases go, this is really, really insignificant, but reverting to the above
direct counterOnPin read completely obliviates the problem. Besides, that "button"
(toggle sw IRL) cannot not cause undue harm, even if it is bouncy, because nothing
can possibly happen unless other inputs change state commensurate with the bouncing.
Suspect the getDebouncedState() takes longer than it takes to get to the code that
detects an increment or decrement. Unsure. So I'm reading it directly for now.
if (CountSetBtn->getDebouncedState()) {
Counting();
} else {
notCounting();
}
*/
counterOnState = digitalRead(counterOnPin); // get count on / set sw state
if (counterOnState) {
Counting();
} else {
notCounting();
}
indicateProxState();
EEPROMwriteAfterDelay(); // write to EEPROM but only after some idle time
serialEcho();
backgroundTasks();
} // ***** end of loop() *****
void startLCD() { // clear display and write static text
lcd.clear(); // clear display and set cursor to upper left
lcd.print(F("Count: "));
displayCount();
}
void displayCount() {
snprintf(countTxt, sizeof countTxt, "%08.6ld", Count);
lcd.setCursor(8, 0);
lcd.print(countTxt);
}
void resetCount() {
Count = 0;
myEE.updateActCount(Count); // using the wear leveler instead
lastStoredCount = Count;
displayCount();
}
void hardwareReset() {
digitalWrite(rebootPin, LOW);
}
void backgroundTasks() {
// do something every other second
// heartbeat routine runs all the time
// this is the most basic Arduino newbie code
// check to see if it's time to toggle the onboard LED; that is, if the difference
// between the current time and last time you toggled the LED is larger than
// the interval at which you want to toggle the LED.
unsigned long currentMillis = millis();
unsigned long currentSecs = currentMillis / 1000;
if (currentMillis - previousMillis >= blinkinterval) {
previousMillis = currentMillis;
toggleLED();
digitalWrite(ledOnboard, led0State);
if (led0State) { // do something like blinkenlights
Serial.print(F("Time "));
Serial.print(currentSecs);
Serial.print(F("\t\t"));
Serial.println();
} else { // do something other than blinkenlights
getTemperature();
printTemperature();
doNothing();
}
}
}
void serialEcho() {
if (Serial.available()) { // If anything comes in Serial (USB)
Serial.write(Serial.read()); // echo it back to Serial (USB)
}
}
void toggleLED() { // this is kinda dumb but why not
led0State = !led0State;
}
void doNothing() { // do nothing placeholder
}
void getTemperature() { // Send temperature conversion request
// ****** very important to use sensors.setWaitForConversion(false); in setup() above ******
// ****** otherwise this request will hold things up for many millis, causing jerkiness
sensors.requestTemperatures();
}
void printTemperature() {
float tempF = sensors.getTempFByIndex(0);
// Check if sensor is taking a smoke break. If so blank the entire LCD line and bail out
// See the next section (commented out) for another way.
if (tempF == DEVICE_DISCONNECTED_F) {
memset(lcdTemp, ' ', 16);
lcdTemp[16] = '\0'; // null terminator
lcd.setCursor(0, 1);
lcd.print(lcdTemp); // print a blank line... and
return; // pull the ripcord
}
memcpy(lcdTemp, "Motor: ", 7); // Copy prefix
// Note: Arduino UNO snprinf() does not work with float,
// not without implementing significant changes to the core (linker flags...?)
// I did not know that. Found out the hard way.
// Using dtosrtf() instead.
dtostrf(tempF, 7, 1, lcdTemp + 7); // Format temperature into buffer
lcdTemp[14] = '\xDF'; // Append degree symbol
lcdTemp[15] = 'F'; // and 'F'
lcdTemp[16] = '\0'; // null terminator
lcd.setCursor(0, 1);
lcd.print(lcdTemp);
}
/*******************************************************
Another method. It displays dashes for temperature
instead of just a blank line,
lest the user think something is wrong with the display.
Choose one or the other.
void printTemperature() {
Float tempF = sensors.getTempFByIndex(0);
memcpy(lcdTemp, "Motor: ", 7);
if (tempF == DEVICE_DISCONNECTED_F) {
// Right-align placeholder in 7-character space
// Fill first 3 chars with spaces, then '--.-'
memcpy(lcdTemp + 7, " --.-", 7);
} else {
// Format temperature into the main buffer
dtostrf(tempF, 7, 1, lcdTemp + 7);
}
lcdTemp[14] = '\xDF'; // Append degree symbol
lcdTemp[15] = 'F'; // and 'F'
lcdTemp[16] = '\0'; // null terminator
lcd.setCursor(0, 1);
lcd.print(lcdTemp);
}
********************************************************/
void EEPROMwriteAfterDelay() {
//
// If updateEEPROM flag has been set, wait a while (ten seconds) first,
// then do it, then indicate it's been done.
// Actions that change the Count value are responsible for restarting
// the idle timer: eepromTimer = millis() accomplishes that.
// alto777 wrote this part
//
if (!updateEEPROM) return; // no need to, we outta here
if (Count == lastStoredCount) return; // don't write if it hasn't changed (eeclass checks that anyway)
if (millis() - eepromTimer < EEdelayTime) return; // value needs to be written, but not yet!
myEE.updateActCount(Count); // EEPROM write using the wear leveler
lastStoredCount = Count;
Serial.print(F("Wrote to EEPROM, value: ")); // everything will eventually be displayed on the LCD
Serial.println(Count); // so we can get rid of this later
updateEEPROM = false; // ok ok, get off my back
}
void indicateProxState() {
//
// prox sw state indicator
// this might be an LED or some other indication of prox state
// I want this to run all the time, constantly, as in always.
//
if (button[2].down()) {
lcd.setCursor(7, 0);
lcd.write(byte(0)); // indicate prox sw closed
}
if (button[2].isReleased()) {
lcd.setCursor(7, 0);
lcd.write(byte(1)); // indicate prox sw open
}
}
void EEdump() {
uint16_t idx;
uint16_t start_idx;
Serial.print("EEPROM length is: ");
Serial.println(EEPROM.length());
Serial.println();
lcd.clear();
lcd.print(F("Index: "));
lcd.setCursor(0, 1);
lcd.print(F("Count: "));
for (idx = 0; idx < EEPROM.length(); idx++) {
if (idx % 8 == 0){
Serial.println();
Serial.print(idx);
Serial.print('\t');
}
byte b = EEPROM.read(idx);
Serial.print(' ');
if (b < 0x10){
Serial.print('0');
}
Serial.print(b,HEX);
}
Serial.println();
startLCD();
}
void Counting() { // meat of the program lives here.
// it is what counts the actual machine cycles
if (button[2].pressed()) { // magnetic prox switch sensed
Count++;
if (Count > 999999) { // wrap through zero
Count = 0;
}
displayCount();
if (lastCount != Count) {
updateEEPROM = true; // update needs doing
eepromTimer = millis(); // ... after some quiet time
}
lastCount = Count;
Serial.print(F("Prox sw detected, count offered to be written: "));
Serial.println(Count);
//
// time-consuming things while we wait
// for something interesting to happen
// can be added here.
//
doNothing(); // it's what I do best
}
}
void notCounting() {
// This routine will be called upon only when count on / off sw is in the "set" position.
// It means the machine is not running production, and the operator either wants to turn
// the counter off for maintenance - or - to preset a new count value prior to resuming
// production on the machine.
// It checks the up / down toggle switch action,
// and increments / decrements the count value when the corresponding button is depressed.
// The resulting count value should be written to EEPROM only when
// the up / down toggle switch is released, and a few seconds have transpired
// after releasing the up / down toggle switch (green / red buttons on the Wokwi)
if (Count != lastCount) { // LCD display the count value only if it has changed.
displayCount();
}
if (button[0].isReleased() && button[1].isReleased()) {
if (Count != lastCount) { // If the Count has changed,
updateEEPROM = true; // update needs doing
eepromTimer = millis(); // ... after some quiet time
lastCount = Count;
Serial.print(F("Counter adjustment made, count offered to be written: "));
Serial.println(Count);
//
// time-consuming things while we wait
// for something interesting to happen
// can be added here.
//
doNothing(); // it's what I do best
}
}
if (button[0].down()) { // increment preset
Count += increment;
if (Count > 999999) { // wrap through zero
Count = 0;
}
// The following changes the increment (delta) depending
// on the duration the button is held down
increment = min(pow(2, button[0].getDownInterval() / 1000), maxDelta);
// The following resets the idle time to address the possibility
// a count up / down button is pressed and released then
// pressed again before the EEPROM write time expires.
// Otherwise the count would be written to EEPROM while still
// actively setting the counter, which is kind of needless.
eepromTimer = millis();
}
if (button[1].down()) { // decrement preset
Count -= decrement;
if (Count < 0) { // wrap through zero
Count = 999999;
}
// The following changes the decrement (delta) depending
// on the duration the button is held down
decrement = min(pow(2, button[1].getDownInterval() / 1000), maxDelta);
// The following resets the idle time to address the possibility
// a count up / down button is pressed and released then
// pressed again before the EEPROM write time expires.
// Otherwise the count would be written to EEPROM while still
// actively setting the counter, which is kind of needless.
eepromTimer = millis();
}
// The following lines reset the increment (delta) to 1
// when button[0] is not down
if (button[0].isReleased()) {
increment = 1;
}
// The following lines reset the decrement (delta) to 1
// when button[1] is not down
if (button[1].isReleased()) {
decrement = 1;
}
}
Up toggle sw
down toggle sw
Count on / set sw
prox sw
on
set
SDA
SCL
goes to LCD backlight