// test file to include writing to / reading from EEPROM, blink the builtin LED without using Delay()
// output to serial
// read pushbutton inputs and illuminate red / green LEDs
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 20
#define LCD_LINES 2
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
#include <EEPROM.h>
// the following was copied from example EEPROM Read file
// initialize the starting address, a value (for each byte) and the count (unsigned long)
int memAddress = 0;
long memValue;
long count0 = 5; // initial value to place in EEPROM
long count1 = count0; // initial value to place in EEPROM
long count2 = count0; // initial value to place in EEPROM
// various time values
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 5; // the debounce time; increase if the output flickers
unsigned long previousMillis = 0; // will store last time onboard LED was updated
long lastCount = -1; // flag to indicate count change (it's never negative)
// constants won't change. Used here to set a pin number:
const int ledOnboard = LED_BUILTIN; // the number of the onboard LED pin
const int button1Pin = 8; // the number of the pushbutton pin
const int button2Pin = 9; // the number of the pushbutton pin
const int led1Pin = 2; // the number of the red LED pin
const int led2Pin = 3; // the number of the green LED pin
const int togglePin = 7; // the number of the yellow LED pin
const long blinkinterval = 1000; // interval at which to blink the onboard LED (milliseconds)
// Variables will change:
int led0State = LOW; // led0State used to set the onboard LED
int led1State = LOW; // led1State used to set the red LED
int led2State = LOW; // led2State used to set the green LED
int button1State = LOW; // variable for reading the pushbutton 1 status
int button2State = LOW; // variable for reading the pushbutton 2 status
int lastButton1State = HIGH; // previous state of button 1
int lastButton2State = HIGH; // previous state of button 2
int switch1State = HIGH; // flag to indicate button 1 state change
int switch2State = HIGH; // flag to indicate button 2 state change
void setup() {
// set digital pins as outputs for the LEDs:
pinMode(ledOnboard, OUTPUT);
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(togglePin, OUTPUT);
// LCD Initialization
lcd.init();
lcd.backlight();
// Print something for later reference
lcd.setCursor(0, 0);
lcd.print("Count:");
Serial.begin(9600);
// initialize the external pushbutton pins as input, and choose the internal pullup resistor:
pinMode(button1Pin, INPUT_PULLUP);
pinMode(button2Pin, INPUT_PULLUP);
// populate first four (long integer i.e. 4 byte) EEPROM storage locations
// use EEPROM.put if you want to explicitly write
// use EEPROM.update if you want to write only if previous contents will be changed - prevents wear...?
EEPROM.put(memAddress + 0 , count0);
EEPROM.update(memAddress + 0 , count0);
EEPROM.put(memAddress + 4 , count1);
EEPROM.update(memAddress + 8 , count2);
}
// define onboard LED toggle function - if onboard LED is off turn it on and vice-versa
// I think this could be written more concisely but the following code makes it obvious
void toggleLED() {
if (led0State == LOW) {
led0State = HIGH;
} else {
led0State = LOW;
}
}
void loop() {
// here is where you'd put code that needs to be running all the time.
// serial echo
if (Serial.available()) { // If anything comes in Serial (USB)
Serial.write(Serial.read()); // echo it back to Serial (USB)
}
// read both button states.
// They may be changed due to deliberate action, or noise, so we need debounce logic to determine which.
button1State = digitalRead(button1Pin);
button2State = digitalRead(button2Pin);
// check for either button change of state first.
if ((button1State != lastButton1State)||(button2State != lastButton2State)) { // state change detected, but was it noise?
lastDebounceTime = millis();
}
lastButton1State = button1State ;
lastButton2State = button2State ;
if ((millis() - lastDebounceTime) > debounceDelay) { // wait for debounce time to expire before doing anything
if (button1State != switch1State) { // if it gets here a legit state change was detected
if (button1State == LOW) {
digitalWrite(led1Pin, HIGH);
digitalWrite(togglePin, digitalRead(togglePin) == HIGH ? LOW : HIGH); // toggle yellow "state change" LED, just for the red button
count1++ ;
}
else {
digitalWrite(led1Pin, LOW);
}
}
switch1State = button1State;
if (button2State != switch2State) { // if it gets here a legit state change was detected, so
if (button2State == LOW) {
digitalWrite(led2Pin, HIGH);
count1-- ;
}
else {
digitalWrite(led2Pin, LOW);
}
}
switch2State = button2State;
}
// set max count at 999999 then it rolls to zero
if (count1 > 999999)
{
count1 = 0 ;
}
// set min count at 0 then it rolls to 999999
if (count1 < 0)
{
count1 = 999999 ;
}
// make the count integer into a string for display purposes
if (count1 != lastCount) {
// we only need to do this if the count value has changed
// because otherwise we'd be writing to the LCD all the time
// Note regarding the following snprintf function:
// The %08 here is something hardcoded.
// It's the width of the display (16) minus the number of characters in "Count:"
// 16 - 6 = 10, so that's the remaining space at the right of that label.
// if we change the label "Count:", we will want to change the 08.
// the .6 tells the function how many digits you want (six).
// the ld means pad with zeroes (I think)
// math is hard
char countTxt[16];
snprintf(countTxt, sizeof countTxt, "%08.6ld", count1);
lcd.setCursor(8, 0);
lcd.print(countTxt);
lastCount = count1;
}
// 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 currentMicros = micros(); // not used
unsigned long currentSecs = currentMillis / 1000;
if (currentMillis - previousMillis >= blinkinterval) {
// save the last time you toggled the LED
previousMillis = currentMillis;
toggleLED();
// seconds elapsed time serial output
Serial.print("Time ");
Serial.print(currentSecs);
Serial.print("\t");
// read a byte from the current address of the EEPROM
memValue = EEPROM.get(memAddress, memValue);
// print the EEPROM memValue at memAddress
Serial.print("Addr: ");
Serial.print(memAddress);
Serial.print(" ");
Serial.print(memValue, HEX);
Serial.print(" ");
Serial.print("Count1: ");
Serial.print(count1);
Serial.print(" ");
Serial.print("Count2: ");
Serial.print(count2);
Serial.println();
// set the onboard LED to the ledState of the variable:
digitalWrite(ledOnboard, led0State);
// Advance to the next address, when at the end restart at the beginning.
memAddress = memAddress + 4; // increment the memory address by 4 bytes
if (memAddress >= EEPROM.length()) {
memAddress = 0;
}
}
}