Is there an interrupt for serial communication?

This is a door lock system that turns on a magnetic strike if an SMS or a signal from a bluetooth device is received. It also has an image capturing feature via adafruit motion camera.

Everything works fine, except that when an image is being written in the SD card, serial communications are "paused" until data transfer is done. While the transfer is in process, it does not read any signal or message from SMS and bluetooth, when transfer is finished, it is the time when the board will read any sent data from the SMS and bluetooth. Is there a way that we can still read data from the bluetooth and sms even if the data transfer is in progress, like an interrupt of sort? thanks in advance for the response.

Here is the code(sorry if it's constructed poorly):

//SIM900D library
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "sms.h"
SMSGSM sms;

//SD Card Library
#include <SD.h>
#define chipSelect 53

//Camera library
#include <Adafruit_VC0706.h>
Adafruit_VC0706 cam = Adafruit_VC0706(&Serial1);

// PIR Variables
int pirPin = A0; // Sensor input 
int sensorValue = 0;
int buzzer;

// SMS Variables
int numdata;
boolean initialized = false; //Initialize loop.
char smsbuffer[160];
char n[20];
char StrikeKey[100] = "UNLOCK"; // Message to Unlock strike.
int StrikePin = 13; //Strike Pin.
char AdminNumber[20];
char AdminNumber1[20];

// Variables to be read by serial terminal (SMS)
char sms_position;
char phone_number[20];
char sms_text[100];
int i;

// SMS Trigger Variables
boolean motionSensed = false;

void setup()
{
  
  //Camera
  #if !defined(SOFTWARE_SPI)
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  if(chipSelect != 53) pinMode(53, OUTPUT); // SS on Mega
#else
  if(chipSelect != 10) pinMode(10, OUTPUT); // SS on Uno, etc.
#endif
#endif

  Serial.println("VC0706 Camera test");
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }  
  
  // Try to locate the camera
  if (cam.begin()) {
    Serial.println("Camera Found:");
  } else {
    Serial.println("No camera found?");
    return;
  }
  // Print out the camera version information (optional)
  char *reply = cam.getVersion();
  if (reply == 0) {
    Serial.print("Failed to get version");
  } else {
    Serial.println("-----------------");
    Serial.print(reply);
    Serial.println("-----------------");
  }

  // Set the picture size - you can choose one of 640x480, 320x240 or 160x120 
  // Remember that bigger pictures take longer to transmit!
  
  //cam.setImageSize(VC0706_640x480);        // biggest
  cam.setImageSize(VC0706_320x240);        // medium
  //cam.setImageSize(VC0706_160x120);          // small

  // You can read the size back from the camera (optional, but maybe useful?)
  uint8_t imgsize = cam.getImageSize();
  Serial.print("Image size: ");
  if (imgsize == VC0706_640x480) Serial.println("640x480");
  if (imgsize == VC0706_320x240) Serial.println("320x240");
  if (imgsize == VC0706_160x120) Serial.println("160x120");


  //  Motion detection system can alert you when the camera 'sees' motion!
  cam.setMotionDetect(true);           // turn it on
  //cam.setMotionDetect(false);        // turn it off   (default)

  // You can also verify whether motion detection is active!
  Serial.print("Motion detection is ");
  if (cam.getMotionDetect()) 
    Serial.println("ON");
  else 
    Serial.println("OFF");
  
  if (!SD.begin()) 
  {
    Serial.println("initialization failed!");
  }
  else
  {
     Serial.println("initialization done.");
   }
    
    
    File Number1 = SD.open("Admin.txt");
  if (Number1) {
    // read from the file until there's nothing else in it:
    while (Number1.available()) {
    	AdminNumber[20] = Serial.write(Number1.read());
    }
  } 
   File Number2 = SD.open("Admin.txt");
  if (Number2) {
    // read from the file until there's nothing else in it:
    while (Number2.available()) {
    	AdminNumber1[20] = Serial.write(Number2.read());
    }
  } 
  else 
  {
    Serial.println("error opening test.txt");
  }
  //Camera Setup
  
  
    
  // Pin Mode
  pinMode(pirPin, INPUT);
  pinMode(StrikePin, OUTPUT); 
  
  // Pin Initial State
  digitalWrite(StrikePin, LOW);
  //Blueooth Baud Rate
  Serial2.begin(9600);
  // GSM Baud Rate
  Serial.begin(9600);
  
}

