changing delay into millis

hey guys/girls im having alil trouble with replacing a delay() with a millis(). i have modified a printer to print directly onto a pcb but im having some trouble with the code. i can get it working without the sensor input but not with a sensor input i have a feeling its got to do with a delay() since i understand that those stop the program and restart after the delay is done.

this is the code working without the input sensor

#define STARTUP 1
#define STANDBY 2
#define PRINTING 3


const int NPIS = 2;
const int MFC = 3;
const int PIS = 4;
const int ES = 5;
const int MPFS = 6;
const int BUZZER = 7;




void setup() {

  Serial.begin(9600);
  pinMode(NPIS, INPUT);
  pinMode(MFC, INPUT);
  pinMode(PIS, OUTPUT);
  pinMode(ES, OUTPUT);
  pinMode(MPFS, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(PIS, LOW);
  digitalWrite(ES, LOW);
  digitalWrite(MPFS, LOW);
  digitalWrite(BUZZER, LOW);

}

void loop()
{

  static byte currentState = STARTUP;

  switch (currentState)
  {

    case STARTUP:
       delay(30000);
       currentState = STANDBY;
    
    case STANDBY:
      digitalWrite(MPFS, HIGH);
      Serial.println("STANDBY");
      if (digitalRead(MFC) == LOW)
       {
        delay(4100);
        digitalWrite(BUZZER, HIGH);
        currentState = PRINTING;
     
     
       } else {
        digitalWrite(BUZZER, LOW);
      }
      break;

 

    case PRINTING:
      digitalWrite(BUZZER, LOW);
      if (printing() == true)
      {
        delay(2000);
        currentState = STANDBY;
      }

      break;

    
  }

}

bool printing()
{
  static unsigned long StartTime = 0;

  if (StartTime == 0)
  {
    StartTime = millis();
  }

  if (millis() - StartTime <= 1824)
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, LOW);
    Serial.println("PIS IS HIGH");

  }
  else if ((millis() - StartTime >= 1825) && (millis() - StartTime <= 2774))
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - StartTime >= 2775) && (millis() - StartTime <= 3599))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - StartTime >= 3600) && (millis() - StartTime <= 5474))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, HIGH);
    digitalWrite(BUZZER, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS HIGH");
  }
  else if (millis() - StartTime >= 5475)
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS LOW");
    StartTime = 0;
    return true;
  }

  return false;
}

now the code that uses the sensor but not detecting it

#define STARTUP 1
#define STANDBY 2
#define PRINTING 3


const int NPIS = 2;
const int MFC = 3;
const int PIS = 4;
const int ES = 5;
const int MPFS = 6;
const int BUZZER = 7;




void setup() {

  Serial.begin(9600);
  pinMode(NPIS, INPUT);
  pinMode(MFC, INPUT);
  pinMode(PIS, OUTPUT);
  pinMode(ES, OUTPUT);
  pinMode(MPFS, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(PIS, LOW);
  digitalWrite(ES, LOW);
  digitalWrite(MPFS, LOW);
  digitalWrite(BUZZER, LOW);

}

void loop()
{

  static byte currentState = STARTUP;

  switch (currentState)
  {

    case STARTUP:
       delay(30000);
       currentState = STANDBY;
    
    case STANDBY:
      digitalWrite(MPFS, HIGH);
      Serial.println("STANDBY");
      if (digitalRead(MFC) == LOW)
       {
        delay(2500);
        digitalWrite(BUZZER, HIGH);
if(digitalRead(NPIS) == LOW)
{
currentState = PRINTING;
        
     }
} 
else {
        digitalWrite(BUZZER, LOW);
      }
      break;

 

    case PRINTING:
      digitalWrite(BUZZER, LOW);
      if (printing() == true)
      {
        delay(2000);
        currentState = STANDBY;
      }

      break;

    
  }

}

bool printing()
{
  static unsigned long StartTime = 0;

  if (StartTime == 0)
  {
    StartTime = millis();
  }

  if (millis() - StartTime <= 1824)
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, LOW);
    Serial.println("PIS IS HIGH");

  }
  else if ((millis() - StartTime >= 1825) && (millis() - StartTime <= 2774))
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - StartTime >= 2775) && (millis() - StartTime <= 3599))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - StartTime >= 3600) && (millis() - StartTime <= 5474))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, HIGH);
    digitalWrite(BUZZER, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS HIGH");
  }
  else if (millis() - StartTime >= 5475)
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS LOW");
    StartTime = 0;
    return true;
  }

  return false;
}

