I'm not sure if I should start a new post or continue this discussion here but here it goes:
I have a working code based on this post, it does what I want but I have a small issue with it that I don't know how to fix. Basically, when the timer is set it is adds seconds to the timer that aren't called for. For Example: I set it for 1 minute and it goes to 1 minute and 3 seconds, the more time I add the more extra seconds are added.
Second question: I did testing using an Arduino Uno but wanted to use an Arduino Nano Every for the final project, the issue is I have been told they aren't compatible to exchange codes? Is there a simple solution to allow this to work with the Every without rewriting the whole code? I've attached it below
Blockquote
#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSerif9pt7b.h>
#define Enter_button 2
#define Back_button 3
#define Upp_button 4
#define Down_button 5
#define Pump_pin 11
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
struct Time_Settings {
uint8_t set_flag = 0;
unsigned long Startup_Delay_value = 0;
unsigned long Pump_Interval_value = 0;
unsigned long Pump_Duration_value = 0;
} timers;
enum startup_setting {
last_config = 0,
change_setting = 1
};
enum timer_setting {
startup_delay = 0,
pump_interval = 1,
pump_duration = 2,
save_and_exit = 3
};
enum setting {
startup_settings = 0,
timer_settings = 1,
time_settings = 2
};
enum time_setting {
hour = 0,
minute = 1,
second = 2
};
enum system_stage {
settings_stage = 0,
info_stage = 1,
running_stage = 2
};
volatile uint8_t delay_Interval_h = 0;
volatile uint8_t delay_Interval_m = 0;
volatile uint8_t delay_Interval_s = 0;
volatile uint8_t Pump_Interval_h = 0;
volatile uint8_t Pump_Interval_m = 0;
volatile uint8_t Pump_Interval_s = 0;
volatile uint8_t Pump_Duration_h = 0;
volatile uint8_t Pump_Duration_m = 0;
volatile uint8_t Pump_Duration_s = 0;
volatile byte startup_menu_level = 0;
volatile byte timer_menu_level = 0;
volatile byte timer_submenu_level = 0;
volatile byte menu_level = 0;
volatile unsigned long Startup_Delay_value_copy = 0;
volatile unsigned long Pump_Interval_value_copy = 0;
volatile unsigned long Pump_Duration_value_copy = 0;
volatile uint8_t system_mode = 0;
volatile byte intervalCountDown_flag = 0;
volatile byte pumping_flag = 0;
volatile byte display_flag = 0;
volatile byte setting_flag = 0;
volatile byte delay_flag = 0;
// variables to hold old state of buttons
byte Upp_button_OldState = LOW;
byte Down_button_OldState = LOW;
// variables to hold new state of buttons
byte Upp_button_NewState = LOW;
byte Down_button_NewState = LOW;
ISR(TIMER1_COMPA_vect) {
if (!delay_flag) {
Startup_Delay_value_copy--;
if (Startup_Delay_value_copy <= 0) {
intervalCountDown_flag = 1;
delay_flag = 1;
}
}
if (delay_flag && intervalCountDown_flag) {
Pump_Interval_value_copy--;
if (Pump_Interval_value_copy <= 0) {
Pump_Interval_value_copy = timers.Pump_Interval_value;
intervalCountDown_flag = 0;
pumping_flag = 1;
display_flag = 1;
digitalWrite(Pump_pin, LOW);
}
}
if (delay_flag && pumping_flag) {
Pump_Duration_value_copy--;
if (Pump_Duration_value_copy <= 0) {
Pump_Duration_value_copy = timers.Pump_Duration_value;
pumping_flag = 0;
intervalCountDown_flag = 1;
display_flag = 1;
digitalWrite(Pump_pin, HIGH);
}
}
}
void Config_interrupt(void) {
//set timer1 interrupt at 1Hz
cli();//stop interrupts
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1hz increments
OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
}
void setup() {
Serial.begin(115200);
pinMode(Enter_button, INPUT_PULLUP);
pinMode(Upp_button, INPUT_PULLUP);
pinMode(Down_button, INPUT_PULLUP);
pinMode(Back_button, INPUT_PULLUP);
pinMode(Pump_pin, OUTPUT);
digitalWrite(Pump_pin, HIGH);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
Config_interrupt();
attachInterrupt(digitalPinToInterrupt(Enter_button), Enter_Function , FALLING);
attachInterrupt(digitalPinToInterrupt(Back_button), Back_Function , FALLING);
//read initial state of buttons
Upp_button_OldState = digitalRead(Upp_button);
Down_button_OldState = digitalRead(Down_button);
//load timer settings
Load_settings();
if (timers.set_flag == 20)setting_flag = 1;
else {
setting_flag = 0;
Startup_Delay_value_copy = 100;
}
//display welcome message
WelcomeScreen();
startup(startup_menu_level);
}
void loop() {
if (system_mode != running_stage) {
if (system_mode == info_stage) {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 10);
display.print("No setting save yet");
display.display();
delay(1);
}
else {
readButtons();
switch (menu_level) {
case startup_settings:
startup(startup_menu_level);
break;
case timer_settings:
Menu_settings(timer_menu_level);
break;
case time_settings:
if (timer_menu_level == startup_delay) {
set_startup_timer(timer_submenu_level);
}
if (timer_menu_level == pump_interval) {
set_interval_timer(timer_submenu_level);
}
if (timer_menu_level == pump_duration) {
set_duration_timer(timer_submenu_level);
}
if (timer_menu_level == save_and_exit) {
menu_level = startup_settings;
Save_and_Exit();
}
break;
}
}
}
else {
if (!delay_flag) {
compute_TimeParameters();
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(10, 1); // Start at top-left corner
display.println(F("Delay Countdown"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(30, 16); // Start at top-left corner
display.print(delay_Interval_h);
display.print(F(":"));
display.print(delay_Interval_m);
display.print(F(":"));
display.print(delay_Interval_s);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
}
if (delay_flag && pumping_flag) {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(22, 10);
display.print("Pumping...");
display.display();
delay(1);
display_flag = 0;
}
if (delay_flag && intervalCountDown_flag) {
compute_TimeParameters();
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(10, 1); // Start at top-left corner
display.println(F("Will start Pump in"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(30, 16); // Start at top-left corner
display.print(Pump_Interval_h);
display.print(F(":"));
display.print(Pump_Interval_m);
display.print(F(":"));
display.print(Pump_Interval_s);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
display_flag = 0;
}
}
}
void Save_and_Exit() {
copy_variables_to_timers();
EEPROM.put(0, timers);
}
void Load_settings() {
EEPROM.get(0, timers);
copy_timers_to_variables();
}
void readButtons() {
Upp_button_NewState = digitalRead(Upp_button);
Down_button_NewState = digitalRead(Down_button);
//check if there is change of state from low to high for button 1
if (Upp_button_NewState != Upp_button_OldState && Upp_button_OldState) {
switch (menu_level) {
case startup_settings:
startup_menu_level = 0;
startup(startup_menu_level);
break;
case timer_settings:
if (timer_menu_level > 0)timer_menu_level--;
break;
case time_settings:
switch (timer_menu_level) {
case startup_delay:
if (timer_submenu_level == hour)Startup_Delay_value_copy += 3600;
if (timer_submenu_level == minute)Startup_Delay_value_copy += 60;
//copy_timers_to_variables();
set_startup_timer(timer_submenu_level);
break;
case pump_interval:
if (timer_submenu_level == hour)Pump_Interval_value_copy += 3600;
if (timer_submenu_level == minute)Pump_Interval_value_copy += 60;
//copy_timers_to_variables();
set_interval_timer(timer_submenu_level);
break;
case pump_duration:
//if (timer_submenu_level == hour)Pump_Duration_value_copy += 3600;
//if (timer_submenu_level == minute)Pump_Duration_value_copy += 60;
if (timer_submenu_level == 0)Pump_Duration_value_copy += 1;
//copy_timers_to_variables();
set_duration_timer(timer_submenu_level);
break;
default: break;
}
break;
default: break;
}
}
//check if there is change of state from low to high for button 2
if (Down_button_NewState != Down_button_OldState && Down_button_OldState) {
switch (menu_level) {
case startup_settings:
startup_menu_level = 1;
startup(startup_menu_level);
break;
case timer_settings:
if (timer_menu_level < 3)timer_menu_level++;
break;
case time_settings:
switch (timer_menu_level) {
case startup_delay:
if (timer_submenu_level == hour && Startup_Delay_value_copy >= 3600)Startup_Delay_value_copy -= 3600;
if (timer_submenu_level == minute && Startup_Delay_value_copy >= 60)Startup_Delay_value_copy -= 60;
//copy_timers_to_variables();
set_startup_timer(timer_submenu_level);
break;
case pump_interval:
if (timer_submenu_level == hour && Pump_Interval_value_copy >= 3600)Pump_Interval_value_copy -= 3600;
if (timer_submenu_level == minute && Pump_Interval_value_copy >= 60)Pump_Interval_value_copy -= 60;
//copy_timers_to_variables();
set_interval_timer(timer_submenu_level);
break;
case pump_duration:
//if (timer_submenu_level == hour && Pump_Duration_value_copy >= 3600)Pump_Duration_value_copy -= 3600;
//if (timer_submenu_level == minute && Pump_Duration_value_copy >= 60)Pump_Duration_value_copy -= 60;
if (timer_submenu_level == 0 && Pump_Duration_value_copy >= 1)Pump_Duration_value_copy -= 1;
//copy_timers_to_variables();
set_duration_timer(timer_submenu_level);
break;
default: break;
}
break;
default: break;
}
}
Upp_button_OldState = Upp_button_NewState;
Down_button_OldState = Down_button_NewState;
delay(100);
}
void copy_timers_to_variables() {
Startup_Delay_value_copy = timers.Startup_Delay_value;
Pump_Interval_value_copy = timers.Pump_Interval_value;
Pump_Duration_value_copy = timers.Pump_Duration_value;
}
void copy_variables_to_timers() {
timers.set_flag = 20;
timers.Startup_Delay_value = Startup_Delay_value_copy;
timers.Pump_Interval_value = Pump_Interval_value_copy ;
timers.Pump_Duration_value = Pump_Duration_value_copy;
}
void compute_TimeParameters() {
delay_Interval_h = Startup_Delay_value_copy / 3600;
delay_Interval_m = ((Startup_Delay_value_copy - ((int)(Startup_Delay_value_copy / 3600) * 3600)) / 60);
delay_Interval_s = ((Startup_Delay_value_copy - ((int)(Startup_Delay_value_copy / 3600) * 3600)) % 60);
Pump_Interval_h = Pump_Interval_value_copy / 3600;
Pump_Interval_m = ((Pump_Interval_value_copy - ((int)(Pump_Interval_value_copy / 3600) * 3600)) / 60);
Pump_Interval_s = ((Pump_Interval_value_copy - ((int)(Pump_Interval_value_copy / 3600) * 3600)) % 60);
Pump_Duration_h = Pump_Duration_value_copy / 3600;
Pump_Duration_m = ((Pump_Duration_value_copy - ((int)(Pump_Duration_value_copy / 3600) * 3600)) / 60);
Pump_Duration_s = ((Pump_Duration_value_copy - ((int)(Pump_Duration_value_copy / 3600) * 3600)) % 60);
}
void Enter_Function() {
switch (menu_level) {
case startup_settings:
if (startup_menu_level == last_config) {
if (setting_flag) {
system_mode = running_stage;
delay_flag = 0;
intervalCountDown_flag = 1;
}
else system_mode = info_stage;
}
if (startup_menu_level == change_setting) {
menu_level = timer_settings;
system_mode = settings_stage;
}
break;
case timer_settings:
menu_level = time_settings;
break;
case time_settings:
timer_submenu_level++;
if (timer_submenu_level == 2 && (timer_menu_level == 0 || timer_menu_level == 1)) {
menu_level = timer_settings;
timer_submenu_level = 0;
}
if (timer_submenu_level == 1 && timer_menu_level == 2) {
menu_level = timer_settings;
timer_submenu_level = 0;
}
break;
default: break;
}
}
void Back_Function() {
switch (menu_level) {
case timer_settings:
menu_level = startup_settings;
break;
case time_settings:
menu_level = timer_settings;
break;
default: break;
}
if (system_mode == info_stage) {
system_mode = settings_stage;
}
}
void WelcomeScreen(void) {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(22, 10);
display.print("WELCOME");
display.display();
delay(2000);
}
void startup(int option) {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 4); // Start at top-left corner
display.println(F("Last save settings"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 18); // Start at top-left corner
display.println(F("New settings"));
display.setTextColor(SSD1306_WHITE); // Draw white text
switch (option) {
case 0:
display.drawRect(5, 1, display.width() - 10, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 1:
display.drawRect(5, 15, display.width() - 10, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
default:
break;
}
display.display();
}
void Menu_settings(int option) {
display.clearDisplay();
switch (option) {
case 0:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 4); // Start at top-left corner
display.println(F("Delay Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 18); // Start at top-left corner
display.println(F("Interval Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.drawRect(5, 1, display.width() - 40, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 1:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 4); // Start at top-left corner
display.println(F("Delay Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 18); // Start at top-left corner
display.println(F("Interval Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.drawRect(5, 15, display.width() - 40, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 2:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 4); // Start at top-left corner
display.println(F("Interval Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 18); // Start at top-left corner
display.println(F("Pump Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.drawRect(5, 15, display.width() - 40, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 3:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 4); // Start at top-left corner
display.println(F("Pump Timer"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(8, 18); // Start at top-left corner
display.println(F("Save and exit"));
display.setTextColor(SSD1306_WHITE); // Draw white text
display.drawRect(5, 15, display.width() - 40, 13, SSD1306_WHITE);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
default:
break;
}
display.display();
//delay(1000);
}
void set_startup_timer(int setting_level) {
display.clearDisplay();
compute_TimeParameters();
switch (setting_level) {
case 0:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 1); // Start at top-left corner
display.println(F("Delay Hour"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 16); // Start at top-left corner
display.println(delay_Interval_h);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 1:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 1); // Start at top-left corner
display.println(F("Delay minute"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 16); // Start at top-left corner
display.println(delay_Interval_m);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
default:
break;
}
display.display();
}
void set_interval_timer(int setting_level) {
compute_TimeParameters();
display.clearDisplay();
switch (setting_level) {
case 0:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 1); // Start at top-left corner
display.println(F("Interval Hour"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 16); // Start at top-left corner
display.println(Pump_Interval_h);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
case 1:
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 1); // Start at top-left corner
display.println(F("Interval minute"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 16); // Start at top-left corner
display.println(Pump_Interval_m);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
break;
default:
break;
}
display.display();
}
void set_duration_timer(int setting_level) {
compute_TimeParameters();
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(36, 1); // Start at top-left corner
display.println(F("Pump time(s)"));
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(56, 16); // Start at top-left corner
display.println(Pump_Duration_s);
display.display(); // Update screen with each newly-drawn rectangle
delay(1);
display.display();
}
Sprayer.ino (21.3 KB)