millis() function not working properly... ( I guess)

I’m thinking of building a DIY gokart-offroad type of car from scrap vehicle parts. And as electronics, I’m planning on using my Arduino Uno for controlling basically everything. So I just made a gear display which lets me know which gear I’m currently on. And a simple parking sensor.

If I’m too close to an object the parking sensor buzzer will blink. And I can’t blink with delay() functions because if I try to shift up when it’s blinking, the input won’t register because delay is a blocking function. So I tried to use millis instead but seems like it also doesn’t register.

The concept is easy. I will have two buttons on each side of my shiftstick. And when I shift up the button gets pressed therefore the 7 segment display adds one. And another one for downshifting.

I have not added the reverse gear yet, but still when the parking sensor function is working, I still can’t push the buttons for a good amount of time.

I hope you guys could understand what I’m trying to say. I just started coding in Arduino so I don’t have enough experience. I’m leaving the .ino file as an attachment. I tried to explain everything in the file. Hopefully someone knows the solution for this. Thanks in advance…

// Setting up the pins for 7-Segment-Display.
const int E = 13;
const int D = 12;
const int C = 11;
const int DP = 10;
const int G = 9;
const int F = 8;
const int A = 7;
const int B = 6;


// Setting up the counter for gear shifting.

int gearCount = 0;

// Setting up the button states and button pin for state-change detectors.

int buttonAddPin = 5;
int buttonAddState = 0;
int previousButtonAddState = 0;

// And this is for downshifting.

int buttonSubstractPin = 4;
int buttonSubstractState = 0;
int previousButtonSubstractState = 0;


// Adding buzzer for parking sensor.

const int buzzerPin = 3;
int buzzerTone = 0;


// Adding parking sensor.

const int trigPin = 2;
const int echoPin = 1;
long duration;
int distance;


// Adding non-delay blinker with millis for buzzer to blink when sensor detects an object.

unsigned long previousTime = 0;




/*---------------------------------- FUNCTIONS FOR SHIFTING -------------------------------------------------*/


// "zero" function is the series of commands for displayıng 0 on the 7-Segment corresponding to neutral gear.

void zero()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);

}


// "one" function is the series of commands for displaying 1 on the 7-Segment-Display corresponding to 1st gear.

void one()
{
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);

}


// "two" function is the series of commands for displaying 2 on the 7-Segment-Display corresponding to 2nd gear.

void two()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH); 
}



// "three" function is the series of commands for displaying 3 on the 7-Segment-Display corresponding to 3rd gear.

void three()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH);
}


// And now the main function that we are going to call in "void loop" to determine which gear we are on.

void gearDisplay()
{

  buttonAddState = digitalRead(buttonAddPin);          // And now the button state change detector for shifting up is ready. As you can see when I push the button
                                                       // program adds 1 to gearCount variable. So now gearCount is 1. Therefore the 7-Segment-Display will show
  if(buttonAddState != previousButtonAddState){        // 1 on it. We will do this a bit later.
    
    if(buttonAddState == HIGH){
      gearCount++;
    }

   delay(50);
   
  }

  previousButtonAddState = buttonAddState;


// Now for downshifting.


  buttonSubstractState = digitalRead(buttonSubstractPin);

  if(buttonSubstractState != previousButtonSubstractState) {

     if(buttonSubstractState == HIGH){
        gearCount--;
     }

  delay(50);

   
  }

  previousButtonSubstractState = buttonSubstractState;



// Now we will call one of the 7-Segment-Display number functions according to the gearCount variable.


  if(gearCount == 0){
    zero();
  }
  
  else if(gearCount == 1){
    one();
  }
  

  else if(gearCount == 2){
    two();
  }


  else if(gearCount == 3){
    three();
  }

  
  else if(gearCount > 3){                 // Just making sure if we press buttons accidentally more than enough, it sets gearCount back to closest gear available.
    gearCount--;
  }

  
  else if(gearCount < 0){                 // Same with this one.
    gearCount++;
  }

}


// That was al for the gear panel. Now the hard part. The parking sensor.


/*---------------------------------------------- SHIFTING DONE ----------------------------------------------------*/












/*--------------------------------------------- PARKING SENSOR ------------------------------------------------------*/