// Loop Void Functions
void loop()
{
  MotionDetectCamera();
  /*if (digitalRead(4) == HIGH)
  {
    initialized = true;
    gsm.begin(9600);*/
    if (initialized == true)
    {
      sensor();
      strikeSMS();
    }
  //}
  
}

void serialEvent2()
{
  byte  BluetoothVal = Serial2.read();
    Serial2.read();
    if (BluetoothVal == 5)
    {
      digitalWrite(StrikePin,HIGH);
      Serial.print("OPEN");
      delay(10000);
      digitalWrite(StrikePin,LOW);
    }
}

void sensor()
{
  // Read sensor value, if value > 0, motion = true
  sensorValue = analogRead(pirPin);
  if (analogRead(sensorValue) > 0)
  {
    motionSensed = true;    
    Serial.println(motionSensed);
  }
}

void strikeSMS()
{
    
        sms_position=sms.IsSMSPresent(SMS_UNREAD);
        if (sms_position) 
        {
          // Print Variables.
            Serial.print("SMS postion:");
            Serial.println(sms_position,DEC);
            sms.GetSMS(sms_position, phone_number, sms_text, 100);
            Serial.println(phone_number);
            Serial.println(sms_text);
         
            // Read last message, then Turn on Strike
            if ((strstr(sms_text, StrikeKey)) && ((strstr(phone_number, AdminNumber)) || (strstr(phone_number, AdminNumber1))))
             {
              digitalWrite(StrikePin,HIGH);
              delay(5000); // Turn off after 5 Seconds
              digitalWrite(StrikePin,LOW);
              sms.DeleteSMS((int)sms_position); // Delete message to free space.
              Serial.println("Message Deleted.");
             }
            else if ((strstr(sms_text, !StrikeKey)) || ((strstr(phone_number, !AdminNumber)) || (strstr(phone_number, !AdminNumber))))
             {
               sms.SendSMS(phone_number, "Invalid Key!");
               sms.DeleteSMS((int)sms_position);
             }
        
        delay(1000);
    }
}

void SMSnotification()
{
  // If PIR sensed Motion...
  if (motionSensed == true)
  {
    if (sms.SendSMS(AdminNumber, "Someone entered the hall. Possible infiltrator may be inside."))
        {
          motionSensed = false;
          Serial.println("\nSMS sent OK.");
          Serial.println(motionSensed);
        }
        else
        {
          Serial.println("\nError sending SMS.");
        }
  }
}



void MotionDetectCamera(){
 if (cam.motionDetected()) {
   Serial.println("Motion!");   
   cam.setMotionDetect(false);
   
  if (! cam.takePicture()) 
    Serial.println("Failed to snap!");
  else 
    Serial.println("Picture taken!");
  
  char filename[13];
  strcpy(filename, "IMAGE00.JPG");
  for (int i = 0; i < 100; i++) {
    filename[5] = '0' + i/10;
    filename[6] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename)) {
      break;
    }
  }
  
  File imgFile = SD.open(filename, FILE_WRITE);
  
  uint16_t jpglen = cam.frameLength();
  Serial.print(jpglen, DEC);
  Serial.println(" byte image");
 
  Serial.print("Writing image to "); Serial.print(filename);
  
  while (jpglen > 0) {
    // read 32 bytes at a time;
    uint8_t *buffer;
    uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
    buffer = cam.readPicture(bytesToRead);
    imgFile.write(buffer, bytesToRead);

    //Serial.print("Read ");  Serial.print(bytesToRead, DEC); Serial.println(" bytes");

    jpglen -= bytesToRead;
  }
  imgFile.close();
  Serial.println("...Done!");
  cam.resumeVideo();
  cam.setMotionDetect(true);
 } 
}

If I remember correctly once I saw a schematic where RX was attached to INT0, every time RX was receiving someting it triggered the external interrupt int0.

Except then the interrupt will fire on the first incoming bit of the serial transmission and waiting for all 9 bits to follow will take too long - it will lock up the processor in the interrupt routine.

So, then you need the interrupt to count up to 9 to check "did we recieve a complete char yet" and only do the action once the char is completed, but after it's complete, there's no more transitions on the line to trigger the interrupt.

