Hello, I am trying to create a simple control system for one of my implements on a farm. It's a watering system. AI been a great help, i am electronically savvy but not with code. i am looking for help ! i know what i need and want, got parts in, trying to play about with code but to complete the code of what i need i have no clue where to start.
this is what I'm trying to achieve.
list of parts i have
Arduino mega2560R3
16 Relay module (12v)
I2C 20x4 LCD with driver 4 pins (SCL,SDA,VVC,GND)
Still awaiting membrane Buttons to arrive
everything will be powered from an external power source, when tractor ON will be supplying 16ish V tested on LAB bench all is good.
WHAT I NEED TO ACHIEVE
When booted up list of Relays with 2 values displayed and be able to scroll through them but module in constant monitoring of a Momentary switch activation that will start of a pre-set cycle once.
the cycle is determined in code, that i will not need amending ever. as follows:
Relays 1,3,5,7,9,11 activate with their individual presets ofd delay before activation and activation duration before closing.
irrelevant of whats happening in the background after 500ms second group activates 2,4,6,8,10 with their individual presets of delay before activation and activation time.
so in theory if
Selenoid 1 activates with 0 delay for 1000ms
Selenoid 2 activates after group delay of 500ms with 0 delay for 500ms
Both should deactivate at the same time just have diferent activation time. i cant seem to get that in code no matter how i try im just no good with code.
Have menu on LCD that can amend values
- of each individual relay and store on EEPROM.
Opening time xx cs (centiseconds max 100cs )
Offset xx % (range from 0 to 2 seconds)
2)Delay between 2 groups of relays as previously mentioned 500ms, just want to be able to amend value on screen and save to eeprom too - Have additional secret menu after pressing some button for 2 seconds that will let me enter SIMULATION mode. Once selected ON it imitates the poress of the momentary switch that activates then cycle every second or so. or even beter cycles in a loop untill stopped
Now who is up to a challenge ?
-------------------------------------------------UPDATE----------------------------------------------------
//“S”: Starts all delays for the solenoids.
//“6”: Moves the cursor up.
//“4”: Moves the cursor down.
//“8”: Toggles the edit mode.
//“EEPROM RESET”: Resets all EEPROM values to zero.
//“DEFAULT”: Sets the Offsets and Intervals to their default values and saves them to the EEPROM.
//--------------------------------------------------------------------------------------------------------------------------------------------------------
//
// ______ _ _____ _ _ __ ___ _ _
// | ____| | | / ____| | | | | /_ | / _ \ | | | |
// | |__ | | ___ __ __ | | ___ _ __ | |_ _ __ ___ | | __ __ | | | | | | | |__ ___ | |_ __ _
// | __| | | / _ \ \ \ /\ / / | | / _ \ | '_ \ | __| | '__| / _ \ | | \ \ / / | | | | | | | '_ \ / _ \ | __| / _` |
// | | | | | (_) | \ V V / | |____ | (_) | | | | | | |_ | | | (_) | | | \ V / | | _ | |_| | | |_) | | __/ | |_ | (_| |
// |_| |_| \___/ \_/\_/ \_____| \___/ |_| |_| \__| |_| \___/ |_| \_/ |_| (_) \___/ |_.__/ \___| \__| \__,_|
//
//
//
// SSSSSSSSSSSSSSS EEEEEEEEEEEEEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFF
// SS:::::::::::::::S E::::::::::::::::::::E F::::::::::::::::::::F
// S:::::SSSSSS::::::S E::::::::::::::::::::E F::::::::::::::::::::F
// S:::::S SSSSSSS EE::::::EEEEEEEEE::::E FF::::::FFFFFFFFF::::F
// S:::::S E:::::E EEEEEE F:::::F FFFFFF
// S:::::S E:::::E F:::::F
// S::::SSSS E::::::EEEEEEEEEE F::::::FFFFFFFFFF
// SS::::::SSSSS E:::::::::::::::E F:::::::::::::::F
// SSS::::::::SS E:::::::::::::::E F:::::::::::::::F
// SSSSSS::::S E::::::EEEEEEEEEE F::::::FFFFFFFFFF
// S:::::S E:::::E F:::::F
// S:::::S E:::::E EEEEEE F:::::F
// SSSSSSS S:::::S EE::::::EEEEEEEE:::::E FF:::::::FF
// S::::::SSSSSS:::::S E::::::::::::::::::::E F::::::::FF
// S:::::::::::::::SS E::::::::::::::::::::E F::::::::FF
// SSSSSSSSSSSSSSS EEEEEEEEEEEEEEEEEEEEEE FFFFFFFFFFF
//
//-------------------------------------------------------------------------------------------------------------------------------------------------------
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Define the relay pins
const int relayPins[] = {22, 23, 24, 25, 26, 27};
// Define the relay states
int relayStates[] = {LOW, LOW, LOW, LOW, LOW, LOW}; // Start with all relays off
// Define the delay times (in milliseconds)
unsigned long Offsets[] = {EEPROM.read(18)*10, EEPROM.read(21)*10, EEPROM.read(24)*10, EEPROM.read(27)*10, EEPROM.read(30)*10, EEPROM.read(33)*10};
// Define the interval (in milliseconds)
unsigned long Intervals[] = {EEPROM.read(0)*10, EEPROM.read(3)*10, EEPROM.read(6)*10, EEPROM.read(9)*10, EEPROM.read(12)*10, EEPROM.read(15)*10};
// Define the button pins
const int buttonUp = 2;
const int buttonDown = 3;
const int buttonSelect = 4;
// Define the cursor position
volatile int cursorPosition = 0;
// Define the edit mode
volatile bool editMode = false;
// Define LCD update
volatile bool updateLCD = true;
// Define the number of solenoids
const int numSolenoids = 6;
// Define the edit item (0 = Offset, 1 = Opening Time)
volatile int editItem = 0;
class Timer {
private:
unsigned long startTime;
unsigned long interval;
bool running;
public:
Timer(unsigned long interval) {
this->interval = interval;
running = false;
}
void start() {
startTime = millis();
running = true;
}
void stop() {
running = false;
}
bool isRunning() {
return running;
}
bool event() {
if (running && millis() - startTime >= interval) {
startTime = millis(); // reset the start time
return true;
}
return false;
}
};
class Delay {
private:
unsigned long startDTime;
unsigned long delayTime;
bool running;
public:
Delay(unsigned long delayTime) {
this->delayTime = delayTime;
running = false;
}
void start() {
startDTime = millis();
running = true;
}
void stop() {
running = false;
}
bool isRunning() {
return running;
}
bool event() {
if (running && millis() - startDTime >= delayTime) {
startDTime = millis(); // reset the start time
return true;
}
return false;
}
};
// Create timers for each relay
Timer timers[] = {Timer(Intervals[0]), Timer(Intervals[1]), Timer(Intervals[2]), Timer(Intervals[3]), Timer(Intervals[4]), Timer(Intervals[5])};
// Create timer Delays for each relay
Delay Delays[] = {Delay(Offsets[0]), Delay(Offsets[1]), Delay(Offsets[2]), Delay(Offsets[3]), Delay(Offsets[4]), Delay(Offsets[5])};
void setup() {
// Initialize the LCD
lcd.init();
lcd.backlight();
// Bootloader
lcd.setCursor(2, 1);
lcd.print("Bandau Uzsikraut");
lcd.setCursor(0,2);
for (int i = 0; i < 20; ++i) {
lcd.print(".");
delay(200);
}
delay(500);
// Clear screen after loading animation
lcd.clear();
delay(750);
// Set the relay pins as output
for(int i = 0; i < 6; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], relayStates[i]); // Ensure all relays start off
}
// Begin serial communication
Serial.begin(9600);
//Read and print EEPROM values
// Selonoid 1
Serial.println("------------------------------------------------");
Serial.print("Selenoid 1 Opening Time [ ");
Serial.print(EEPROM.read(0)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(18)*10);
Serial.println(" ]");
//Selonoid 2
Serial.print("Selenoid 2 Opening Time [ ");
Serial.print(EEPROM.read(3)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(21)*10);
Serial.println(" ]");
//Selonoid 3
Serial.print("Selenoid 3 Opening Time [ ");
Serial.print(EEPROM.read(6)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(24)*10);
Serial.println(" ]");
//Selonoid 4
Serial.print("Selenoid 4 Opening Time [ ");
Serial.print(EEPROM.read(9)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(27)*10);
Serial.println(" ]");
//Selonoid 5
Serial.print("Selenoid 5 Opening Time [ ");
Serial.print(EEPROM.read(12)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(30)*10);
Serial.println(" ]");
//Selonoid 6
Serial.print("Selenoid 6 Opening Time [ ");
Serial.print(EEPROM.read(15)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(33)*10);
Serial.println(" ]");
Serial.println("------------------------------------------------");
// Attach interrupts to the buttons
attachInterrupt(digitalPinToInterrupt(buttonUp), moveCursorUp, RISING);
attachInterrupt(digitalPinToInterrupt(buttonDown), moveCursorDown, RISING);
attachInterrupt(digitalPinToInterrupt(buttonSelect), toggleEditMode, RISING);
}
void loop() {
// Check for serial input
if(Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim(); // Remove any trailing whitespace
//--------------------------------------------HELP COMMAND IN SERIAL MONITOR--------------------------------------------
if(command == "HELP") {
Serial.println("List of available commands:");
Serial.println("\"S\": Start all delays for the solenoids.");
Serial.println("\"6\": Move the cursor up.");
Serial.println("\"4\": Move the cursor down.");
Serial.println("\"8\": Toggle the edit mode.");
Serial.println("\"EEPROM RESET\": Reset all EEPROM values to zero.");
Serial.println("\"DEFAULT\": Set the Offsets and Intervals to their default values and save them to the EEPROM.");
Serial.println("\"Print\": Prints a table of current values saved on Selonoids.");
//-----------------------------------------------------------------------------------------------------------------------
} else if (command == "S") {
//Report Switch on Serial Monitor
Serial.println("Switch activated");
// Start all delays
for(int i = 0; i < numSolenoids; i++) {
Delays[i].start();
}
} else if (command == "6") {
moveCursorUp();
} else if (command == "4") {
moveCursorDown();
} else if (command == "8") {
toggleEditMode();
} else if(command == "Default") {
// Save Default offsets and intervals to the EEPROM
for (int i = 0; i < numSolenoids; i++) {
if (i == 0 || i == 2 || i == 4) { // Solenoids 1, 3, 5
Offsets[i] = 0;
} else { // The rest of the solenoids
Offsets[i] = 500;
}
Intervals[i] = 60;
EEPROM.update(18 + i * 3, Offsets[i] / 10);
EEPROM.update(i * 3, Intervals[i] / 10);
}
Serial.println("Default Values Saved to EEPROM.");
updateLCD = true; // Set the flag to update the LCD
} else if (command == "EEPROM RESET") {
// Zero out the EEPROM values
for (int i = 0; i < numSolenoids * 2 + 1; i++) {
EEPROM.update(i, 0);
Serial.println("EEPROM VALUES ZEROED");
updateLCD = true; // Set the flag to update the LCD
}
//------------------Print values on command
} else if (command == "Print") {
Serial.println("------------------------------------------------");
Serial.print("Selenoid 1 Opening Time [ ");
Serial.print(EEPROM.read(0)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(18)*10);
Serial.println(" ]");
//Selonoid 2
Serial.print("Selenoid 2 Opening Time [ ");
Serial.print(EEPROM.read(3)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(21)*10);
Serial.println(" ]");
//Selonoid 3
Serial.print("Selenoid 3 Opening Time [ ");
Serial.print(EEPROM.read(6)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(24)*10);
Serial.println(" ]");
//Selonoid 4
Serial.print("Selenoid 4 Opening Time [ ");
Serial.print(EEPROM.read(9)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(27)*10);
Serial.println(" ]");
//Selonoid 5
Serial.print("Selenoid 5 Opening Time [ ");
Serial.print(EEPROM.read(12)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(30)*10);
Serial.println(" ]");
//Selonoid 6
Serial.print("Selenoid 6 Opening Time [ ");
Serial.print(EEPROM.read(15)*10);
Serial.print(" ] Offset [ ");
Serial.print(EEPROM.read(33)*10);
Serial.println(" ]");
Serial.println("------------------------------------------------");
updateLCD = true; // Set the flag to update the LCD
//-----------------------------------------
}
}
// Update the relays
for(int i = 0; i < numSolenoids; i++) {
if(Delays[i].event()) {
// Start the timer after the delay
timers[i].start();
relayStates[i] = HIGH; // Turn on the relay
digitalWrite(relayPins[i], relayStates[i]);
Delays[i].stop(); // Stop the delay after one cycle
}
if(timers[i].event()) {
// Change the state of the relay
relayStates[i] = LOW; // Turn off the relay
digitalWrite(relayPins[i], relayStates[i]);
timers[i].stop(); // Stop the timer after one cycle
}
}
// Update the LCD if needed
if (updateLCD) {
lcd.clear();
lcd.setCursor(5, 0);
lcd.print("Selonoid ");
lcd.print(cursorPosition + 1);
lcd.setCursor(0, 1);
lcd.print("Offset : ");
if (editMode && editItem == 0) {
lcd.print("<< ");
lcd.print(Offsets[cursorPosition]/10);
lcd.print(" >> %");
} else {
lcd.print(Offsets[cursorPosition]/10);
lcd.print(" %");
}
lcd.setCursor(0, 2);
lcd.print("Opening: ");
if (editMode && editItem == 1) {
lcd.print("<< ");
lcd.print(Intervals[cursorPosition]/10);
lcd.print(" >> cs");
} else {
lcd.print(Intervals[cursorPosition]/10);
lcd.print(" cs");
}
updateLCD = false; // Reset the flag
}
}
void moveCursorUp() {
if (editMode) {
// Increment the value of the selected item
if (editItem == 0) {
Offsets[cursorPosition] = min(1500, Offsets[cursorPosition] + 10);
} else {
Intervals[cursorPosition] += 10;
}
} else {
// Move the cursor up
cursorPosition = max(0, cursorPosition + 1);
}
updateLCD = true; // Set the flag to update the LCD
}
void moveCursorDown() {
if (editMode) {
// Decrement the value of the selected item
if (editItem == 0) {
Offsets[cursorPosition] = max(0, Offsets[cursorPosition] - 10);
} else {
Intervals[cursorPosition] = max(0, Intervals[cursorPosition] - 10);
}
} else {
// Move the cursor down
cursorPosition = min(numSolenoids - 1, cursorPosition - 1);
}
updateLCD = true; // Set the flag to update the LCD
}
void toggleEditMode() {
if (editMode) {
// Switch to the next item to edit
editItem = (editItem + 1) % 2;
if (editItem == 0) {
// If we've cycled back to the first item, exit edit mode and display a "Saved" message
editMode = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("*******************");
lcd.setCursor(5, 1);
lcd.print("Selonoid ");
lcd.print(cursorPosition + 1);
lcd.setCursor(7, 2);
lcd.print("Saved!");
lcd.setCursor(0, 3);
lcd.print("*******************");
//---------------------First try EEPROM UPDATE
for (int i = 0; i < numSolenoids; i++) {
EEPROM.update(18 + i * 3, Offsets[i] / 10);
EEPROM.update(i * 3, Intervals[i] / 10);
}
Serial.println("Values saved to EEPROM.");
//--------------------------------------------
delay(2000); // Time on screen
}
} else {
// Enter edit mode
editMode = true;
}
updateLCD = true; // Set the flag to update the LCD
}