Near Identical sections of code do different things

Hi, I have a program that I am working on that works as a stopwatch. For the display it uses a five-digit, seven-segment display powered by a single shift register.

When I start the program it displays "SPLIT" for one and a half seconds then displays "59.59.0" (59 minutes 59 seconds and 0 tenths of a second) which is what I want it to do. Then if I push the "start" button (connected to pin 9) it starts counting up and after it reaches "59.59.9" it stops displaying the tenths of a second digit and starts displaying the hour digit by shifting the digits to the right (1.00.00). Pushing the "function" button (connects to pin 13) causes it to display "lap" for one and a half seconds and then goes onto the lap function.

The problem I am having is when it displays "LAP". I have the "Timer" function in the while loop because I want it to continue to increase the time but every time "nextNumber" is less than "milliseconds" digits[0](tenths second) equals 7406. When that happens it sets digit[0] to 0 and repeats setting digits[0] from 7406 to 0 until the loop exits (lines 82 -88 in code)

. After it exits the loop, the time is the same as when it entered the loop. I also tried replacing the function "DisplayLap" with the function "DisplaySplit" and digits[0] never went above 9 and it worked as I wanted it to except that it displayed "split" instead of "lap".

Why does digits[0] ever equal 7406?

StopWatch_3_0.ino (20.7 KB)

If you post your code as described in the how to use this forum sticky, more forum members will read it.

It's not possible, 20k is too big so the OP attached it instead.

Why does digits[0] ever equal 7406?

Sometimes the beginning of an array getting suspect values, is the result of another array exceeding its upper limit, since they are often allocated sequentially in memory. So look for wild array indices.

  prevMillis = millis();
  while (!digitalRead(functionButten) || (prevMillis + 1500) > millis()) {

Looking only at these two lines - which are duplicated several more times - I'd say (prevMillis + 1500) > millis() is always going to be true.

I would start by: Taking one reading of millis() at the top and use that value throughout. At the bottom of loop() *then * update prevMillis;

See IDE -> file/examples/digital/blinkwithoutdelay for correct setup of Arduino timers.

I didn't look much deeper than that.

The value 7406 is 0x1CEE in hex. Those are the last two bytes of your "writeLap[]" array. That may not be a coincidence.

You seem to be doing this quite a bit:

  for (digit = 0; digit < 5; digit++) {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, LSBFIRST, writeSet[digit]);
    if (digit != 7) {
      digitalWrite(digit + 2, HIGH);
    }
    if (digit > 0) {
      digitalWrite(digit + 2, HIGH);
    }
    else {
      digitalWrite(7, HIGH);
    }
    digitalWrite(latchpin, HIGH);
    digitalWrite(digit + 3, LOW);
    delay(1);
  }

Why the check for != 7 when 'digit' only goes up to 4?

You seem to be using pins 7, 3, 4, 5, 6 for the 5 digits. It would be easier to understand if you had one global constant array for the digit pin numbers:

const byte DigitPins[5] = {7, 3, 4, 5, 6};

Then the repeated code could simplify to:

  for (digit = 0; digit < 5; digit++) {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, LSBFIRST, writeSet[digit]);
    digitalWrite(DigitPins[digit], HIGH);
    digitalWrite(latchpin, HIGH);
    delay(1);
    digitalWrite(DigitPins[digit], LOW);
  }

You could save a lot of repeated code by putting that into a function and passing in the array of patterns to display:

void show(byte patterns[5])
{
   for (digit = 0; digit < 5; digit++) {
    // Set the segment pins
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, LSBFIRST, patterns[digit]);
    digitalWrite(latchpin, HIGH);

    // Enable the digit briefly
    digitalWrite(DigitPins[digit], HIGH);
    delay(1);  // Higher delay gives more brightness but more flicker
    digitalWrite(DigitPins[digit], LOW);
  }

void DisplayLap() {
  const byte writeLap[5] = {0x0, 0x0, 0xCE, 0xEE, 0x1C}; //lap in hex  
  show(writeLap);
}


void DisplaySplit() {
  const byte writeSplit[5] = {0x1E, 0xC, 0x1C, 0xCE, 0xB6}; //split in hex
  show(writeSplit);
}


void DisplaySet() {
  const byte writeSet[5] = {0x0,0x0,0x1E,0x9E,0xB6}; //set in hex
  show(writeSet);
}



void DisplayClock() {

  const byte writeClock[5] = {0xAE,0x9C,0xFC,0x1C,0x9C}; //clock in hex

  show(writeClock);

}

I would also suggest you take a look at the State Change Detection example (File->examples-02.Digital->StateChangeDetection) since you want to detect when your buttons change state and react to that, not necessarily react to their current state.

You could also make a lot of those global variables locals within their respective functions and/or for() loops.

Thanks for responding, I will definitely consider using your suggestions.

I went back to the code and noticed that "writeLap" was declared as a byte which would be to small to hold EE (238). I changed it to an int and now the code works as long as I have the Serial.println() function in the while loop for lap

  while (digitalRead(functionButten)) { //test if to go on to split
    Hour();
    Time();
    WriteTime();
    lapChangeMode();
    Serial.println(digits[0]);
  }

I have been noticing this happening other times also where the code behaves differently depending on what Serial.println() functions I have in it.

Why is the program doing this?

StopWatch_3_0.ino (20.7 KB)

Also, after I posted the last one, I changed "writeLap" back to a byte and the program still worked the way I wanted it to.
Now I am really confused.