Missing Serial data due to hardware Interrupt

Hi guys I am doing a project which includes receiving Serial data from esp8266 and I am using Hardware interrupt. It is a zero detector that trigger the hardware interrupt and occur every 10ms. Due to interrupt I am losing Serial data coming from esp8266 during the interrupt, is there a way in which I can keep serial data while not doing anything to the interrupt because interrupt is also important.

umairrafiq13:
is there a way in which I can keep serial data while not doing anything to the interrupt

Probably not.

But not because it is not possible, but because you do not want to change your faulty interrupt handling.

Ok what changes I need to make in the interrupt to keep my serial data.

Line 34 looks suspicious to me.

AWOL:
Line 34 looks suspicious to me.

+1

...R

More than a slight hint of the XY problem! :astonished:

umairrafiq13:
Hi guys I am doing a project which includes receiving Serial data from esp8266 and I am using Hardware interrupt. It is a zero detector that trigger the hardware interrupt and occur every 10ms. Due to interrupt I am losing Serial data coming from esp8266 during the interrupt

That's hard to believe. But without seeing circuit schematics and source code, there are millions of mistakes possible.

Are you possibly using some kind of software emulated serial interface for the purpose of "losing Serial data" like perhaps ""SoftwareSerial" or something like that? In that case the solution would be easy: Use a HardwareSerial interface on the microcontroller board to receive serial data!

Many Arduino boards offer more than just one hardwareSerial interface, i.e. an Arduino MEGA2560 offers four Serial interfaces in hardware, fully functional with the Arduino core library up to 500000 baud.

#define DEBUG true
#define SSID "EE-Dept"
#define PASS "pak_1947"
#define staticip "192.168.1.99"
String cmd;
int dimming=0;

void setup() {

pinMode(5,OUTPUT);
digitalWrite(5,LOW);

pinMode(6,OUTPUT);
digitalWrite(6,LOW);

pinMode(7,OUTPUT);
digitalWrite(7,LOW);

Serial.begin(115200);
Serial3.begin(115200);

sendCommand("AT+RST",2000,DEBUG);
sendCommand("AT+CWMODE=2",3000,DEBUG); // wifi mode 3rd mode i-e ap+station
/* cmd="AT+CIPSTA=""; //set ip adress of esp8266 station
cmd+=staticip;
cmd+=""";
sendCommand(cmd,1000,DEBUG);
cmd="AT+CWJAP=""; // connect to AP(AT+CWJAP=,)
cmd+=SSID;
cmd+="","";
cmd+=PASS;
cmd+=""";
sendCommand(cmd,20000,DEBUG);*/
sendCommand("AT+CIPMUX=1",1000,DEBUG); //set multiple connection mode
sendCommand("AT+CIPSERVER=1,8888",1000,DEBUG); //configure as server
sendCommand("AT+CIFSR",1000,DEBUG); //get local ip adress

Serial.println("Server Ready");
attachInterrupt(0,zerocrossing,RISING);
// put your setup code here, to run once:

}

void loop() {
if(Serial3.available())
{
int connectionId;
String content;
delay(50);
Serial.println("Listening to Serial3");
if(Serial3.find("+IPD,")) // data recieve from network
{
//delay(500);
connectionId= Serial3.read()-48;
Serial.print("Connection number=");
Serial.println(connectionId);

if(Serial3.find("pin="))
{
int pinNumber =(Serial3.read()-48);
Serial.print("Request of changing status of pin ");
Serial.println(pinNumber);
if(pinNumber==8){
syncdata(connectionId);
}
else if(pinNumber==0){

if(Serial3.find(","))
{
dimming=(Serial3.read()-48)*10;
dimming=dimming+(Serial3.read()-48)*1;
Serial.println(dimming);
content+="Fan speed ";
content+=dimming;
sendHTTPResponse(connectionId,content);
}

}
/* else {
digitalWrite(pinNumber, !digitalRead(pinNumber));

if(digitalRead(pinNumber))
{
content += "{"Lights":[{"Status":"Pin ";
content+=pinNumber;
content+=" ON"}] }";
}
else
{
content += "{"Lights":[{"Status":"Pin ";
content+=pinNumber;
content+=" OFF"}] }";
}

sendHTTPResponse(connectionId,content);
}*/

}

}

}
}
String sendData(String command,const int timeout, boolean debug)
{
String response = "";

int dataSize = command.length();
char data[dataSize];
command.toCharArray(data,dataSize);

Serial3.write(data,dataSize);
if(debug)
{
Serial.println("\r\n=============HTTP Response From Arduino =====");
Serial.write(data,dataSize);
Serial.println("\r\n=============================================");
}
long int time = millis();

while( (time+timeout) > millis())
{
while(Serial3.available())
{

char c = Serial3.read(); // read the next character.
response+=c;
}
}

if(debug)
{
Serial.println(response);
}

return response;
}

