Code changes with the use of buttons

Hi all,
I'm running into a problem and I really can't find where it goes wrong.
Trying to make an fuel injector tester and it is actually working ..almost.

first of all I have this code

#include <U8x8lib.h>
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/U8X8_PIN_NONE);
#define BEEPER 8
#define BUTTON_PIN10 10
#define BUTTON_PIN11 11
#define BUTTON_PIN12 12
#define BUTTON_PIN13 13

int i = 0;                                                                    // counter for "pages"
int pags[5] = { 0, 6, 800, 5, 10 };                                           // array for page values
String pag[5] = { "PAIRED", "# INJECTORS", "RPM", "DUTY CYCLE %", "TIMER" };  // page titles
int selection = 0;                                                            // pointer for walking trough the arrays above
int countdown = 1;                                                            // seconds for countdown clock                            (adjustable)
int countdownCounter = 0;                                                     // used to count down :p
unsigned long countdownCounterStart;
int c = 0;                            // counter for running
int countTill;                        // copy of c ( devided by 2 (paired))
unsigned long a = 0;                  // counter that keeps track of openings per injector
unsigned long runTime = 0;            // keeps track of (new) time for the global timer
int pinRay[] = { 2, 3, 4, 5, 6, 7 };  // array with pins to drive the injectors
bool pinPower = false;                // boolean that stores if a pin is powered                  (prevents closing injectors multiple times in the loop)
float MPR;                            // millisecs per revolution                                 (determined by RPM in loop())
float openTime = 0.00;                // time an injector is open                                 (determined by MPR and dutyCycle in loop())
//unsigned long nextClosingTime = 0;   // time that the open injector must close
float nextClosingTime = 0;                     // time that the open injector must close
bool running = false;                          // the sequence is running when true, sequence will stop after all (connected) injectors finished the loop
bool stopCalled = false;                       // called to kill running
unsigned long lastTimeButtonStateChanged = 0;  //debounce start stop btn
bool mayBeep = false;                          // used to "TIME" the beeper after a timed loop..

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN13, INPUT);
  pinMode(BUTTON_PIN12, INPUT);
  pinMode(BUTTON_PIN11, INPUT);
  pinMode(BUTTON_PIN10, INPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);  //beeper
  u8x8.begin();
  u8x8.setPowerSave(0);
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.setInverseFont(1);
  u8x8.drawString(0, 0, "RagR Builds    ");
  u8x8.setInverseFont(0);
}

