Defeated by millis()

Hi, i'm starting to think mid 50's is a little late for an old dog to learn new tricks :grinning_face_with_smiling_eyes:, having failed badly with talent and understanding today, i hope you guys can set me back on track :folded_hands:. My 1st self learn project is to create a timer for boxing workouts. I have 2off 7 segment displays, one counting up rounds, the other displaying seconds left in each round and in the rest periods, in between. LED's identify the present mode (box or rest), a start button kicks off the timers.
I have a 12V supply and a 12V relay driving a buzzer loud enough to be heard over music.
All is working really well with exception to my desire to initiate the buzzer at the end of each box and rest period. Using delay() messes with the timings, I have tried numerous millis() attempts both in my project code and in stand alone code, and just don’t get it :frowning:
I’m hoping somone can point me in the right direction, my code is below, I’ve read reread and read again the blink without delay example along with many many other googled examples, just cant seem to translate it / them to my requirements.
I've stripped out my failed attempts and hope my annotations give clarity, I’ve commented //BUZZ where i would like to initiate the buzzer. Many thanks in advance. :slight_smile:
Also any other coding tips appreciatively received.

/*************************************************** 
Boxing timer project.
Karl Smith 28/08/2025
***************************************************/

//required libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

Adafruit_7segment seconds_matrix = Adafruit_7segment();  //seconds count down 4x7 segment display
Adafruit_7segment rounds_matrix = Adafruit_7segment();   //rounds count up 4x7 segment display

int boxled = 13;    //box LED output pin
int restled = 12;   //rest LED output pin
int start = 3;      //start button input
int startled = 11;  //'press start' button LED
int buzzer = 10;    //buzzer relay

//***************** Timing & rounds parameters:**********************************
int boxtime = 3;    // Enter length of boxing rounds in seconds
int resttime = 3;   // Enter rest time between rounds in seconds
int NumRounds = 3;  // Enter number of rounds
//*******************************************************************************


void setup() {
#ifndef __AVR_ATtiny85__
  Serial.begin(9600);
#endif
  seconds_matrix.begin(0x70);  //address for seconds count down display (no links shorted)
  rounds_matrix.begin(0x71);   //address for rounds count up display (A0 shorted)
  //initialise digital pins
  pinMode(boxled, OUTPUT);
  pinMode(restled, OUTPUT);
  pinMode(start, INPUT_PULLUP);
  pinMode(startled, OUTPUT);
  pinMode(buzzer, OUTPUT);
  digitalWrite(buzzer, LOW);  //buzzer off
}

//Box function
int box(int round) {
  for (uint16_t boxcounter = boxtime; boxcounter > 0; boxcounter--) {
    digitalWrite(boxled, HIGH);          // Box LED on
    seconds_matrix.println(boxcounter);  // write seconds left of round to seconds matrix
    seconds_matrix.writeDisplay();
    rounds_matrix.println(round);  // Write round number to rounds matrix
    rounds_matrix.writeDisplay();
    delay(1000);  // 1000mS = 1sec
  }
  digitalWrite(boxled, LOW);  // Box LED off
  //BUZZ
}

// Rest between rounds function
void rest() {
  for (uint16_t restcounter = resttime; restcounter > 0; restcounter--) {
    digitalWrite(restled, HIGH);          // Rest LED on
    seconds_matrix.println(restcounter);  //write seconds left of rest to seconds matrix
    seconds_matrix.writeDisplay();
    delay(1000);  //1000mS = 1sec
  }
  digitalWrite(restled, LOW);  // Box LED off
                               //BUZZ
}

void loop() {
  digitalWrite(buzzer, LOW);   //start with buzzer off
  rounds_matrix.println(" ");  //Clear rounds display before start
  rounds_matrix.writeDisplay();
  digitalWrite(startled, HIGH);          // Turn 'Press start' LED on
  int startrounds = digitalRead(start);  //read start button
  if (startrounds == LOW) {
    digitalWrite(startled, LOW);                                  // Turn 'Press start' LED off
    for (uint8_t rounds = 1; rounds < NumRounds + 1; rounds++) {  // count rounds
      if (rounds < NumRounds) {
        box(rounds);
        rest();
      } else if (rounds = NumRounds) {
        box(rounds);
        seconds_matrix.println(" ");  //clear display when rounds complete
        seconds_matrix.writeDisplay();
        //BUZZZ
      }
    }
  }
}
  • Please, do not flaunt your youth at us oldsters, it makes us feel very mortal.

  • Take some time with this example, there are a lot of comments in the sketch to explain what is being done.