i need the buzzer to go on between 2.5sec and the 4.6sec which is my timing window for the npis to go low

You’ve got a state machine, but you’re making it stop in lots of places. For example, in the STARTUP state:

   case STARTUP:
       delay(30000);
       currentState = STANDBY;

To use the millis() technique, save a timestamp when the STARTUP state begins. The STARTUP state begins after reset (i.e., the initial state):

uint32_t stateTime;

void setup()
{
    ...pin stuff...

  stateTime = millis(); // for initial state STARTUP
}

void loop()
{
  switch (currentState) {

    case STARTUP:
       if (millis() - stateTime >= 3000) {
         currentState = STANDBY;
         stateTime = millis();

         // These next 2 lines were in the STANDBY case, but they are actually code to be executed 
         //  when it *enters* the STANDBY state.  This is not code that should be constantly
         //  executed while you're *in* the STANDBY state.
         digitalWrite(MPFS, HIGH);
         Serial.println("STANDBY");
       }
       break;  // <-- notice!

That’s how you make loop() run without stopping. Until millis() advances by 3000, loop will runrunrun, constantly testing millis()-stateTime. When millis() is finally 3000 bigger than stateTime, the state variables advances to STANDBY, the MPFS pin is set HIGH, and a debug message is printed.

In general, the sketch should be checking something, not waiting for something.

Let’s look at the STANDBY state:

    case STANDBY:
      if (digitalRead(MFC) == LOW)
      {
         delay(2500);
         digitalWrite(BUZZER, HIGH);
         if (digitalRead(NPIS) == LOW)
         {
            currentState = PRINTING;
         }
      } else {
         digitalWrite(BUZZER, LOW);
      }
      break;

Again, you’ve got a blocking delay in there. Just add another state, NPIS_WAIT:

    case STANDBY:
         if (digitalRead(MFC) == LOW) {
            currentState = NPIS_WAIT;
            stateTime = millis();

            // Entering NPIS_WAIT state
            digitalWrite(BUZZER, HIGH); // start the buzzer
            Serial.println("NPIS_WAIT");
         }
         break;

    case NPIS_WAIT:
       // Has the buzzer been on long enough?
       if (millis() - stateTime >= 2500) {
         // yes, turn it off
         digitalWrite(BUZZER, LOW);
       }

       // Time to print?
       if (digitalRead(NPIS) == LOW) {
         currentState = PRINTING;
         stateTime = millis();

         digitalWrite(BUZZER, LOW); // always turn it off?

         Serial.println("PRINTING");

       } else if (millis() - stateTime > 4600) {
          // it has been too long... what should happen here?

          digitalWrite(BUZZER, LOW); // always turn it off?
       }
       break;

The NPIS_WAIT constantly checks three things:

  • is it time to turn the buzzer off?
  • is the NPIS pin LOW?
  • if the NPIS pin is still high, has it been too long?

When any of these happen, in any order, it takes the appropriate action.

Can you apply the same technique to the last state, PRINTING? No delays! :slight_smile:

You could also elaborate a little. I can’t tell if the buzzer is a separate timed activity, outside this state machine. It may get turned on by the state machine, but maybe it gets turned off independently of the currentState/NPIS changes.

Cheers,
/dev

great thanks so much for your help i got the code all working now
sry i didnt explain the code overly well

#define STARTUP 1
#define STANDBY 2
#define NPIS_WAIT 3
#define PRINTING 4


const int NPIS = 2;
const int MFC = 3;
const int PIS = 4;
const int ES = 5;
const int MPFS = 6;
const int BUZZER = 7;

uint32_t stateTime;



void setup() {

  Serial.begin(9600);
  pinMode(NPIS, INPUT);
  pinMode(MFC, INPUT);
  pinMode(PIS, OUTPUT);
  pinMode(ES, OUTPUT);
  pinMode(MPFS, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(PIS, LOW);
  digitalWrite(ES, LOW);
  digitalWrite(MPFS, LOW);
  digitalWrite(BUZZER, LOW);
  stateTime = millis();

}

void loop()
{

  static byte currentState = STARTUP;

  switch (currentState)
  {

    case STARTUP:
      if(millis() - stateTime >= 15000)
      {
        currentState = STANDBY;
        stateTime = millis();
        digitalWrite(MPFS, HIGH);
        Serial.println("STANDBY");
      }
      break;
      
    case STANDBY:
      
      if (digitalRead(MFC) == LOW)
       {
        currentState = NPIS_WAIT;
        Serial.println("NPIS_WAIT");
        stateTime = millis();
      } 
      break;

    case NPIS_WAIT:

    if((millis()- stateTime >= 3500) && (millis() - stateTime <= 4500))
    {
      digitalWrite(BUZZER, HIGH);
    }
    else if (millis() - stateTime > 4600)
    {
      currentState = STANDBY;
      digitalWrite(MPFS, HIGH);
    digitalWrite(BUZZER, LOW);
    }
      
    if(digitalRead(NPIS) == LOW)
    {
      currentState = PRINTING;
      stateTime = millis();
      digitalWrite(BUZZER, LOW);
      Serial.println("PRINTING");
    }
    
    break;

    case PRINTING:

      if (millis() - stateTime <= 1824)
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, LOW);
    Serial.println("PIS IS HIGH");

  }
  else if ((millis() - stateTime >= 1825) && (millis() - stateTime <= 2774))
  {
    digitalWrite(MPFS, HIGH);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - stateTime >= 2775) && (millis() - stateTime <= 3599))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, HIGH);
    digitalWrite(ES, HIGH);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS HIGH");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - stateTime >= 3600) && (millis() - stateTime <= 5474))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, HIGH);
    digitalWrite(BUZZER, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS HIGH");
  }
  else if ((millis() - stateTime >= 5475)&& (millis() - stateTime <= 8475))
  {
    digitalWrite(MPFS, LOW);
    digitalWrite(PIS, LOW);
    digitalWrite(ES, LOW);
    Serial.println("MPFS IS LOW");
    Serial.println("PIS IS LOW");
    Serial.println("ES IS LOW");
  }else if (millis() - stateTime > 8476)
     {
      currentState = STANDBY;
      digitalWrite(MPFS, HIGH);
      Serial.println("STANDBY");
     }
      break;

    
  }

}