void loop() {
  byte buttonState10 = digitalRead(BUTTON_PIN10);
  byte buttonState11 = digitalRead(BUTTON_PIN11);
  byte buttonState12 = digitalRead(BUTTON_PIN12);
  byte buttonState13 = digitalRead(BUTTON_PIN13);
  if (pags[0] == 1) {                   //if paired
    MPR = 1000 / ((pags[2] / 2) / 60);  //milliSecs Per Revolution
    countTill = (pags[1] - 1) / 2;
  } else {
    MPR = 1000 / (pags[2] / 60);  //milliSecs Per Revolution
    countTill = pags[1] - 1;
  }
  openTime = (MPR / 100) * pags[3];  //percent from dutyCycle

  /*---------------------------------------------------------------------------------------------------- cycle trough pages--*/
  if (buttonState12 == HIGH) {
    //pages
    i++;
    if (i >= 5) {
      i = 0;
    }
    selection = i;
    u8x8.setCursor(0, 2);
    u8x8.clearLine(2);
    u8x8.clearLine(3);
    u8x8.clearLine(4);
    u8x8.clearLine(5);
    u8x8.clearLine(6);
    u8x8.println((String)pag[i]);
    u8x8.setCursor(0, 4);
    u8x8.clearLine(4);

    if (i == 4) {  // show formatted countdown time
      u8x8.println(formatTime(pags[4]));
    } else {
      u8x8.println((String)pags[i]);
    }

    delay(250);
  }
  /*---------------------------------------------------------------------------------------------------- BTN MINUS--*/
  if (buttonState10 == HIGH) {
    u8x8.clearLine(3);
    u8x8.clearLine(4);

    //pair injectors (N)
    if (i == 0) {
      pags[0] = 0;
      u8x8.clearLine(3);
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String) "not paired");
      delay(300);
    }
    //amountInjectors
    if (i == 1) {
      pags[1]--;
      if (pags[1] <= 1) {
        pags[1] = 1;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String)pags[i]);
      delay(300);
    }
    //RPM
    if (i == 2) {
      pags[2] -= 50;
      if (pags[2] < 550) {
        pags[2] = 550;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String)pags[i]);
      delay(100);
    }
    //dutyCycle
    if (i == 3) {
      pags[3]--;
      if (pags[3] <= 1) {
        pags[3] = 1;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println(pags[i]);
      delay(100);
    }
    //countdown
    if (i == 4) {
      pags[4]--;
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println(formatTime(pags[4]));
      delay(100);
    }
  }

  /*---------------------------------------------------------------------------------------------------- BTN PLUS--*/
  if (buttonState11 == HIGH) {
    u8x8.clearLine(3);
    u8x8.clearLine(4);
    //pairen (Y/N)
    if (i == 0) {
      if (pags[1] % 2 != 0) {
        pags[0] = 0;
        u8x8.setCursor(0, 3);
        u8x8.clearLine(3);
        u8x8.println((String) "cant pair");
        u8x8.setCursor(0, 4);
        u8x8.clearLine(4);
        u8x8.println((String) "odd amount");
      } else {
        pags[0] = 1;
        u8x8.setCursor(0, 4);
        u8x8.clearLine(3);
        u8x8.clearLine(4);
        u8x8.println((String) "paired");
      }
    }
    //amountInjectors
    if (i == 1) {
      pags[1]++;
      if (pags[1] > 6) {
        pags[1] = 6;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String)pags[i]);
      delay(300);
    }
    //RPM
    if (i == 2) {
      pags[2] += 50;
      if (pags[2] > 7000) {
        pags[2] = 7000;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String)pags[i]);
      delay(100);
    }
    //dutyCycle
    if (i == 3) {
      pags[3]++;
      if (pags[3] > 100) {
        pags[3] = 100;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println((String)pags[i] + " %");
      delay(100);
    }
    //countdown
    if (i == 4) {
      //both (up/down) btns pressed to generate minuts
      if (buttonState10 == HIGH) {
        pags[4] += 60;
        delay(250);
      } else {
        pags[4]++;
      }
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.println(formatTime(pags[4]));
      delay(100);
    }
  }

  /*---------------------------------------------------------------------------------------------------- start/stop the sequence --*/
  if (millis() - lastTimeButtonStateChanged > 500) {
    if (buttonState13 == HIGH) {
      lastTimeButtonStateChanged = millis();

      if (running) {  //pressed STOP during running
        stopCalled = true;
        Serial.println((String) "pressed stop");
      } else {
        stopCalled = false;
        nextClosingTime = (millis() + openTime);
        if (pags[0] == 0) {
          Serial.println((String)pinRay[c] + "  open: " + millis() + "\tclose: " + nextClosingTime + " (start by btn)");
          digitalWrite(pinRay[c], HIGH);
        } else {  //paired
          Serial.println((String)pinRay[c] + " en " + pinRay[c + countTill + 1] + "  open: " + millis() + "\tclose: " + nextClosingTime + " (start by btn)");
          digitalWrite(pinRay[c], HIGH);
          digitalWrite(pinRay[c + countTill + 1], HIGH);
        }
        pinPower = true;
        running = true;
        runTime = millis();  //update the timers
        countdownCounterStart = millis() + 1000;
        countdownCounter = pags[4];
        if (a > 0) {  //reset the "amount times pulsed" counter"
          a = 0;
        }
      }
      u8x8.clearLine(2);
      u8x8.clearLine(3);
      u8x8.clearLine(4);
      u8x8.clearLine(5);
      u8x8.clearLine(6);
      u8x8.setCursor(0, 2);
      u8x8.println((String) "RPM: " + pags[2]);
      u8x8.setCursor(0, 3);
      u8x8.println((String) "DutyCycle: " + pags[3] + "%");
      u8x8.setCursor(0, 4);
      u8x8.println((String) "open: " + openTime + "m/s");
      u8x8.clearLine(6);
      u8x8.setCursor(0, 6);
      u8x8.println(formatTime(pags[4]));
    }
  }
  /*----------------------------------------------------------------------------------------------------RUNNING--*/

  if (running) {
    if (millis() >= (runTime + MPR)) {
      nextClosingTime = (millis() + openTime);
      runTime += MPR;
      //reset loop between injectors & update screen
      if (c >= countTill) {
        a++;  //update amount of loops
        u8x8.setCursor(0, 2);
        u8x8.println((String) "RPM: " + pags[2]);
        u8x8.setCursor(0, 3);
        u8x8.println((String) "DutyCycle: " + pags[3] + "%");
        u8x8.setCursor(0, 4);
        u8x8.println((String) "open: " + openTime + "m/s");
        c = 0;
        if (stopCalled) {
          running = false;
          killEmAll();
          if (mayBeep) {
            beep();
          }
        }
      } else {
        c++;
      }

      if (running) {
        if (pags[0] == 1) {
          //Serial.println((String)"open double");
          Serial.println((String)pinRay[c] + " en " + pinRay[c + countTill + 1] + "  open: " + millis() + "\tclose: " + nextClosingTime);
          digitalWrite(pinRay[c], HIGH);
          digitalWrite(pinRay[c + countTill + 1], HIGH);
        } else {
          Serial.println((String)pinRay[c] + "  open: " + millis() + "\tclose: " + nextClosingTime);
          digitalWrite(pinRay[c], HIGH);
        }
        pinPower = !pinPower;
      }
    }

    //countdown shizzle
    if (millis() > countdownCounterStart) {
      countdownCounterStart += 1000;
      countdownCounter--;
      u8x8.setCursor(0, 6);
      u8x8.clearLine(6);
      u8x8.println(formatTime(countdownCounter));
      if (countdownCounter < 1) {
        stopCalled = true;
        mayBeep = true;
      }
    }
    u8x8.setCursor(0, 5);
    u8x8.println((String)a + " loops");
    u8x8.setCursor(0, 7);
    u8x8.println("press to stop ");
  } else {
    u8x8.setCursor(0, 7);
    u8x8.println("press to start ");
  }
  // close current injector
  if (millis() >= nextClosingTime /*&& running*/ && pinPower) {
    if (pags[0] == 1) {
      //Serial.println("close double");
      Serial.println((String) "  " + pinRay[c] + " en " + pinRay[c + countTill + 1] + " dicht: " + nextClosingTime);
      digitalWrite(pinRay[c], LOW);
      digitalWrite(pinRay[c + countTill + 1], LOW);
    } else {
      Serial.println((String) "\t" + pinRay[c] + " dicht: " + nextClosingTime);
      digitalWrite(pinRay[c], LOW);
    }
    pinPower = false;
  }
}  // end loop

