thanks for the advise i redo the high voltage traces as you suggested. and my board is one layer. maybe i can make it 2 layer. if there is any other suggestion i appreciate it. and what do you think about the setup of the relays.
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ACS712.h>
#include <EEPROM.h>
#include "DisplayController.h"
// Pin definitions for sensors, relays, buttons and rf module
const int PIN_SENSOR_RIGHT = A1;
const int PIN_SENSOR_LEFT = A0;
const int PIN_BUZZER = 2;
const int PIN_RF_OPEN = 3;
const int PIN_RF_CLOSE = 4;
const int PIN_RF_STOP = 5;
const int PIN_BUTTON_UP = 6;
const int PIN_BUTTON_DOWN = 7;
const int PIN_BUTTON_SELECT = 8;
const int PIN_RELAY_RIGHT_DIRECTION = 9;
const int PIN_RELAY_RIGHT_POWER = 10;
const int PIN_RELAY_LEFT_POWER = 11;
const int PIN_RELAY_LEFT_DIRECTION = 12;
// Define EEPROM addresses for storing settings
const int STALL_TIME_ADDRESS = 0;
const int CURRENT_SENSOR_ON_ADDRESS = 2;
const int OPENING_R_THRESHOLD_ADDRESS = 3;
const int OPENING_L_THRESHOLD_ADDRESS = 7;
const int CLOSING_R_THRESHOLD_ADDRESS = 11;
const int CLOSING_L_THRESHOLD_ADDRESS = 15;
// Define menu items as strings stored in program memory
const char chrMainMenu[] PROGMEM = "Main Menu";
const char chrRightActuator[] PROGMEM = "Right Actuator";
const char chrLeftActuator[] PROGMEM = "Left Actuator";
const char chrStallTime[] PROGMEM = "Stall Time sec";
const char chrCurrentSensor[] PROGMEM = "Current Sensor";
const char chrExit[] PROGMEM = "Exit";
const char chrOThreshold[] PROGMEM = "O.Threshold";
const char chrCThreshold[] PROGMEM = "C.Threshold";
// Index definitions for menu items
const int STALL_TIME_INDEX = 2;
const int CURRENT_SENSOR_ON_INDEX = 3;
const int OPENING_R_THRESHOLD_INDEX = 5;
const int OPENING_L_THRESHOLD_INDEX = 8;
const int CLOSING_R_THRESHOLD_INDEX = 6;
const int CLOSING_L_THRESHOLD_INDEX = 9;
// Menu items definition
MenuItem Menu_Items[] = {
/*Main menu page*/
/*00*/{chrRightActuator, MenuItem::PAGE, {.intValue = 2}},
/*01*/{chrLeftActuator, MenuItem::PAGE, {.intValue = 3}},
/*02*/{chrStallTime, MenuItem::INT, {.intValue = 3}, {.intMin = 0}, {.intMax = 10}},
/*03*/{chrCurrentSensor, MenuItem::BOOL, {.boolValue = false}},
/*04*/{chrExit, MenuItem::PAGE, {.intValue = 0}},
/* Right Actuator menu page*/
/*05*/{chrOThreshold, MenuItem::FLOAT, {.floatValue = 1.10}, {.floatMin = 0.500}, {.floatMax = 5.00}},
/*06*/{chrCThreshold, MenuItem::FLOAT, {.floatValue = 1.10}, {.floatMin = 0.500}, {.floatMax = 5.00}},
/*07*/{chrExit, MenuItem::PAGE, {.intValue = 1}},
/* Left Actuator menu page*/
/*08*/{chrOThreshold, MenuItem::FLOAT, {.floatValue = 1.10}, {.floatMin = 0.500}, {.floatMax = 5.00}},
/*09*/{chrCThreshold, MenuItem::FLOAT, {.floatValue = 1.10}, {.floatMin = 0.500}, {.floatMax = 5.00}},
/*10*/{chrExit, MenuItem::PAGE, {.intValue = 1}},
};
// Menu index definitions
MenuIndex Menu_Index[] = {
{chrMainMenu, 5, 0},
{chrMainMenu, 5, 0},
{chrRightActuator, 3, 5},
{chrLeftActuator, 3, 8},
};
// Display controller initialization
DisplayController displayController;
// Current sensor initializations
ACS712 currentSensor_Right(ACS712_05B, PIN_SENSOR_RIGHT);
ACS712 currentSensor_Left(ACS712_05B, PIN_SENSOR_LEFT);
// Function prototypes
void readFromEEPROM();
void saveToEEPROM();
void rfStateUpdate();
bool debounce(unsigned long& lastDebounceTime);
void buttonHandler();
void currentCheck(float &r_Current, float &l_Current);
void setRelays();
void setBuzzer();
// Actuator states initialization
ActuatorState R_Actuator_State = STOPPED;
ActuatorState L_Actuator_State = STOPPED;
ActuatorState rf_State = STOPPED;
ActuatorState button_State = STOPPED;
const unsigned long DEBOUNCE_TIME = 200; // Constant for debounce timing
unsigned long holdTime;
void setup()
{
Serial.begin(9600); // Start serial communication at 9600 baud
displayController.begin(); // Initialize the display controller
currentSensor_Right.calibrate(); // Calibrate the right current sensor
currentSensor_Left.calibrate(); // Calibrate the left current sensor
// Set pin modes for RF controls and buttons
pinMode(PIN_RF_OPEN, INPUT);
pinMode(PIN_RF_CLOSE, INPUT);
pinMode(PIN_RF_STOP, INPUT);
pinMode(PIN_BUTTON_UP, INPUT_PULLUP);
pinMode(PIN_BUTTON_DOWN, INPUT_PULLUP);
pinMode(PIN_BUTTON_SELECT, INPUT_PULLUP);
// Set pin modes for relays controlling the actuators
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_RELAY_RIGHT_DIRECTION, OUTPUT);
pinMode(PIN_RELAY_RIGHT_POWER, OUTPUT);
pinMode(PIN_RELAY_LEFT_DIRECTION, OUTPUT);
pinMode(PIN_RELAY_LEFT_POWER, OUTPUT);
//
pinMode(LED_BUILTIN, OUTPUT);
/*///////////////////////
EEPROM.put(STALL_TIME_ADDRESS, 3);
EEPROM.put(CURRENT_SENSOR_ON_ADDRESS, true);
EEPROM.put(OPENING_R_THRESHOLD_ADDRESS, 1.20);
EEPROM.put(OPENING_L_THRESHOLD_ADDRESS, 1.20);
EEPROM.put(CLOSING_R_THRESHOLD_ADDRESS, 1.20);
EEPROM.put(CLOSING_L_THRESHOLD_ADDRESS, 1.20);
*///////////////////////
readFromEEPROM(); // Read values from EEPROM
displayController.menu = Menu_Items; // Set the menu items for display
displayController.menuIndex = Menu_Index; // Set the menu index for navigation
Serial.println("Start");
displayController.displayLogo();
int buzzer_State = LOW;
for (int i = 0; i < 10; i++)
{
buzzer_State = !buzzer_State;
digitalWrite(PIN_BUZZER ,buzzer_State);
delay(100);
}
digitalWrite(PIN_BUZZER ,LOW);
}
void loop()
{
float currentRight = currentSensor_Right.getCurrentAC(50);
float currentLeft = currentSensor_Left.getCurrentAC(50);
rfStateUpdate();
buttonHandler();
currentCheck(currentRight, currentLeft);
if (button_State == CLOSING || rf_State == CLOSING)
{
//if (R_Actuator_State != CLOSING || L_Actuator_State != CLOSING)
//{
R_Actuator_State = CLOSING;
L_Actuator_State = CLOSING;
setRelays();
//}
} else if (button_State == OPENING || rf_State == OPENING)
{
//if (R_Actuator_State != OPENING || L_Actuator_State != OPENING)
//{
R_Actuator_State = OPENING;
L_Actuator_State = OPENING;
setRelays();
//}
} else //if (button_State == STOPPED || rf_State == STOPPED)
{
R_Actuator_State = STOPPED;
L_Actuator_State = STOPPED;
setRelays();
}
//setBuzzer();
/*
Serial.print(F("button: "));
Serial.print(button_State == STOPPED ? F("Stopped") : (button_State == CLOSING ? F("Closing") : F("Opening")));
Serial.print(F("\t rf: "));
Serial.print(rf_State == STOPPED ? F("Stopped") : (rf_State == CLOSING ? F("Closing") : F("Opening")));
Serial.print(F("\t r_ac: "));
Serial.print(R_Actuator_State == STOPPED ? F("Stopped") : (R_Actuator_State == CLOSING ? F("Closing") : F("Opening")));
Serial.print(F("\t l_ac: "));
Serial.println(L_Actuator_State == STOPPED ? F("Stopped") : (L_Actuator_State == CLOSING ? F("Closing") : F("Opening")));
*/
if(displayController.Current_Page == MAIN_PAGE){
displayController.displayMainPage(R_Actuator_State, L_Actuator_State, currentRight, currentLeft);
}else {
displayController.displayMenu();
}
}
void rfStateUpdate()
{
static bool prvRfOpenState;
static bool prvRfCloseState;
bool RfOpenState = digitalRead(PIN_RF_OPEN);
bool RfCloseState = digitalRead(PIN_RF_CLOSE);
bool RfStopState = digitalRead(PIN_RF_STOP);
if (RfStopState)
{
rf_State = STOPPED;
}else if(RfCloseState && !prvRfCloseState)
{
rf_State = CLOSING;
}else if(RfOpenState && !prvRfOpenState)
{
rf_State = OPENING;
}
prvRfOpenState = RfOpenState;
prvRfCloseState = RfCloseState;
//Serial.print(rf_State == STOPPED ? F("Stopped") : (rf_State == CLOSING ? F("Closing") : F("Opening")));
}
bool debounce(unsigned long& lastDebounceTime) {
unsigned long currentTime = millis();
if (currentTime - lastDebounceTime > DEBOUNCE_TIME) {
lastDebounceTime = currentTime;
return true;
}
return false;
}
void buttonHandler()
{
static int prv_btnUp_State = HIGH;
static int prv_btnDown_State = HIGH;
int btnUp_State = digitalRead(PIN_BUTTON_UP);
int btnDown_State = digitalRead(PIN_BUTTON_DOWN);
int btnSelect_State = digitalRead(PIN_BUTTON_SELECT);
if (displayController.Current_Page == MAIN_PAGE)
{
if (btnDown_State == LOW && (btnDown_State != prv_btnDown_State))
{
button_State = CLOSING;
rf_State = STOPPED;
}else if (btnUp_State == LOW && (btnUp_State != prv_btnUp_State))
{
button_State = OPENING;
rf_State = STOPPED;
}else if (btnUp_State && btnDown_State)
{
button_State = STOPPED;
}
prv_btnUp_State = btnUp_State;
prv_btnDown_State = btnDown_State;
//Serial.print("btnUp_State");
//Serial.print(btnUp_State);
//Serial.print("\t prv_btnUp_State");
//Serial.println(prv_btnUp_State);
//Serial.print(button_State == STOPPED ? F("Stopped") : (button_State == CLOSING ? F("Closing") : F("Opening")));
} else
{
// handle Up button in menu
if (btnUp_State == LOW)
{
static unsigned long lastDebounceTimeUp = 0;
if (debounce(lastDebounceTimeUp)) {displayController.menuItem_Inc();}
}
// handle Down button in menu
if (btnDown_State == LOW)
{
static unsigned long lastDebounceTimeDown = 0;
if (debounce(lastDebounceTimeDown)) {displayController.menuItem_Dec();}
}
}
// Handle Select button
if (btnSelect_State == LOW)
{
static unsigned long lastDebounceTimeSelect = 0;
if (debounce(lastDebounceTimeSelect))
{
displayController.menuItem_Selc();
if(displayController.ValueChanged())
{
//Serial.println("value changed");
saveToEEPROM();
}
}
}
}
void currentCheck(float &r_Current, float &l_Current)
{
bool current_ON = Menu_Items[CURRENT_SENSOR_ON_INDEX].value.boolValue; // Retrieve the boolean value for the current sensor from the menu items
static unsigned long OverCurStartTime = 0; // Track when the overcurrent condition started
// Proceed only if the current sensor is enabled
if (!current_ON) return;
float r_threshold, l_threshold;
// Check if either actuator is in the OPENING state
if (R_Actuator_State == OPENING || L_Actuator_State == OPENING)
{
// Retrieve the overcurrent thresholds from the menu items
r_threshold = Menu_Items[OPENING_R_THRESHOLD_INDEX].value.floatValue; // Right actuator threshold
l_threshold = Menu_Items[OPENING_L_THRESHOLD_INDEX].value.floatValue; // Left actuator threshold
} else
{
// Retrieve the overcurrent thresholds from the menu items
r_threshold = Menu_Items[CLOSING_R_THRESHOLD_INDEX].value.floatValue; // Right actuator threshold
l_threshold = Menu_Items[CLOSING_L_THRESHOLD_INDEX].value.floatValue; // Left actuator threshold
}
// Compare the current values against the thresholds
if (r_Current > r_threshold || l_Current > l_threshold) //|| fabs(r_Current - l_Current) > 0.1)
{
digitalWrite(PIN_BUZZER ,HIGH);
//if door is Opening imeditally stop the door after over current
if(R_Actuator_State == OPENING || L_Actuator_State == OPENING)
{
// Stop the actuator(s) if current exceeds the threshold
button_State = STOPPED;
rf_State = STOPPED;
digitalWrite(PIN_BUZZER ,LOW);
return;
}
unsigned long currentTime = millis();
unsigned int stallTime = Menu_Items[STALL_TIME_INDEX].value.intValue * 1000;
// If this is the first overcurrent detection, set the start time
if(OverCurStartTime == 0)
{
OverCurStartTime = currentTime;
}
if (currentTime - OverCurStartTime > stallTime)
{
// Stop the actuator(s) if current exceeds the threshold
button_State = STOPPED;
rf_State = STOPPED;
// After stopping, reset the OverCurStartTime to prevent repeated stops
OverCurStartTime = 0; // Reset the timer after stopping
digitalWrite(PIN_BUZZER ,LOW);
}
}else
{
// If current is below the threshold, reset OverCurStartTime
OverCurStartTime = 0; // Reset if the current is normal
}
}
void setRelays()
{
bool rA_O = R_Actuator_State == OPENING ? HIGH : LOW;
digitalWrite(PIN_RELAY_RIGHT_DIRECTION, rA_O); // Set right actuator direction to open
bool lA_O = L_Actuator_State == OPENING ? HIGH : LOW;
digitalWrite(PIN_RELAY_LEFT_DIRECTION, lA_O); // Set left actuator direction to open
delay(200);
bool rA_S = R_Actuator_State != STOPPED ? HIGH : LOW;
digitalWrite(PIN_RELAY_RIGHT_POWER, rA_S); // Power on the right actuator
bool lA_S = L_Actuator_State != STOPPED ? HIGH : LOW;
digitalWrite(PIN_RELAY_LEFT_POWER, lA_S); // Power on the left actuator
/////////
Serial.print("R_Dir; ");
Serial.print(rA_O);
Serial.print("\t L_Dir: ");
Serial.print(lA_O);
Serial.print("\t R_Power: ");
Serial.print(rA_S);
Serial.print("\t L_Power: ");
Serial.println(lA_S);
}
void setBuzzer()
{
static int buzzer_State = LOW;
unsigned long currentTime = millis();
static long prvTime = 0;
unsigned long buzzerDellay = 100;
if(R_Actuator_State == STOPPED && L_Actuator_State == STOPPED)
{
buzzer_State = LOW;
}else
{
if ((currentTime - prvTime) > buzzerDellay )
{
buzzer_State = !buzzer_State;
}
}
digitalWrite(PIN_BUZZER ,buzzer_State);
}
void readFromEEPROM()
{
EEPROM.get(STALL_TIME_ADDRESS, Menu_Items[STALL_TIME_INDEX].value.intValue);
EEPROM.get(CURRENT_SENSOR_ON_ADDRESS, Menu_Items[CURRENT_SENSOR_ON_INDEX].value.boolValue);
EEPROM.get(OPENING_R_THRESHOLD_ADDRESS, Menu_Items[OPENING_R_THRESHOLD_INDEX].value.floatValue);
EEPROM.get(OPENING_L_THRESHOLD_ADDRESS, Menu_Items[OPENING_L_THRESHOLD_INDEX].value.floatValue);
EEPROM.get(CLOSING_R_THRESHOLD_ADDRESS, Menu_Items[CLOSING_R_THRESHOLD_INDEX].value.floatValue);
EEPROM.get(CLOSING_L_THRESHOLD_ADDRESS, Menu_Items[CLOSING_L_THRESHOLD_INDEX].value.floatValue);
}
void saveToEEPROM()
{
int index = displayController.Current_MenuItem;
switch (index)
{
case STALL_TIME_INDEX:
EEPROM.put(STALL_TIME_ADDRESS, Menu_Items[STALL_TIME_INDEX].value.intValue);
break;
case CURRENT_SENSOR_ON_INDEX:
EEPROM.put(CURRENT_SENSOR_ON_ADDRESS, Menu_Items[CURRENT_SENSOR_ON_INDEX].value.boolValue);
break;
case OPENING_R_THRESHOLD_INDEX:
EEPROM.put(OPENING_R_THRESHOLD_ADDRESS, Menu_Items[OPENING_R_THRESHOLD_INDEX].value.floatValue);
break;
case OPENING_L_THRESHOLD_INDEX:
EEPROM.put(OPENING_L_THRESHOLD_ADDRESS, Menu_Items[OPENING_L_THRESHOLD_INDEX].value.floatValue);
break;
case CLOSING_R_THRESHOLD_INDEX:
EEPROM.put(CLOSING_R_THRESHOLD_ADDRESS, Menu_Items[CLOSING_R_THRESHOLD_INDEX].value.floatValue);
break;
case CLOSING_L_THRESHOLD_INDEX:
EEPROM.put(CLOSING_L_THRESHOLD_ADDRESS, Menu_Items[CLOSING_L_THRESHOLD_INDEX].value.floatValue);
break;
default:
break;
}
}
and this is the code