Hello , i have been at this for a while now , in essence the code works but it shows some unexpected behaviour on the configbutton
so as it is , not every short press of the configbutton changes the firemode, most of the times it does but lets say 1in5 it doesnt do anything
when it is in programming mode , a short press doesnt allways changes the selected settings and it will exit programming mode on a short press randomly.
i case anybody was wondering this is a program to control a solenoid of a HPA airsoft engine
i am all out of ideas , if anybody can help me out here that would be greatly appreciated
#include <EEPROM.h>
// Define pin assignments
const int triggerPin = 2; // Pin connected to trigger switch
const int solenoidPin = 3; // Pin connected to solenoid valve
const int configButton = 5; // Pin used for programming & fire mode selection
const int feedbackLED = 4; // Pin connected to LED for feedback
// Define adjustable settings with predefined values
const int dwellTimes[] = {7, 6, 7, 8, 9, 10, 11, 12, 13, 14};
const int fireRates[] = {20, 9, 12, 15, 18, 20, 23, 26, 29, 33};
const int dmrCooldowns[] = {1000, 800, 600, 400, 200};
const int burstLengths[] = {3, 3, 4, 5, 6, 7};
// Define adjustable parameter indexes (loaded from EEPROM at startup)
int dwellTimeIndex;
int fireRateIndex;
int dmrCooldownIndex;
int burstLengthIndex;
// Define fire mode types
enum FireMode { SEMI_AUTO, BURST_MODE, FULL_AUTO, DMR_MODE, BINARY_MODE };
FireMode fireMode = SEMI_AUTO;
// Define adjustable setting types
enum Setting { DWELL_TIME, FIRE_RATE, DMR_COOLDOWN, BURST_LENGTH };
Setting selectedSetting = DWELL_TIME; // Default selection
// Define control variables
bool inProgrammingMode = false; // Dedicated flag to track if we're in programming mode
bool modeactive = false;
bool buttonPressed = false;
bool triggerPressed = false;
bool triggerReleased = true; // Tracks trigger release in Binary Mode
unsigned long buttonPressStart = 0;
unsigned long lastFireTime = 0;
unsigned long modeactivetime = 0;
void setup() {
Serial.begin(9600); // Initialize serial communication
Serial.println("FCU Booting...");
Serial.println("loading settings");
//read eeprom and set values on first boot
dwellTimeIndex = EEPROM.read(1);
fireRateIndex = EEPROM.read(2);
dmrCooldownIndex = EEPROM.read(3);
burstLengthIndex = EEPROM.read(4);
Serial.println(dwellTimeIndex);
Serial.println(fireRateIndex);
Serial.println(dmrCooldownIndex);
Serial.println(burstLengthIndex);
if (dwellTimeIndex == 255) {
dwellTimeIndex = 0;
}
if (fireRateIndex == 255) {
fireRateIndex = 0;
}
if (dmrCooldownIndex == 255) {
dmrCooldownIndex = 0;
}
if (burstLengthIndex == 255) {
burstLengthIndex = 0;
}
// Set pin modes
pinMode(triggerPin, INPUT_PULLUP);
pinMode(solenoidPin, OUTPUT);
pinMode(configButton, INPUT_PULLUP);
pinMode(feedbackLED, OUTPUT);
// Default states
digitalWrite(solenoidPin, LOW);
digitalWrite(feedbackLED, LOW);
}
void loop() {
unsigned long currentTime = millis();
// Handle button press (Short press cycles fire mode, long press enters programming mode)
if (digitalRead(configButton) == LOW) {
// Serial.println("buttonreleased");
if (!buttonPressed) {
buttonPressed = true;
buttonPressStart = millis();
}
// Long press (2 sec) enters programming mode
if (buttonPressed && (millis() - buttonPressStart > 2000) && !inProgrammingMode) {
inProgrammingMode = true; // Keep this flag separate from button state
Serial.println("Entered Programming Mode");
modeactive = true;
modeactivetime = millis();
blinkLED(20, 50);
}
}
else {
// Short press cycles **fire mode** if programming mode is NOT active
if (buttonPressed && (millis() - buttonPressStart < 2000) && !inProgrammingMode) {
fireMode = static_cast<FireMode>((fireMode + 1) % 5);
Serial.print("Fire Mode Changed: ");
switch (fireMode) {
case SEMI_AUTO:
Serial.println("Semi-Auto");
blinkLED(1, 150);
break;
case BURST_MODE:
Serial.println("Burst Mode");
blinkLED(2, 150);
break;
case FULL_AUTO:
Serial.println("Full Auto");
blinkLED(3, 150);
break;
case DMR_MODE:
Serial.println("DMR Mode");
blinkLED(4, 150);
break;
case BINARY_MODE:
Serial.println("Binary Mode");
blinkLED(5, 150);
break;
}
}
// Short press cycles settings **only if programming mode is active**
if (buttonPressed && (millis() - buttonPressStart < 2000) && inProgrammingMode) {
selectedSetting = static_cast<Setting>((selectedSetting + 1) % 4);
Serial.println("Selected Setting: ");
Serial.println(selectedSetting);
modeactivetime = millis();
blinkLED(selectedSetting + 1, 250);
}
// If programming mode is active and long press detected again, exit mode
if (inProgrammingMode && (millis() - buttonPressStart > 2000)) {
if (buttonPressed && (millis() - modeactivetime > 5000)){
inProgrammingMode = false;
Serial.println("Exiting Programming Mode");
Serial.println("storing in EEPROM");
EEPROM.write(1, dwellTimeIndex);
EEPROM.write(2, fireRateIndex);
EEPROM.write(3, dmrCooldownIndex);
EEPROM.write(4, burstLengthIndex);
blinkLED(3, 500);
}
}
}
// Adjust selected setting using trigger press in programming mode
if (inProgrammingMode && digitalRead(triggerPin) == LOW && !triggerPressed) {
Serial.println("adjusting setting"); \
switch (selectedSetting) {
case DWELL_TIME:
dwellTimeIndex = (dwellTimeIndex + 1) % 10;
Serial.println("dwellTimeIndex");
Serial.println(dwellTimeIndex);
blinkLED(dwellTimeIndex + 1, 250);
break;
case FIRE_RATE:
fireRateIndex = (fireRateIndex + 1) % 10;
Serial.println("fireRateIndex");
Serial.println(fireRateIndex);
blinkLED(fireRateIndex + 1, 250);
break;
case DMR_COOLDOWN:
dmrCooldownIndex = (dmrCooldownIndex + 1) % 5;
Serial.println("dmrCooldownIndex");
Serial.println(dmrCooldownIndex);
blinkLED(dmrCooldownIndex + 1, 250);
break;
case BURST_LENGTH:
burstLengthIndex = (burstLengthIndex + 1) % 6;
Serial.println("burstLengthIndex");
Serial.println(burstLengthIndex);
blinkLED(burstLengthIndex + 1, 250);
break;
}
}
// Solenoid control based on selected fire mode
if (!inProgrammingMode && digitalRead(triggerPin) == LOW) {
if (currentTime - lastFireTime >= 1000 / fireRates[fireRateIndex]) {
lastFireTime = currentTime;
switch (fireMode) {
case SEMI_AUTO:
if (triggerReleased) {
fireShot(dwellTimes[dwellTimeIndex]); // Fire on pull
triggerReleased = false; // Reset after firing
}
break;
case BURST_MODE:
if (triggerReleased) { // Ensure trigger was released before firing
triggerReleased = false; // Mark trigger as "not released"
for (int i = 0; i < burstLengths[burstLengthIndex]; i++) {
fireShot(dwellTimes[dwellTimeIndex]);
delay(1000 / fireRates[fireRateIndex]); // Maintain fire rate timing
}
}
break;
case FULL_AUTO:
fireShot(dwellTimes[dwellTimeIndex]);
break;
case DMR_MODE:
if (triggerReleased) { // Ensure trigger was released before firing
triggerReleased = false; // Mark trigger as "not released"
fireShot(dwellTimes[dwellTimeIndex]);
delay(dmrCooldowns[dmrCooldownIndex]);
}
break;
case BINARY_MODE:
if (triggerReleased) {
fireShot(dwellTimes[dwellTimeIndex]); // Fire on pull
triggerReleased = false;
}
break;
}
}
if (!inProgrammingMode && digitalRead(triggerPin) == HIGH && fireMode == BINARY_MODE && !triggerReleased) {
fireShot(dwellTimes[dwellTimeIndex]); // Fire on release
triggerReleased = true;
}
}
//Serial.println(modeactivetime);
if (digitalRead(configButton) == HIGH) {
buttonPressed = false;
// Serial.println("buttonreleased");
}
if (digitalRead(triggerPin) == HIGH) {
triggerReleased = true; // Set to true when trigger is released
}
}
// Function to activate solenoid
void fireShot(int dwell) {
digitalWrite(solenoidPin, HIGH);
delay(dwell);
digitalWrite(solenoidPin, LOW);
Serial.println("pew");
}
// Function to blink LED for feedback
void blinkLED(int times, int delayTime) {
for (int i = 0; i < times; i++) {
digitalWrite(feedbackLED, HIGH);
delay(delayTime);
digitalWrite(feedbackLED, LOW);
delay(delayTime);
}
}