I notice you are using serialEvent2() The Arduino documentation says that this works like an interrupt except it doesn't: it only looks to see if there is any serial data ready after the end of loop(). This means that, for proper use of this functionality, your loop() function needs to end frequently. Don't let it complete a long operation like writing a large image. Make it stop at several points in this process and give the serial event a chance to see if there's data incoming.

Make it stop at several points in this process and give the serial event a chance to see if there's data incoming.

How can we do that?

Also we tried a timer interrupt in a sample code concerning the bluetooth and a simple while loop that prints its increment, removed the serialEvent2() and placed the bluetooth function in that serial event to the interrupt. It did stopped the process, turned on the strike but, as you said, locked up the processor in the interrupt routine. It stopped at digitalWrite(StrikePin,HIGH); and stayed in there. We tried to remove the delay and produced the same output. What went wrong? Here's the code we tried.

#define StrikePin 13

void setup()
{
  Serial2.begin(9600);
  Serial.begin(9600);
  pinMode(StrikePin, OUTPUT);

  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  TCNT1 = 34286;            // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 34286;            // preload timer
byte  BluetoothVal = Serial2.read();
    Serial2.read();
    if (BluetoothVal == 5)
    {
      
      digitalWrite(StrikePin,HIGH);
      delay(10000);
      digitalWrite(StrikePin,LOW);
 
    }

}

void loop()
{
       
  for(int j=0;j<100000;j++)
  {
   Serial.print(j);
  }
}

ZhyCore:
How can we do that?

It looks like this piece of code does not all have to be completed in a single pass through loop()

 while (jpglen > 0) {
    // read 32 bytes at a time;
    uint8_t *buffer;
    uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
    buffer = cam.readPicture(bytesToRead);
    imgFile.write(buffer, bytesToRead);

    //Serial.print("Read ");  Serial.print(bytesToRead, DEC); Serial.println(" bytes");

    jpglen -= bytesToRead;
  }

Also I spotted delay(1000) somewhere - that can't help. Use millis() to manage timing in a non-blocking way as in several things at a time.

....R

It seems like the delay at the program is what causes the trouble in the interrupt. We removed it and placed the delay in our bluetooth app in android. We'll be trying to implement millis() in our program for the turn on and turn off of the strike for the GSM function. Thanks for your help kind sirs. Will it really affect the interrupt, as said in our previous searches, if we will be using a Serial.print inside the interrupt function?

ZhyCore:
It seems like the delay at the program is what causes the trouble in the interrupt.

You put "delay()" in a real program?

Will it really affect the interrupt, as said in our previous searches, if we will be using a Serial.print inside the interrupt function?

Yes, it stands a really good chance of preventing your sketch from running.

char AdminNumber[20];

     AdminNumber[20] = Serial.write(Number1.read());

Writing into the 21st byte of a 20-byte array is a bad mistake. AdminNumber contains 20 bytes indexed 0 through 19.

ZhyCore:
Will it really affect the interrupt, as said in our previous searches, if we will be using a Serial.print inside the interrupt function?

Ah dear! :astonished:

You really do not understand interrupts, do you?

Yes, it is a "newbie" trap to be sure.

The whole concept of an interrupt is that a critical operation which it is necessary to perform with a very small delay of an event occurring and which can be dealt with - not necessarily completely, but the necessary action can be initiated and allowed to proceed - very quickly, can be performed without significantly affecting or altering the operation of the main program stream in any way apart from a negligible delay.

"Talking" on the serial port fails this criterion badly - it is a slow process. In order to perform slow processes simultaneously, you need to arrange your code to perform them piecemeal, continuously alternating between performing one step of one process if it is ready to do so, one step of the next process, then the next, and so on.

This frequently means that you cannot use the basic libraries because calls to functions generally do not return until the whole process is complete. You need buffered functions (such as Serial.read) which provide a "ready" function (Serial.available) so that unless they are ready to perform the next step, you pass on to the next process in your list.

I also wonder what you think a "return" in the setup() function will do?

  sensorValue = analogRead(pirPin);
  if (analogRead(sensorValue) > 0)

It makes no sense to use the value returned by analogRead() as the pin number in another analogRead(). You probably meant:

  sensorValue = analogRead(pirPin);
  if (sensorValue > 0)