I think my youngest is almost in your age range. You did something most of the young ones do not and that is post your code correctly the first time. Great job. You did pick a tough one for a first project, but you will get there.

For additional help, check out useful links and tutorials: Useful Links on Arduino Forum. Of course one of the better sources of information (in my opinion) is the Arduino Cookbook. Skim it cover to cover and stop on any project that interests you. I probably sound like a broken record about the Cookbook but it how I learned, it has the basics.

Appreciated thanks guys, made me feel young again too :slightly_smiling_face:, ive had a scan through plenty to go at thankyou

Often it takes running code that prints out key variable values to help you trace through the lines that do execute to watch the logic in action.

I suggest that you stick to the simplest examples you can find (ones that don’t have other/extra things going on, leave those for later) just to cut down on the number of lines to hold in your head at once.

This is the best complete commonsense tutorial for just millis timing I know of.

Millis timing is key but once we know that, we also use (simpler than the name sounds) finite state machines to write code that fits different conditions moment to moment when void loop() runs over and over again, because things change and we want to control that.

But Take Your Time and you should learn piece by piece and hate to tell ya but it was way f__king easier when you were young, I started writing code when I was 23 in 1980 so I can’t relate except to say that it took me a sustained effort back then.

I think what you really have is a state machine. That, in combination with using millis to change states, will have you up and running quickly. The tutorials section contains both state machines and millis.

p.s. 83 yo here.

Excellent link thankyou, definately aimed at my present level of understanding, learned a lot quickly (i believe) :slight_smile:
Thanks again to all

loving this place, so much to learn, in all my present life circles; im the elder :slight_smile:

You have two States, Box and Rest.
Secs left in either is something like
now - BoxStart
now - RestStart

State change is
(Now - BoxStart) >= BoxDuration
(Now - RestStart) >= RestDuration

Add in the display code, round counter and there you go.

More than enough clues I think,
good luck.

[quote=gilshultz]Of course one of the better sources of information (in my opinion) is the Arduino Cookbook.[/quote}

I may have mislead you a bit, states are

StartBox
Boxing
EndBox

StartRest
Resting
EndRest

Thankyou :slight_smile: tomorrows plan have mostly changed to this

On the other hand, maybe your code is close… you might have more than one of this kind of error

else if (rounds = NumRounds) {

Single = is for assignment, double == is a check for equality.

We all have made, and might even again, that mistake.

Go now to the IDE Preferences and crank up the warning level. This is such a common mistake that the compiler can see you making it (maybe) and advise you to take a close look.

I'll look more, that one happened to jump out.

a7

Agreed, and another is Electronics Cookbook.
chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://cdn.instructables.com/ORIG/FFN/1L27/J7MFSITD/FFN1L27J7MFSITD.pdf

Good spot. yes the compiler does indeed spot it; not when just 'show verbose output' > "compile" is ticked, but it does flag up when show verbose output' > "upload" ticked as well. Both now ticked going forward :slight_smile:

found it thanks :slight_smile:

I didn't see any other problems. And I did not build your entire project, but the basic flow is correct.

I got alternating rounds of boxing and resting, three boxing rounds each time the start button is pressed.

I agree with advice to do this differently, but sometimes it is nice to see what you coded working to plan.

a7

are you sure? I remember the first IC being invented and my professor holding up a junction and telling us it will never amount to anything we will study vacuum tubes.

  • Sounds like you were a few years ahead of me.
    Got 1 or 2 shocks from vacuum tube circuits and a couple of glass burns, didn’t need finger prints anyway.

:palm_down_hand:

One of the big things about code is that you can be wrong ten thousand times but you only have to get it right ONCE.