SoftwareSerial + Interrupt

Hi,

I finally got a second arduino to try out this problem and I think I have managed to come up with a solution. :slight_smile:

It seems that to wake up the sleeping arduino you need the LOW to last for at least 2ms which can be consider as a serial break command.

My code I used to test this

//Sleeping arduino

#include <avr/sleep.h>
#include <SoftwareSerial.h>

#define RXPIN 2
#define TIMEOUT 1000UL

SoftwareSerial mySerial(RXPIN, 4); //pin2 RX, pin4 TX

unsigned long oldtime = 0;

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  sleep_disable();         // first thing after waking from sleep:
  // disable sleep...
  detachInterrupt(digitalPinToInterrupt(RXPIN));      // disables interrupt 0 on pin 2 so the

  Serial.println("Woken!");

  sei();

  mySerial.begin(28800);
  mySerial.print("w"); //tx 'w' so indicate device in awake and ready to receive
  oldtime = millis();

  while (millis() - oldtime < 100) { //wait for 100ms for sender to reply
    if (mySerial.available()) {
      char c = mySerial.read();
      if (c == 'W') {
        Serial.println("WakeUp Acknowledged!");
        break;
      }
    }
  }
}

void sleepNow() {

  sleep_enable();

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  /* Trigger mode of the interrupt pin. can be:
                   LOW        a low level triggers
                   CHANGE     a change in level triggers
                   RISING     a rising edge of a level triggers
                   FALLING    a falling edge of a level triggers

       In all but the IDLE sleep modes only LOW can be used.
  */

  Serial.println("Sleeping Now");
  delay(500);
  mySerial.end();

  attachInterrupt(digitalPinToInterrupt(RXPIN), wakeUpNow, LOW); // wakeUpNow when pin 2 gets LOW

  sleep_mode();
}

void setup() {
  Serial.begin(9600);
  mySerial.begin(28800);
  pinMode(RXPIN, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (millis() - oldtime < TIMEOUT) { //go to sleep if no data received by TIMEOUT
    if (mySerial.available()) {
      oldtime = millis();
      char c = mySerial.read();
      Serial.println(c); //print RX data in serial monitor (as ASCII)
    }
  }
  else {
    mySerial.print("s"); //tells sender it is going to sleep
    sleepNow();
  }
}
//Code for sender

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11, 12);

unsigned long oldtime = 0;

void sendData() {
  char data[9] = "abcdefgh";
  for (char i = 0; i < 8; ++i) {
    mySerial.print(data[i]);
    delay(50);
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  mySerial.begin(28800);
  Serial.println("READY");
  //mySerial.print(NULL);
}

void loop() {
  char otwp;
  // put your main code here, to run repeatedly:
  if (mySerial.available()) {
    otwp = mySerial.read();
    Serial.println(otwp);
  }

  if (otwp == 'w') {
    mySerial.print("W");
    sendData();
  }



  if (millis() - oldtime > 5000) { //send wakeup command every 5s
    digitalWrite(12, LOW);
    delay(2);
    digitalWrite(12, HIGH);
    oldtime = millis();
  }

}

Hope that helps!