one question why a uint32_t instead of a unsigned long?

one question why a uint32_t instead of a unsigned long?

They resolve to the same unsigned 32-bit integer type on most platforms, but using uint32_t makes it explicit that I want a 32-bit unsigned integer.

In the category of more than you wanted to know: The C/C++ language says that int is a compiler-dependent size. It is 16 bits on the 8-bit AVR Arduinos (UNO, Mega, Micro et al), and 32 bits on the 32-bit SAM Arduinos (Due, et al). The uint8_t, int32_t etc. are explicitly-sized types and not subject to "interpretation" by different compilers. Since I write code for multiple platforms, I am in the habit of using these types instead of int or unsigned long.

The PRINTING state looks pretty good, but you might want to consider a sub-state to avoid printing too much:

    case PRINTING:

      switch (printingState) {
        case 0:
          // This part could be performed above, when currentState changes to PRINTING.
          //    It's really code that should be executed upon ENTERing the PRINTING state.
          //    Notice that the time is not checked.
          digitalWrite(MPFS, HIGH);
          digitalWrite(PIS, HIGH);
          digitalWrite(ES, LOW);
          Serial.println("PIS IS HIGH");
          printingState = 1;
          break;

        case 1:
          if (millis() - stateTime >= 1825)
          {
            digitalWrite(MPFS, HIGH);
            digitalWrite(PIS, HIGH);
            digitalWrite(ES, HIGH);
            Serial.println("PIS IS HIGH");
            Serial.println("ES IS HIGH");
            printingState = 2;
          }
          break;

        case 2:
          if (millis() - stateTime >= 2775)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, HIGH);
            digitalWrite(ES, HIGH);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS HIGH");
            Serial.println("ES IS HIGH");
            printingState = 3;
          }
          break;

        case 3:
          if (millis() - stateTime >= 3600)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, LOW);
            digitalWrite(ES, HIGH);
            digitalWrite(BUZZER, LOW);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS LOW");
            Serial.println("ES IS HIGH");
            printingState = 4;
          }
          break;

        case 4:
          if (millis() - stateTime >= 5475)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, LOW);
            digitalWrite(ES, LOW);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS LOW");
            Serial.println("ES IS LOW");
            printingState = 5;
          }
          break;

        case 5:
          if (millis() - stateTime > 8476)
          {
            digitalWrite(MPFS, HIGH);
            printingState = 0; // reset for next time
            currentState = STANDBY;
            Serial.println("STANDBY");
          }
      } // switch (printingState)
      break;

You may have noticed that when it enters the PRINTING state, it prints constantly to the Serial Monitor. This will affect your timing, because Serial.print will "block" when the output buffer is full. For example, printing this:

    MPFS IS LOW
    PIS IS HIGH
    ES IS HIGH