void beep() {
  digitalWrite(BEEPER, 1);
  delay(750);
  digitalWrite(BEEPER, 0);
  delay(500);
  digitalWrite(BEEPER, 1);
  delay(750);
  digitalWrite(BEEPER, 0);
  delay(500);
  digitalWrite(BEEPER, 1);
  delay(750);
  digitalWrite(BEEPER, 0);
  countdownCounter = pags[4];
  mayBeep = false;
}

//make sure all injectors are closed
void killEmAll() {
  for (int k = 0; k < 6; k++) {
    Serial.println((String) "kill " + pinRay[k]);
    digitalWrite(pinRay[k], LOW);
  }
}

//readable time
String formatTime(int timeStamp) {
  int cMin = timeStamp / 60;
  int cSec = timeStamp % 60;
  String e = cSec <= 9 ? "0" : "";
  return (String)cMin + ":" + e + cSec;
}

And this is my test enviroment


The code works (opens and close the injectors (leds for now) as long as I keep the RPM under 800 -> int pags[5] = { 0, 6, 800, 5, 10 };

The serial log shows me (when under 800 RPM) perfect open and close times, but when I change to 800 of higher, the first 2 leds/log-lines don't close the current led/injector.
In the next loop it al goes well.

When I really strip the code so there is only a start button and I hardcode the RPM to any number, everything goes well...

Im really searching DAYS now, but really can't find the problem...

The log file now looks like this when 800 or more RPM

2  open: 3435	close: 3438.80 (start by btn)
3  open: 3517	close: 3520.80
4  open: 3603	close: 3606.80
	4 dicht: 3606.80
5  open: 3667	close: 3670.80
	5 dicht: 3670.80
6  open: 3752	close: 3755.80
	6 dicht: 3755.80
7  open: 3817	close: 3820.80
	7 dicht: 3820.80
2  open: 3937	close: 3906.80
	2 dicht: 3906.80
3  open: 3981	close: 3984.80
	3 dicht: 3984.80
4  open: 4045	close: 4048.80
	4 dicht: 4048.80
5  open: 4131	close: 4134.80
	5 dicht: 4134.80
6  open: 4196	close: 4199.80
	6 dicht: 4199.80
7  open: 4281	close: 4284.80
	7 dicht: 4284.80
2  open: 4401	close: 4370.80
	2 dicht: 4370.80
3  open: 4445	close: 4448.80
	3 dicht: 4448.80
pressed stop
4  open: 4559	close: 4562.80
	4 dicht: 4562.80
5  open: 4582	close: 4585.80

while it should look like this (example with 750 rpm)

2  open: 76154	close: 76158.15 (start by btn)
	2 dicht: 76158.15
3  open: 76258	close: 76262.15
	3 dicht: 76262.15
4  open: 76322	close: 76326.15
	4 dicht: 76326.15
5  open: 76408	close: 76412.15
	5 dicht: 76412.15
6  open: 76494	close: 76498.15
	6 dicht: 76498.15
7  open: 76579	close: 76583.15
	7 dicht: 76583.15
2  open: 76699	close: 76669.15
	2 dicht: 76669.15
3  open: 76743	close: 76747.15
	3 dicht: 76747.15
pressed stop
4  open: 76889	close: 76893.15
	4 dicht: 76893.15
5  open: 76911	close: 76915.15
	5 dicht: 76915.15
6  open: 76997	close: 77001.15
	6 dicht: 77001.15
7  open: 77083	close: 77087.15
	7 dicht: 77087.15
kill 2
kill 3
kill 4
kill 5
kill 6
kill 7

With the stripped code and change the rpm in the array it works well..
Here is the stripped code I tested (you don't need anything exept one button to test it:


#define BUTTON_PIN10 10
#define BUTTON_PIN11 11
#define BUTTON_PIN12 12
#define BUTTON_PIN13 13

int i = 0;                                                                    // counter for "pages"
int pags[5] = { 0, 6, 900, 5, 10 };                                           // array for page values
String pag[5] = { "PAIRED", "# INJECTORS", "RPM", "DUTY CYCLE %", "TIMER" };  // page titles
int selection = 0;                                                            // pointer for walking trough the arrays above
int countdown = 1;                                                            // seconds for countdown clock                            (adjustable)
int countdownCounter = 0;                                                     // used to count down :p
unsigned long countdownCounterStart;
int cMin;
int cSec;
String e = "0";
int c = 0;                            // counter for running
int countTill;                        // copy of c ( devided by 2 (paired))
unsigned long a = 0;                  // counter that keeps track of openings per injector
unsigned long runTime = 0;            // keeps track of (new) time for the global timer
int pinRay[] = { 2, 3, 4, 5, 6, 7 };  // array with pins to drive the injectors
bool pinPower = false;                // boolean that stores if a pin is powered                  (prevents closing injectors multiple times in the loop)
float MPR;                            // millisecs per revolution                                 (determined by RPM in loop())
float openTime = 0.00;                // time an injector is open                                 (determined by MPR and dutyCycle in loop())
//unsigned long nextClosingTime = 0;   // time that the open injector must close
float nextClosingTime = 0;                     // time that the open injector must close
bool running = false;                          // the sequence is running when true, sequence will stop after all (connected) injectors finished the loop
bool stopCalled = false;                       // called to kill running
unsigned long lastTimeButtonStateChanged = 0;  //debounce start stop btn


void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN13, INPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
}

void loop() {
  byte buttonState13 = digitalRead(BUTTON_PIN13);
  /*---------------------------------------------------------------------------------------------------- start/stop the sequence --*/
  if (millis() - lastTimeButtonStateChanged > 500) {
    if (buttonState13 == HIGH) {
      lastTimeButtonStateChanged = millis();

      if (running) {  //pressed STOP during running
        stopCalled = true;
        Serial.println((String) "pressed stop");
      } else {
        stopCalled = false;
        nextClosingTime = (millis() + openTime);
        if (pags[0] == 0) {
          Serial.println((String)pinRay[c] + "  open: " + millis() + "\tclose: " + nextClosingTime + " (start by btn)");
          digitalWrite(pinRay[c], HIGH);
        } else {  //paired
          Serial.println((String)pinRay[c] + " en " + pinRay[c + countTill + 1] + "  open: " + millis() + "\tclose: " + nextClosingTime + " (start by btn)");
          digitalWrite(pinRay[c], HIGH);
          digitalWrite(pinRay[c + countTill + 1], HIGH);
        }
        pinPower = !pinPower;
        running = !running;
        runTime = millis();  //update the timers
        countdownCounterStart = millis() + 1000;
        countdownCounter = pags[4];
        if (a > 0) {  //reset the "amount times pulsed" counter"
          a = 0;
        }
      }
    }
  }
  /*----------------------------------------------------------------------------------------------------RUNNING--*/
  //int countTill;
  if (pags[0] == 1) {                   //if paired
    MPR = 1000 / ((pags[2] / 2) / 60);  //milliSecs Per Revolution
    countTill = (pags[1] - 1) / 2;
  } else {
    MPR = 1000 / (pags[2] / 60);  //milliSecs Per Revolution
    countTill = pags[1] - 1;
  }
  openTime = (MPR / 100) * pags[3];

  if (running) {
    if (millis() >= (runTime + MPR)) {
      nextClosingTime = (millis() + openTime);
      runTime += MPR;
      //reset loop between injectors & update screen
      if (c >= countTill) {
        c = 0;
        if (stopCalled) {
          running = !running;
        }
      } else {
        c++;
      }

      if (running) {
        if (pags[0] == 1) {
          //Serial.println((String)"open double");
          Serial.println((String)pinRay[c] + " en " + pinRay[c + countTill + 1] + "  open: " + millis() + "\tclose: " + nextClosingTime);
          digitalWrite(pinRay[c], HIGH);
          digitalWrite(pinRay[c + countTill + 1], HIGH);
        } else {
          Serial.println((String)pinRay[c] + "  open: " + millis() + "\tclose: " + nextClosingTime);
          digitalWrite(pinRay[c], HIGH);
        }
        pinPower = !pinPower;
      }
    }

    // close current injector
    if (millis() >= nextClosingTime && running && pinPower) {
      if (pags[0] == 1) {
        //Serial.println("close double");
        Serial.println((String) "  " + pinRay[c] + " en " + pinRay[c + countTill + 1] + " dicht: " + nextClosingTime);
        digitalWrite(pinRay[c], LOW);
        digitalWrite(pinRay[c + countTill + 1], LOW);
      } else {
        Serial.println((String) "\t" + pinRay[c] + " close: " + nextClosingTime);
        digitalWrite(pinRay[c], LOW);
      }
      pinPower = !pinPower;
    }
  }
}  // end loop

Does anuone see where I go wrong?
Many thx in advance!!

First of all make each and every variable that is used in conjunction with function millis() of type

unsigned long

instead of

float nextClosingTime = 0;  // time that the open injector must close

define

unsigned long nextClosingTime = 0; // time that the open injector must close

Do this for each and every variable that is used with function millis()

beeing a comparison or an assignemt

best regards Stefan

Thx for the reply Stefan, you are right it should be an unsigned long!
You can see I had an unsigned long, but tested it with float because of the misstakes that happens with my code and I was thinking it was maybe because of the floating numbers.
But it is no difference when I use unsigned long, the problem stay exactly the same.

Thx for reading anyway!

More suggestions maybe?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.