void parkingSensor()
{

  digitalWrite(trigPin, LOW);                 // Resetting trigPin

  delayMicroseconds(2);                       // Delaying to prevent any issiues. ( I saw this online, most people do it like this so I also did.)


  digitalWrite(trigPin, HIGH);                // Creating a short soundwave.
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);          // Detecting the time that passes for the soundwave to reach back to the receiver.

  distance = duration*0.034/2;                // Simple math for calculating the distance between the obstacle and sensor.


  unsigned long currentTime = millis();       // Store the current time for blinking the buzzers.


  if((distance > 0) && (distance < 31)){              // If the distance is in between 0-31 buzz non-stop.

    buzzerTone = 1000;
    tone(buzzerPin, buzzerTone);
  }


  else if((distance > 30) && (distance < 76)){        // If the distance is between 30-76 buzz every 100 miliseconds.

      if(currentTime - previousTime >= 100){

        previousTime = currentTime;

        if(buzzerTone == 1000){

          buzzerTone = 0;
        }

        else {

          buzzerTone = 1000;
        }
      
       tone(buzzerPin, buzzerTone);
      }
  }


  else if((distance > 75) && (distance < 101)){      // If the distance is between 75-101 buzz every 300 miliseconds.

      if(currentTime - previousTime >= 300){

        previousTime = currentTime;


          if(buzzerTone == 1000){

            buzzerTone = 0;
          }
      
          else {

           buzzerTone = 1000;
          }
      
       tone(buzzerPin, buzzerTone);
      
      }
  }



  else if(distance > 100){                         // If the distance is more than 100 don't buzz.

    buzzerTone = 0;

    tone(buzzerPin, buzzerTone);
  }
  
}

/*------------------------------- PARKING SENSOR DONE -----------------------------------*/




// And this was, I guess, all I had to do but unfortunately it's not working...



void setup() {
  
  
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(DP, OUTPUT);
  pinMode(buttonAddPin, INPUT);
  pinMode(buttonSubstractPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {

  gearDisplay();

  parkingSensor();
}

EDIT: Turns out that pulseIn() 's default duration is 1 second. And it’s also a blocking function which blocks the buttons from registering inputs on every loop for 1 second. Changing that to smaller values, for example 10ms in my case, was enough and solved the issue. All credit goes to @CherryDT on StackOverflow who solved this.

btw this is how the code should look like for 10ms: pulseIn(echoPin, HIGH, 10000)

// Note that the duration in pulseIn() is in microseconds.

gearsandparkingsensor.ino (6.77 KB)

Please.post your code.
In code tags.

Added. Thanks for the heads up!

duration = pulseIn(echoPin, HIGH);

pulseIn() is a blocking function, and since you call this every pass through loop I think this is the cause of the poorly responding buttons.

One solution would be that you use the NewPing.h (available through the library manager) to read the distance sensor. There is a timer method which is non blocking. See the NewPingEventTimer library example.

Alternatively if you want to write you own code, you can use an external interrupt to respond to the rise and fall of the return pulse. I would not try to make the trigger pulse non blocking since it is only for a few microseconds, but I would not trigger continuously, but only at an interval which makes sense for the speed of movement. Here's an example

const byte triggerPin = 7;
const byte echoPin = 2;
boolean triggerPulseFinished = false;

//variables changed in ISR
volatile unsigned long returnPulseDuration;
volatile boolean returnPulseCaptured = false;

void setup()
{
  Serial.begin (115200);
  Serial.println("starting...");
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(echoPin), EchoPinISR, CHANGE); // Pin 2 interrupt on any change
}
void loop()
{
  triggerPulse();
  readReturn();
}

void triggerPulse()
{
  const unsigned int pingSpeed = 100;//trigger every 100 ms
  static unsigned long pingTimer = millis();
  if (millis() >= pingTimer && triggerPulseFinished == false)
  {
    pingTimer += pingSpeed;
    digitalWrite(triggerPin, LOW);
    delayMicroseconds(2);
    digitalWrite(triggerPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(triggerPin, LOW);
    triggerPulseFinished = true;
  }
}

void readReturn()
{
  if (returnPulseCaptured == true && triggerPulseFinished == true)
  {
    //protected access to returnPulseDuration not necessary
    //because interrupt is not active until reset
    //Serial.print((returnPulseDuration / 2) / 29.1, 1);
    //Serial.println(" cm");
    Serial.print((returnPulseDuration / 2) / 73.0, 1);
    Serial.println(" inches");
    returnPulseCaptured = false; //reset
    triggerPulseFinished = false;
  }
}

void EchoPinISR()
{
  if (returnPulseCaptured == false)
  {
    static unsigned long startTime;
    if (digitalRead(echoPin)) // Gone HIGH
      startTime = micros();
    else  // Gone LOW
    {
      returnPulseDuration = micros() - startTime;
      returnPulseCaptured = true;
    }
  }
}

You also need to distinguish between when your distance sensor transitions from one distance zone to another vs. simply being in that zone. Much like the StateChangeDetection example in the IDE

// Setting up the pins for 7-Segment-Display.
const int E = 13;
const int D = 12;
const int C = 11;
const int DP = 10;
const int G = 9;
const int F = 8;
const int A = 7;
const int B = 6;

// Setting up the counter for gear shifting.
int gearCount = 0;

// Setting up the button states and button pin for state-change detectors.
const int buttonAddPin = 5;
int previousButtonAddState = 0;

// And this is for downshifting.
const int buttonSubstractPin = 4;
int previousButtonSubstractState = 0;

// Adding buzzer for parking sensor.
const int buzzerPin = 3;
const int buzzerTone = 1000;
bool isBuzzerOn = false;
int previousBuzzerState;
unsigned long buzzerDuration;

// Adding parking sensor.
const int trigPin = 2;
const int echoPin = 1;

// Adding non-delay blinker with millis for buzzer to blink when sensor detects an object.
unsigned long previousTime = 0;

/*---------------------------------- FUNCTIONS FOR SHIFTING -------------------------------------------------*/
// "zero" function is the series of commands for displayıng 0 on the 7-Segment corresponding to neutral gear.
void zero()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);
}