... takes ~40ms. The sketch is stuck at those prints for that time. This is just like using delay( 40 ). The sketch won't be testing millis() constantly, just once per 40ms. This will affect the timing of the digital outputs by the same amount.

Maybe it doesn't matter for your application, but I thought you should see how to implement a sub-state for this timing.

Cheers,
/dev

ok i will try that code, i assume that i have to #define the case 1, case 2, case 3 ... at the top of the sketch like i did with the startup,standby ...?

If you have a name for these timed states, you could #define them at the top, and substitute each name for the number I used. I can't tell what these states should be named. If the numeric state is ok, you can just declare printingState as a uint8_t and use "case 0:" etc.

ok got it working perfectly thanks to you buddy, thank you so much for your help i was pullin my hair out for like a month tryin to figure out the code lol. anyways here’s the new working code

#define STARTUP 1
#define STANDBY 2
#define NPIS_WAIT 3
#define PRINTING 4


const int NPIS = 2;
const int MFC = 3;
const int PIS = 4;
const int ES = 5;
const int MPFS = 6;
const int BUZZER = 7;

uint8_t printingState;
uint32_t stateTime;



void setup() {

  Serial.begin(9600);
  pinMode(NPIS, INPUT);
  pinMode(MFC, INPUT);
  pinMode(PIS, OUTPUT);
  pinMode(ES, OUTPUT);
  pinMode(MPFS, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(PIS, LOW);
  digitalWrite(ES, LOW);
  digitalWrite(MPFS, LOW);
  digitalWrite(BUZZER, LOW);
  stateTime = millis();

}

void loop()
{

  static byte currentState = STARTUP;

  switch (currentState)
  {

    case STARTUP:
      if (millis() - stateTime >= 15000)
      {
        currentState = STANDBY;
        stateTime = millis();
        digitalWrite(MPFS, HIGH);
        Serial.println("STANDBY");
      }
      break;

    case STANDBY:

      if (digitalRead(MFC) == LOW)
      {
        currentState = NPIS_WAIT;
        Serial.println("NPIS_WAIT");
        stateTime = millis();
      }
      break;

    case NPIS_WAIT:

      if ((millis() - stateTime >= 3500) && (millis() - stateTime <= 4500))
      {
        digitalWrite(BUZZER, HIGH);
      }
      else if (millis() - stateTime > 4600)
      {
        currentState = STANDBY;
        digitalWrite(MPFS, HIGH);
        digitalWrite(BUZZER, LOW);
      }

      if (digitalRead(NPIS) == LOW)
      {
        currentState = PRINTING;
        stateTime = millis();
        digitalWrite(BUZZER, LOW);
        Serial.println("PRINTING");
      }

      break;

    case PRINTING:

      switch (printingState)
      {
        case 0:
          digitalWrite(MPFS, HIGH);
          digitalWrite(PIS, HIGH);
          digitalWrite(ES, LOW);
          Serial.println("PIS IS HIGH");
          printingState = 1;
          break;

        case 1:
          if (millis() - stateTime >= 1825)
          {
            digitalWrite(MPFS, HIGH);
            digitalWrite(PIS, HIGH);
            digitalWrite(ES, HIGH);
            Serial.println("PIS IS HIGH");
            Serial.println("ES IS HIGH");
            printingState = 2;
          }
          break;

        case 2:
          if (millis() - stateTime >= 2775)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, HIGH);
            digitalWrite(ES, HIGH);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS HIGH");
            Serial.println("ES IS HIGH");
            printingState = 3;
          }
          break;

        case 3:
          if (millis() - stateTime >= 3600)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, LOW);
            digitalWrite(ES, HIGH);
            digitalWrite(BUZZER, LOW);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS LOW");
            Serial.println("ES IS HIGH");
            printingState = 4;
          }
          break;

        case 4:
          if (millis() - stateTime >= 5475)
          {
            digitalWrite(MPFS, LOW);
            digitalWrite(PIS, LOW);
            digitalWrite(ES, LOW);
            Serial.println("MPFS IS LOW");
            Serial.println("PIS IS LOW");
            Serial.println("ES IS LOW");
            printingState = 5;
          }
          break;

        case 5:
          if (millis() - stateTime > 8476)
          {
            digitalWrite(MPFS, HIGH);
            printingState = 0; // reset for next time
            currentState = STANDBY;
            Serial.println("STANDBY");
          }
      } // switch (printingState)
      break;


  }

}