void sendHTTPResponse(int connectionId,String content)
{

String httpResponse;
String httpHeader;

httpHeader = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset-UTP-8\r\n";
httpHeader += "Content-Length: ";
httpHeader += content.length();
httpHeader += "\r\n";
httpHeader += "Connection: close\r\n\r\n";
httpResponse = httpHeader + content + " " ;
sendCIPData(connectionId,httpResponse);

}

void sendCIPData(int connectionId,String data)
{

String cipSend= "AT+CIPSEND="; //send data(AT+CIPSEND=,)
cipSend += connectionId;
cipSend +=",";
cipSend +=data.length();
sendCommand(cipSend,1000,DEBUG);
sendData(data,1000,DEBUG);
}
void sendCommand(String command,const int timeout, boolean debug)
{
String response = "";

Serial3.println(command);
long int time = millis();

while( (time+timeout) > millis())
{
while(Serial3.available())
{

char c = Serial3.read(); // read the next character.
response+=c;
}
}

if(debug)
{
Serial.println(response);
}
}
void syncdata(int connectionId)
{
String content;
content += "{"Lights":[{";
for(int i=5;i<7;i++){
if(digitalRead(i))
{
content+=""Status";
content+=i;
content+="":"Pin";
content+=" ON",";
}
else
{
content+=""Status";
content+=i;
content+="":"Pin";
content+=" OFF",";
}
}
if(digitalRead(7))
{
content+=""Status";
content+="7";
content+="":"Pin";
content+=" ON"";
}
else
{
content+=""Status";
content+="7";
content+="":"Pin";
content+=" OFF"";
}

content+="}]}";
sendHTTPResponse(connectionId,content);
}
void connectioncloser(){

while(!Serial3.find("CLOSED"))
{

}
}
void zerocrossing()
{
int dimtime=(77*dimming);
delayMicroseconds(dimtime);
digitalWrite(7,LOW);
delayMicroseconds(10);
digitalWrite(7,HIGH);
}

umairrafiq13:
delay(50);

I think your missing characters are caused by using too much delay (do-nothing-time) in the loop which wil lead so an overflow of the serial input buffer.

The Serial input buffer can hold up to 63 characters maximum.

With a baudrate of 115200 there may be transmitted 11520 characters per second, that' s 11520*50/1000= 576 characters in 50 milliseconds.

So while you are celebrating the blocking of your program with a "delay(50"); command in your loop() code, there might arrive up to 576 characters on the serial interface while the serial input buffer can store only 63 characters, and depending on the actual number of characters that arrive during the delay times, you might lose many hundred characters per second, just because your code is blocking program execution with delay and you are not reading incoming serial input during those delay times.

Waiting in an ISR that is called all 10 mS for up to 7,6 mS is a bad idea.

And the 7,6 mS are only guaranteed for legal, wellformed input.
If you manage to raise the value above 10mS your Arduino will lock,
because there is no time left for any activity.

Try to be prepared to be bombarded with any input, even malicious,
you have no control over the sending side.

I dislike comments that contradict the obvious facts.

sendCommand("AT+CWMODE=2",3000,DEBUG); // wifi mode 3rd mode i-e ap+station

@jurs

delay(50); is there so can serial buffer can fill up with data otherwise it is too quick that serial.find() could not run properly because there is nothing there to find.
Code run fine without interrupt as soon as interrupt start doing his job everything malfunctions.

@whandall

Sorry I edit code very often so forgot to change the comments too.
And
dimtime=(77*dimming);
delayMicroseconds(dimtime);
digitalWrite(7,LOW);
delayMicroseconds(10);
digitalWrite(7,HIGH);

that timing is calculated with 50 Hz frequency to dim an ac lamp.
Can work between 0-128 @128 9.8ms so dimtime cannot be more than 10ms.

Please use code tags </> to present code.

At 115kBaud a character is received every 0.1ms. Every delay that blocks for a longer time can cause loss of characters.

You have to replace all delays (including delayMicroseconds) by non-blocking code, e.g. using a timer and timer interrupts.

umairrafiq13:
that timing is calculated with 50 Hz frequency to dim an ac lamp. Can work between 0-128 @128 9.8ms so dimtime cannot be more than 10ms.

But only if you get the expected numbers in the conversion.

dimming=(Serial3.read()-48)*10;
dimming=dimming+(Serial3.read()-48)*1;

I would replace the number by a "zz" to stall your Arduino.

@Whandall

I appreciate your findings in my code and I will change my code so I make sure I can get the expected numbers in conversion.

@DrDiettrich

Thanks Now I have to study timers in arduino and I will use them in my project and will post my findings here.Any other solution will be appreciated.

I thin your approach is so wrong. You check if data is available and next you keep on reading and reading and reading, even if there was only be one byte available.

You should read some data, check, read some more data, check, .....

Your loop actually calls for a statemachine.

As I see it
1)
wait for '+IPD,'
2)
get connectionID
3)
wait for 'pin='
3)
get pin number
4a)
wait for pin data
4b)
sync
5)
process pin data

