Blink without Delay outside loop?

I need to switch an LED and beeper on for 3,000ms then switch it off, without stopping the processing of my mega. But the catch is that the code to call this cannot be inside the main loop. So the BlinkwithoutDelay example cannot work for me as it is.

I have an RFID reader that reads the tags of animals coming through a shoot, sometimes at speed. Once an animal comes through that is marked to be drafted, the LED and beeper comes on for three seconds but the unit needs to be free to read and process the next incoming RFID tags as they come in. The code that reads and processes the RFID's is already within the loop, so inserting a BlinkWithoutDelay type instruction inside the already existing code will cause a delay in processing.

Not sure if I'm making enough sense to get the help I need.

Code coming below.

you could use a timer interrupt to blink the LED
http://www.hobbytronics.co.uk/arduino-timer-interrupts

“so inserting a BlinkWithoutDelay type instruction inside the already existing code will cause a delay in processing.”

BWD, if it written correctly, does not cause program delay.

Always show us your current compete sketch.
Use CTRL T to format the sketch.
Please use code tags. Use the </> icon in the posting menu.

[code] Paste sketch here. [/code]

.

Anything extra will cause a delay, even if it's only a fraction of a microsecond. So your question does not make sense from that perspective :wink:

And interrupts will also add delays :smiley:

Robin2 has an article "demonstration of multiple things at the same time" or something in that line. Possibly worth reading.

With changing my search of around 1,000 EID records from linear to binary I managed to reduce the search time for each EID match to max 170ms. So 1 or 2ms is ok. 3,000ms will not be ok.

