I have been working on this timer project for a little while. At this point it seems to be working fine. The one thing I am have trouble with is the whole thing seems to lock up randomly (only happened a few times) usually at or near startup. It will quit responding to any inputs including the rotary encoder. The reset button on the board does not effect it. Only unplugging the board and plugging it back in fixes it. I'm using an Arduino Uno and everything is connected using a solderless breadboard. Not sure if the problem is in my code, or if maybe there is a problem with my Arduino board, or my breadboard setup. Really not sure.
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define clkPin 2 //clk, dt, and sw pins from the rotary encoder
#define dtPin 4
#define swPin 6
#define startPin 8 //start/pause button
#define memoryPinA 9 //saved time buttons
#define memoryPinB 10
#define longPressTime 1500
#define uvPin 11 //uv light
#define buzzerPin 12
#define buzzerFreq 440
#define buzzOnTime 750
#define buzzOffTime 250
#define NumberOfBuzzes 3
#define flashOnTime 400
#define flashOffTime 250
#define debounceTime 10
volatile int timeSel = 1;
volatile int hours;
volatile int minutes;
volatile int seconds;
bool startPinState = false;
void encoderISR() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > debounceTime) {
if (digitalRead(dtPin) == HIGH) {
if (timeSel == 0) {
hours ++;
}
if (timeSel == 1) {
minutes ++;
}
if (timeSel == 2) {
seconds ++;
}
}
else {
if (timeSel == 0) {
hours --;
}
if (timeSel == 1) {
minutes --;
}
if (timeSel == 2) {
seconds --;
}
}
hours = max(0, hours);
minutes = min(59, max(0, minutes));
seconds = min(59, max(0, seconds));
lastInterruptTime = interruptTime;
}
}
void toggleHMS() { //steps through the variable used to select housr, minutes, and seconds
if (timeSel < 2) {
timeSel ++;
}
else {
timeSel = 0;
}
if (timeSel == 0) {
flashHours();
delay(flashOffTime);
printTime();
delay(flashOnTime);
flashHours();
delay(flashOffTime);
printTime();
}
if (timeSel == 1) {
flashMinutes();
delay(flashOffTime);
printTime();
delay(flashOnTime);
flashMinutes();
delay(flashOffTime);
printTime();
}
if (timeSel == 2) {
flashSeconds();
delay(flashOffTime);
printTime();
delay(flashOnTime);
flashSeconds();
delay(flashOffTime);
printTime();
}
while (!digitalRead(swPin))
delay(debounceTime);
}
void flashHours() {
lcd.clear();
lcd.setCursor(4, 0);
lcd.print(" ");
// lcd.print(hours);
lcd.print(":");
if (minutes < 10) {
lcd.print("0");
}
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) {
lcd.print("0");
}
lcd.print(seconds);
}
void flashMinutes() {
lcd.clear();
lcd.setCursor(4, 0);
if ( hours < 10) {
lcd.print(" ");
}
lcd.print(hours);
lcd.print(":");
lcd.print(" ");
lcd.print(":");
if (seconds < 10) {
lcd.print("0");
}
lcd.print(seconds);
}
void flashSeconds() {
lcd.clear();
lcd.setCursor(4, 0);
if ( hours < 10) {
lcd.print(" ");
}
lcd.print(hours);
lcd.print(":");
if (minutes < 10) {
lcd.print("0");
}
lcd.print(minutes);
lcd.print(":");
lcd.print(" ");
}
void printTime() {
lcd.clear();
lcd.setCursor(4, 0);
if ( hours < 10) {
lcd.print(" ");
}
lcd.print(hours);
lcd.print(":");
if (minutes < 10) {
lcd.print("0");
}
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) {
lcd.print("0");
}
lcd.print(seconds);
}
void countDown() {
if (seconds > 0) {
seconds --;
}
else if (minutes > 0) {
minutes --;
seconds = 59;
}
else if (hours > 0) {
hours --;
minutes = 59;
seconds = 59;
}
}
void buzz() {
for (int j = 0; j < NumberOfBuzzes; j++) {
tone(buzzerPin, buzzerFreq);
delay(buzzOnTime);
noTone(buzzerPin);
delay(buzzOffTime);
}
}
void callMemoryA() {
hours = EEPROM.read(0);
minutes = EEPROM.read(1);
seconds = EEPROM.read(2);
printTime();
}
void callMemoryB() {
hours = EEPROM.read(10);
minutes = EEPROM.read(11);
seconds = EEPROM.read(12);
printTime();
}
void updateMemoryA() {
EEPROM.update(0, hours);
EEPROM.update(1, minutes);
EEPROM.update(2, seconds);
lcd.clear();
delay(flashOffTime);
printTime();
delay(flashOnTime);
lcd.clear();
delay(flashOffTime);
printTime();
}
void updateMemoryB() {
EEPROM.update(10, hours);
EEPROM.update(11, minutes);
EEPROM.update(12, seconds);
lcd.clear();
delay(flashOffTime);
printTime();
delay(flashOnTime);
lcd.clear();
delay(flashOffTime);
printTime();
}
void setup() {
//Serial.begin(9600);
lcd.init();
lcd.backlight();
pinMode(clkPin, INPUT);
pinMode(dtPin, INPUT);
pinMode(swPin, INPUT_PULLUP);
pinMode(startPin, INPUT_PULLUP);
pinMode(memoryPinA, INPUT_PULLUP);
pinMode(memoryPinB, INPUT_PULLUP);
pinMode(uvPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(clkPin), encoderISR, LOW);
printTime();
}
void loop() {
static unsigned long lastTime = 0;
unsigned long currentTime = millis();
int timeSum = (hours + minutes + seconds);
static int lastTimeSum;
if (timeSum == 0 && startPinState == true) {
startPinState = false;
digitalWrite(uvPin, LOW);
printTime();
buzz();
}
if (currentTime - lastTime >= 1000) {
if (startPinState == true && timeSum > 0) {
countDown();
digitalWrite(uvPin, HIGH);
lastTime = currentTime;
}
else {
digitalWrite(uvPin, LOW);
}
}
if ((!digitalRead(swPin))) {
toggleHMS();
}
if ((!digitalRead(startPin))) {
startPinState = !startPinState;
while (!digitalRead(startPin))
delay(debounceTime);
}
if (timeSum != lastTimeSum) { //only updates the lcd if the time changes
printTime();
lastTimeSum = timeSum;
}
if ((!digitalRead(memoryPinA))) {
unsigned long buttonStart = millis();
unsigned long buttonEnd;
delay(debounceTime);
while ((!digitalRead(memoryPinA))) {
buttonEnd = millis();
}
if (buttonEnd - buttonStart >= longPressTime) {
updateMemoryA();
}
else {
callMemoryA();
}
startPinState = false;
delay(debounceTime);
}
if ((!digitalRead(memoryPinB))) {
unsigned long buttonStart = millis();
unsigned long buttonEnd;
delay(debounceTime);
while ((!digitalRead(memoryPinB))) {
buttonEnd = millis();
}
if (buttonEnd - buttonStart >= longPressTime) {
updateMemoryB();
}
else {
callMemoryB();
}
startPinState = false;
delay(debounceTime);
}
}
If you see anything in the code that should be done differently, I would certainly appreciate the feedback. Still learning. Thanks in advance!