I might have missed something, but you can adjust the below to your needs

The basics
read one character and add to buffer
check/process buffer based on what needs to be received in that state

Variables used and state names

// serial  buffer
String serialBuffer = "";
// received pin number
int pinNumber = -1;
// received connection id
int connectionID;

String content;

// sensible (?) names for the states that our loop() can be in
#define ST_WAITFOR_IPD 0      // wait for '+IPD,'
#define ST_GET_ID 1           // get connecttion id
#define ST_WAITFOR_PIN 2      // wait for 'pin='
#define ST_GET_PIN 3          // get and process pin number
#define ST_WAITFOR_PINserialBuffer 4  // wait for pin serialBuffer 
#define ST_GET_PINserialBuffer 5      // get and process pin serialBuffer
#define ST_SYNC 6             // whatever

// current state; start with waiting for '+IPD,'
byte currentState = ST_WAITFOR_IPD;

Note: the loop() contains a timeout functionality.
loop()

void loop()
{
  // remember when last byte was received
  static unsigned long lastbyteMillis = millis();
  
  int index = 0;
  int dimming = -1;

  if (Serial3.available() > 0)
  {
    serialBuffer += Serial3.read();
    lastbyteMillis = millis();
  }

  // check for timeout during receive
  if(millis() - lastbyteMillis >= 1000)
  {
    // clear the current data
    serialBuffer = "";
    // reset state
    currentState = ST_WAITFOR_IPD;
    // done
    return;
  }


  switch (currentState)
  {
    case ST_WAITFOR_IPD:
      index = serialBuffer.indexOf("+IPD,");
      // if we got '+IPD,'
      if (index >= 0)
      {
        // clear the serialBuffer
        serialBuffer = "";
        // go to next state
        currentState = ST_GET_ID;
      }
      break;
    case ST_GET_ID:
      // if a byte received
      if (serialBuffer != "")
      {
        // convert to int
        connectionID = serialBuffer.charAt(0) - 48;
        // clear the serialBuffer
        serialBuffer = "";
        // go to next state
        currentState = ST_WAITFOR_PIN;
      }
      break;
    case ST_WAITFOR_PIN:
      index = serialBuffer.indexOf("pin=");
      // if we got 'pin='
      if (index >= 0)
      {
        // clear the serialBuffer
        serialBuffer = "";
        // go to next state
        currentState = ST_GET_PIN;
      }
      break;
    case ST_GET_PIN:
      // if a byte received
      if (serialBuffer != "")
      {
        // convert to int
        pinNumber = serialBuffer.charAt(0) - 48;
        // check
        if (pinNumber == 8)
        {
          currentState = ST_SYNC;
        }
        else if (pinNumber == 0)
        {
          currentState = ST_WAITFOR_PINserialBuffer;
        }
        // clear the serialBuffer
        serialBuffer = "";
      }
      break;
    case ST_SYNC:
      // do what we have to do
      syncdata(connectionID);
      // finished, back to beginning
      currentState = ST_WAITFOR_IPD;
      break;
    case ST_WAITFOR_PINserialBuffer:
      if (serialBuffer == ",")
      {
        serialBuffer = "";
        currentState = ST_GET_PINserialBuffer;
      }
      break;
    case ST_GET_PINserialBuffer:
      if (serialBuffer.length() == 2)
      {
        // process
        dimming = (serialBuffer.charAt(0) - 48) * 10;
        dimming = dimming + (serialBuffer.charAt(1) - 48);
        Serial.println(dimming);
        content += "Fan speed ";
        content += dimming;
        sendHTTPResponse(connectionID, content);

        // clear the serialBuffer
        serialBuffer = "";
        // finished, back to beginning
        currentState = ST_WAITFOR_IPD;
      }
      break;
    default:
      Serial.print("Unknow state "); Serial.println(currentState);
      currentState = ST_WAITFOR_IPD;
      break;

  }
}

Use this as a base; I leave the debugging up to you :wink:

@sterretje

I copy pasted your code and will try it but doing a few changes to hardware right now.

Is it ok if I use your code? my coding is not better than yours.

sterretje:
int index = 0;
int dimming = -1;

I think index=-1 and dimming=0 is more appropriate.

Of course you can use this code; it's provided as is to give you an idea for a different approach. If you don't understand it, ask or don't use it as you are the one that has to maintain it in future.

The initial value of 'index' should not matter; the value is only evaluated after a call to serialBuffer.indexOf().

Thank All of you for helping me
I used Timer interrupts to solve this problem

@sterretje

I edit some of your code and make it work for me Thanks for giving me a new approach

@DrDiettrich

Thanks for Timer interrupt suggestion.

Code file is attached. Code is too long to be posted here.

newcoding_debugging.ino (8.79 KB)

AWOL:
Line 34 looks suspicious to me.

nope, definitely line 0, missing code tag !