// "one" function is the series of commands for displaying 1 on the 7-Segment-Display corresponding to 1st gear.
void one()
{
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);
}

// "two" function is the series of commands for displaying 2 on the 7-Segment-Display corresponding to 2nd gear.
void two()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH);
}

// "three" function is the series of commands for displaying 3 on the 7-Segment-Display corresponding to 3rd gear.
void three()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH);
}

// And now the main function that we are going to call in "void loop" to determine which gear we are on.
void gearDisplay()
{
  int buttonAddState = digitalRead(buttonAddPin);          // And now the button state change detector for shifting up is ready. As you can see when I push the button
  // program adds 1 to gearCount variable. So now gearCount is 1. Therefore the 7-Segment-Display will show
  if (buttonAddState != previousButtonAddState) {      // 1 on it. We will do this a bit later.
    if (buttonAddState == HIGH) {
      gearCount++;
    }
    delay(50);
  }
  previousButtonAddState = buttonAddState;


  // Now for downshifting.
  int buttonSubstractState = digitalRead(buttonSubstractPin);
  if (buttonSubstractState != previousButtonSubstractState) {
    if (buttonSubstractState == HIGH) {
      gearCount--;
    }
    delay(50);
  }
  previousButtonSubstractState = buttonSubstractState;

  // Now we will call one of the 7-Segment-Display number functions according to the gearCount variable.
  if (gearCount == 0) {
    zero();
  }
  else if (gearCount == 1) {
    one();
  }
  else if (gearCount == 2) {
    two();
  }
  else if (gearCount == 3) {
    three();
  }
  else if (gearCount > 3) {               // Just making sure if we press buttons accidentally more than enough, it sets gearCount back to closest gear available.
    gearCount--;
  }
  else if (gearCount < 0) {               // Same with this one.
    gearCount++;
  }
}

// That was al for the gear panel. Now the hard part. The parking sensor.
/*---------------------------------------------- SHIFTING DONE ----------------------------------------------------*/


/*--------------------------------------------- PARKING SENSOR ------------------------------------------------------*/
void parkingSensor()
{
  int buzzerState = 0;

  digitalWrite(trigPin, LOW);                 // Resetting trigPin
  delayMicroseconds(2);                       // Delaying to prevent any issiues. ( I saw this online, most people do it like this so I also did.)
  digitalWrite(trigPin, HIGH);                // Creating a short soundwave.
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH);          // Detecting the time that passes for the soundwave to reach back to the receiver.
  int distance = duration * 0.034 / 2;            // Simple math for calculating the distance between the obstacle and sensor.

  unsigned long currentTime = millis();       // Store the current time for blinking the buzzers.

  if ((distance > 0) && (distance < 31)) {            // If the distance is in between 0-31 buzz non-stop.
    buzzerState = 0;
    tone(buzzerPin, buzzerTone);
  }
  else if ((distance > 30) && (distance < 76)) {      // If the distance is between 30-76 buzz every 100 miliseconds.
    buzzerState = 1;
  }
  else if ((distance > 75) && (distance < 101)) {    // If the distance is between 75-101 buzz every 300 miliseconds.
    buzzerState = 2;
  }
  else if (distance > 100) {                       // If the distance is more than 100 don't buzz.
    buzzerState = 3;
  }

  if ( previousBuzzerState != buzzerState ) {
    // state has changed so start timer
    previousTime = currentTime;
    switch (buzzerState) {
      case 0:
        buzzerDuration = 0;
        isBuzzerOn = true;
        tone(buzzerPin, buzzerTone);
        break;
      case 1:
        buzzerDuration = 100;
        isBuzzerOn = true;
        tone(buzzerPin, buzzerTone);
        break;
      case 2:
        buzzerDuration = 300;
        isBuzzerOn = true;
        tone(buzzerPin, buzzerTone);
        break;
      case 3:
        buzzerDuration = 0;
        isBuzzerOn = false;
        noTone(buzzerPin);
        break;
    }
  }
  previousBuzzerState = buzzerState;
  if (buzzerDuration && currentTime - previousTime >= buzzerDuration) {
    previousTime = currentTime;
    if ( isBuzzerOn == true ) {
      noTone(buzzerPin);
    }
    else {
      tone(buzzerPin, buzzerTone);
    }
    isBuzzerOn = !isBuzzerOn;
  }
}

/*------------------------------- PARKING SENSOR DONE -----------------------------------*/


// And this was, I guess, all I had to do but unfortunately it's not working...
void setup() {
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(DP, OUTPUT);
  pinMode(buttonAddPin, INPUT);
  pinMode(buttonSubstractPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {

  gearDisplay();
  parkingSensor();
}

You can shrink your display functions by 90% - using an array of digits, and a single function to drive the LEDs