The code below DOES NOT COMPILE. My complete sketch is around 1,700 lines - forgive me for just putting an extract below to give you an idea of where I’m at. The LED switch-on instruction is right at the bottom.

    #include <SD.h>  
    #include <SPI.h>                
    #include <Adafruit_RGBLCDShield.h>

    long betweencounts = 120000;       // set idle time before ftp upload and next batch starts
    char *a, *b, *c;
    char DateStamp[24], Balance[10];
    int FileSizeup, LastSectionSize, FTPSections, UploadMaxint;
    int FirstHead, batchSize = 0;
    String dataString, filename, DateStampstr, ParsedBal, cellSignal, Balancestr, FileSizeDownstr;
    char inputChar, sim900response;           
    long mark1, mark2, resttime, timeout, timeoutFTP = 0;
    boolean doFTP = false;
    boolean cls = false;
    boolean errorFlag = false;
    boolean FTPsetup = true;
    boolean FTPsetupdown = true;
    char EID[18];
    const char downFilename[13] = "mastfile.txt";
    int lines, records; 
    int mastFileindex = 0;
    int mastFilepos = 0;
    long int mastFileSize;
    char eidtest[20];
    char vidtest[6];
    char hok[3];
    String SMSbatchHok;
    byte draft;
    boolean fulltag = false;
    boolean match = false;
    int y = 0;
    int EIDalpha = 0;
    long searchstart, searchend;
    int BWint = 0;
    int LKint = 0;
    int LHint = 0;
    int SKint = 0;
    int SHint = 0;
    int SLint = 0;
    int RKint = 0;    
          
    File logFile;
    File mastFile;
    
    Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

    void setup()
    {        
      Serial.begin(9600);
      Serial1.begin(9600);      // RFID
      Serial2.begin(9600);      // SIM900
      pinMode(53, OUTPUT);
      pinMode(22, OUTPUT);      // Green LED - Standby
      pinMode(24, OUTPUT);      // Red LED - Busy
      pinMode(26, OUTPUT);      // Blue LED - Draft
      pinMode(28, OUTPUT);      // Yellow LED - EID Read    
      digitalWrite(24, HIGH);
      lcd.begin(16, 2);
      Serial.println();         
      SDInit();
      ModemReset();              
      SetupGPRS();         
      NTPTime();       
      GetmastFile();
      smsSystemInit();
      standby();   
    }
      
    void loop()
    {              
       digitalWrite(24, LOW);
       digitalWrite(22, HIGH);
       if (Serial1.available())                     
         TagRead();                                                                                    
    }
    
    void TagRead()
    {
       mark2 = mark1;
       mark1 = millis();
       resttime = mark1 - mark2;
       dataString = "";                                                    
       int index = 0;
       while (Serial1.available())
       {
          byte x = Serial1.read();
          if (x == '\r')
             index++;
          if (x == 32);           
          else
          {   
             EID[index] = x;
             index++;
          }
          delay(5);
       } 
       checkMatchandAssignData();                                         
    }

  
    void checkMatchandAssignData()
    {
      if(strcmp(EID, eidtest) == 0)         // CHECK FULL TAGNUMBER IN MASTFILE AGAINST CURRENT EID 
           {
             searchend = millis() - searchstart;
             match = true;
             EIDalpha = 2;          
             mastFilepos = mastFile.position();
             eidtest[0] = '\0';                         
             int z = 0;             
             byte dump = mastFile.read();        // remove comma after tag number            
             if (dump == 13)                    
               dump = mastFile.read();                          
             if (dump == 10)    
               dump = mastFile.read();           
             do                                  // IF MATCH, GIVE VALUES TO CURRENT EID'S VID, HOK, DRAFT
             {               
               vidtest[z] = mastFile.read();               
               if (vidtest[z] == 13)                    
                 vidtest[z] = mastFile.read();                          
               if (vidtest[z] == 10)    
                 vidtest[z] = mastFile.read();               
               z++;
             }   while (vidtest[z - 1] != ',');           
             vidtest[z - 1] = '\0';
             z = 0;                
             do           
             {
               hok[z] = mastFile.read();
               if (hok[z] == 13)                    
                 hok[z] = mastFile.read();                          
               if (hok[z] == 10)    
                 hok[z] = mastFile.read();               
               z++;
             }   while (hok[z - 1] != ',');
             hok[z - 1] = '\0';
             z = 0;                                         
             draft = mastFile.read();             
             if (draft == 13)                    
               draft = mastFile.read();                          
             if (draft == 10)    
               draft = mastFile.read();                           
             if (draft == 49)                                // if draft == 1
                digitalWrite(26, HIGH);
    }

So 1 or 2ms is ok. 3,000ms will not be ok.

Is the comma a separator or a decimal point?

Blink without Delay outside loop?

In an Arduino program loop() should be in charge of everything that needs to repeat or wait.

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing. It may help with understanding the technique.

...R

This example usingMillis() demonstrates how to incorporate the BWD concepts.
Suggest you examine what it does.

/*
  GetRidOfDelay.ino
  LarryD
  Version YY/MM/DD
  1.00    17/02/01  Running code
 
*/
 
//LED wiring:
// +5V---220 ohm resistor---LED anode---LED cathode---Arduino pin
 
const byte heartBeatLED            = 13;    //used to see if the sketch is blocking
const unsigned long heartBeatDelay = 100UL;
const byte myLED                   = 12;    //wired so a LOW turns the LED on
 
//SRAM variables
unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long myLEDmillis;
unsigned long waitTime = 0;
unsigned long currentMicros;
 
byte LEDstate = 0;
 
//                          s e t u p ( )
//**********************************************************************
void setup()
{
  pinMode(heartBeatLED, OUTPUT);
 
  pinMode(myLED, OUTPUT);
  digitalWrite(myLED, HIGH);        //HIGH is LED off
 
} //                 E n d  o f  s e t u p ( )
 
//                          l o o p ( )
//**********************************************************************
void loop()
{
  currentMillis = millis(); //for milli second timing
  currentMicros = micros(); //for mirco second timing
 
  //***************************
  //HeartBeat LED, should toggle every heartBeatDelay milliseconds if code is nonblocking
  if (currentMillis - heartBeatMillis >= heartBeatDelay)
  {
    heartBeatMillis = heartBeatMillis + heartBeatDelay; //reset timing
 
    //Toggle heartBeatLED
    digitalWrite(heartBeatLED, !digitalRead(heartBeatLED));
  }
 
  //***************************
  //swap the comment marks // on the next two lines to see a comparison
 
  //usingDelay();
  usingMillis();
 
 
} //                    E n d  o f  l o o p ( )
 
//======================================================================
//                        F U N C T I O N S
//======================================================================
 
//                     u s i n g D e l a y ( )
//**********************************************************************
void usingDelay()
{
  digitalWrite(myLED, LOW);  //LOW  is LED on
  delay(2000);
  digitalWrite(myLED, HIGH); //HIGH is LED off
  delay(1000);
  digitalWrite(myLED, LOW);  //LOW  is LED on
  delay(500);
  digitalWrite(myLED, HIGH); //HIGH is LED off
  delay(250);
 
}//                E n d  o f  u s i n g D e l a y ( )
 
//                     u s i n g M i l l i s ( )
//**********************************************************************
void usingMillis()
{
  //is it time to process the next state code?
  if (currentMillis - myLEDmillis < waitTime)
  {
    //No, it is not time
    return;
  }
 
  //Yes, it is now time
  myLEDmillis = currentMillis;     //reset timing
 
  //state code
  switch (LEDstate)
  {
    case 0:
      digitalWrite(myLED, LOW);    //turn LED on
      LEDstate = 1;                //next state
      waitTime = 2000UL;           //setup the wait value
      break;
 
    case 1:
      digitalWrite(myLED, HIGH);   //turn LED off
      LEDstate = 2;                //next state
      waitTime = 1000UL;           //setup the wait value
      break;
 
    case 2:
      digitalWrite(myLED, LOW);    //turn LED on
      LEDstate = 3;                //next state      
      waitTime = 500UL;            //setup the wait value
      break;
 
    case 3:
      digitalWrite(myLED, HIGH);   //turn LED off
      LEDstate = 0;                //next state
      waitTime = 250UL;            //setup the wait value
      break;
 
  } //End of switch/case
 
}//                E n d  o f  u s i n g M i l l i s ( )
 
//======================================================================
//                        E N D  O F  C O D E
//======================================================================

.

AWOL:
Is the comma a separator or a decimal point?

Decimal point. If the program stops for 3 seconds
a few animals will make their way past the reader without being read.

heinburgh:
Decimal point. If the program stops for 3 seconds
a few animals will make their way past the reader without being read.

I think you have completely failed to understand things here.

The entire point of the Blink Without Delay concept is to be able to time things without stopping the rest of the program.

Jiggy-Ninja:
I think you have completely failed to understand things here.

The entire point of the Blink Without Delay concept is to be able to time things without stopping the rest of the program.

I thought this was exactly what I am after.

Thanks for the leads, I'm on it. Are there any cons to using timer interrupts?

Never mind how the Code works, I want to see this :slight_smile:

animals coming through a shoot, sometimes at speed.

ian332isport:
Never mind how the Code works, I want to see this :slight_smile:

Not much to see, a bit boring really. It’s a bit like counting sheep. Come to think of it, that’s exactly what my sketch does. It counts sheep :wink:

Why do you need to get into the complication of using a timer interrupt ?

The code can all be contained within the loop() function without delaying anythng.

start of loop()
  if a new tag is present
    add 1 to the count
    set buzzer flag to true
    save buzzer start time   
  end if
  
  if the buzzer period has passed
    turn off the buzzer
    set buzzer flag to false
  end if
  
  if the buzzer flag is true
    turn on the buzzer
  end if
end of loop()

ian332isport:
Never mind how the Code works, I want to see this :slight_smile:

animals coming through a shoot, sometimes at speed.

If people were shooting at me I would always be at speed. Poor animals :slight_smile:

…R

Robin2:
If people were shooting at me I would always be at speed. Poor animals :slight_smile:

...R

Aaah. Ok. Chute, not shoot.

heinburgh:
I thought this was exactly what I am after.

It is exactly what you want. This why this...

But the catch is that the code to call this cannot be inside the main loop. So the BlinkwithoutDelay example cannot work for me as it is.

...is nonsense.

Thanks for the leads, I'm on it. Are there any cons to using timer interrupts?

A Timer interrupt will work, but it's not necessary.

Ok, so you have a long loop that is waiting on blocking I/O, and it doen't make a lot of sense to recode it all as a state machine.

Fair enough.

Write a pair of functions:

boolean beeping = false;
unsigned long beepStartMs;

void startBeep() {
  digitalWrite(beeperPin, HIGH);
  beepStartMs = millis();
  beeping = true;
}

void handleBeep() {
  if(beeping && millis()-beepStartMs >= 3000) {
    digitalWrite(beeperPin, LOW);
    beeping = false;
  }
}

Then make sure that that handleBeep function is called periodically. Obviously, you put a call to it in the loop(). But your main problem is the I/O, so add a call to that function in your I/O loops.

Oh by the way: I think your code wont work. Your read of EID exits the loop as soon as !available, and there's no guarantee that your data stream won't be coming in in lumps. That is, after reading a few bytes there might be a tiny delay before reading the next few. This will trigger a premature exit and call to checkMatchandAssignData.

Furthermore, checkMatchandAssignData does a if(strcmp(EID, eidtest) == 0), but TagRead does not properly terminate EID with a '\0'.

Oh, and this:

         if (x == '\r')
             index++;
          if (x == 32);          
          else
          {  
             EID[index] = x;
             index++;
          }

will have curious behaviour when a '\r' is read. index will be incremented, meaning that whatever crud happened to be lying around in memory in EID will be left there. And then, because '\r' ≠ 32, it will be written out to EID.

That is, let's say that the stack is full of lowercase letter 'a' written there by a previous operation, and the following is read from Serial1 'bc de\rfg'.

EID will contain "bcdea\rfg".

Oh - why 32 and not simply ' '?

This is the blink without delay code structure they are talking about :slight_smile:

unsigned long DelayTimer;
void loop(){
  if ((millis() - DelayTimer) >= (3000)) { // Check the timer only if time has passed we turn off the LED and beeper
    digitalWrite(BuzzerPin, LOW); // now after 3 seconds we will turn this off
  }
  if (Serial1.available())        
    TagRead(); 
}
// now Else where in your code
void scanningCode(){
   if(WeFoundTheOne){
      DelayTimer = millis(); // Start the timer
      digitalWrite(BuzzerPin, HIGH); //<<< Turn the Beeper on and the LED
}

Z

Jiggy-Ninja:
It is exactly what you want. This why this......is nonsense.A Timer interrupt will work, but it's not necessary.

You're right, that was nonsense. In my loop there are functions that call other functions that call more functions, uploading and downloading files by ftp, setting up gprs, etc. Some of them take up mintes at a time, which had me thinking I had to put this functionality outside loop(). UKHeliBob with his usual back to basics approach helped me to realise I just had to put the code in the right place within the loop.

The code works, no interrupt needed, just good old millis().

Thanks for the inputs everyone.