Program freezing after receiving data from serial

Hello Everyone,

I need some help with my code as it seems to crash.

I have 2 Arduino Uno with HC-12 on each,

The Number1 is waiting to receive an A when it does it sends B.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); //RX, TX
char rc;

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
}

void loop() {
  while (mySerial.available() > 0) {
  rc = mySerial.read();
  Serial.print(rc);
   if(rc == 'A'){
    mySerial.print('B');
    Serial.print("Sent B");
    } 
  }      
}

The Number2 is what seems to have the problem.

First, off I have reduced the sleep count to 4 on purpose so we don't have to wait too long, I am aware that it can be set to a max of 8, however, I would like it to sleep for longer than 8 so I have put the sleep delay so when it wakes if the sleep delay is less than 2 it will go back to sleep. when it wakes and the sleep delay is exceeded it will then send A to the Number1 and then Number1 will then send back B.

When the Number2 receives back the B it freezes

#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <SoftwareSerial.h>


//--------------- Declare Software serial pins -----------------------

SoftwareSerial mySerial(2, 3); //RX, TX

//-------------- Declare sleep wake varaibales ------------------------

volatile char sleepCnt = 4;  // makes the arduino sleep for ex amount of seconds 8 max.
char sleepDelay = 0;  // makes the arduino sleep for ex amount of seconds 8 max.
bool wake = false;    // Initialy set wake false

//---------------- Millis statment declarations ------------------------

unsigned long currentTime;
unsigned long previousTime = 0;

//--------------------- General variables ------------------------------

int connectionCount = 0;
char serialGo;              // read the serial port if the correct caracter is recieved start sending data.
bool sendData = false;      // Failsafe to stop data being sent at the wrong time.
const int statusLED = 7;    // output pin for the LED

void setup() {

  Serial.begin(9600);
  mySerial.begin(9600);
  pinMode(statusLED, OUTPUT);
}

void loop() {
  currentTime = millis();

  if (sleepDelay <= 2 && wake == false) {
    sleepDelay ++;
    Sleeping();
  }
  else if (sleepDelay > 2 && wake == false) {
    wake = true;
    sleepDelay = 0;                             // Reset the sleep delay to zero
    serialGo = mySerial.read();
  }
  if (wake == true) {
    while (mySerial.available() <= 0) {
      mySerial.println('A');   // send a capital A
      Serial.print("A");
      delay(300);
      connectionCount ++;
      if (connectionCount > 30) {
        connectionCount = 0;
        wake = false;
        sleepDelay = 0;
        Sleeping();
        break;
      }
      else if (serialGo == 'B') {
        sendData = true;
        wake = false;
        connectionCount = 0;
        Serial.print("I have received a B");
        break;
      }
    }
  }

  if (sendData == true) {
    Serial.print("I made it to send data");
    delay(1000);
    Sleeping();
  }
}

void Sleeping() {

  // Disable the ADC (Analog to digital converter, pins A0 [14] to A5 [19])
  static byte prevADCSRA = ADCSRA;
  ADCSRA = 0;

  /* Set the type of sleep mode we want. Can be one of (in order of power saving):

     SLEEP_MODE_IDLE (Timer 0 will wake up every millisecond to keep millis running)
     SLEEP_MODE_ADC
     SLEEP_MODE_PWR_SAVE (TIMER 2 keeps running)
     SLEEP_MODE_EXT_STANDBY
     SLEEP_MODE_STANDBY (Oscillator keeps running, makes for faster wake-up)
     SLEEP_MODE_PWR_DOWN (Deep sleep)
  */
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  while (sleepCnt < 4) {
    // Turn of Brown Out Detection (low voltage). This is automatically re-enabled upon timer interrupt
    sleep_bod_disable();

    // Ensure we can wake up again by first disabling interrupts (temporarily) so
    // the wakeISR does not run before we are asleep and then prevent interrupts,
    // and then defining the ISR (Interrupt Service Routine) to run when poked awake by the timer
    noInterrupts();

    // clear various "reset" flags
    MCUSR = 0;  // allow changes, disable reset
    WDTCSR = bit (WDCE) | bit(WDE); // set interrupt mode and an interval
    WDTCSR = bit (WDIE) | bit(WDP3) | bit(WDP1) | bit(WDP0);    // set WDIE, and 1 second delay
    wdt_reset();

    // Send a message just to show we are about to sleep
    led();
    Serial.println("Good night!");
    Serial.flush();

    // Allow interrupts now
    interrupts();

    // And enter sleep mode as set above
    sleep_cpu();
  }

  // --------------------------------------------------------
  // �Controller is now asleep until woken up by an interrupt
  // --------------------------------------------------------

  // Prevent sleep mode, so we don't enter it again, except deliberately, by code
  sleep_disable();

  // Wakes up at this point when timer wakes up �C
  Serial.println("I'm awake!");

  // Reset sleep counter
  sleepCnt = 0;

  // Re-enable ADC if it was previously running
  ADCSRA = prevADCSRA;
}

// When WatchDog timer causes �C to wake it comes here
ISR (WDT_vect) {

  // Turn off watchdog, we don't want it to do anything (like resetting this sketch)
  wdt_disable();

  // Increment the WDT interrupt count
  sleepCnt++;

  // Now we continue running the main Loop() just after we went to sleep
}

Any ideas would be glad received,

cheers Jon

I'm just trying at the moment to understand your setup.
You have two nodes (A and B), each with a transceiver.
You send attempt data from node A to the to Node B (which may be sleeping).
Are you expecting the transceiver of node B to wake up the attached MCU when it sees data ?
or are you expecting that the received data will be in the serial buffer of node B's serial buffer when it wakes ?

Generally, unless you have a relatively precise synchronisation, having a receiving node in a sleeping state is difficult to manage.

@6v6gt my apologies it difficult to explane. say NodeA is sleeping when it wakes it sends an Capital A to NodeB that is not sleeping, Node B will then send back a capital B, Node A on recept will send the rest of the data it needs to send then go back to sleeep

there is wrong concept of receiving at node 2

  else if (sleepDelay > 2 && wake == false) {
    wake = true;
    sleepDelay = 0;                             // Reset the sleep delay to zero
=>  serialGo = mySerial.read(); //MISTAKE
  }

by calling serial.read() without detecting the input your serialGo variable will get random value.
you need to place a detector before serial.read() to make sure the RX not receive noise.

you did well on node1 program

 while (mySerial.available() > 0) //this line is the detector 
{
  rc = mySerial.read();
  Serial.print(rc);
}

@rzk thank you !

I will have a play about and see what I can get it to do, I believe I tried something similar but for some reason, after Node1 had first detected the B and sent the data.

I disconnected the transmitter from Node2 hoping that it would sit there sending A then go back to sleep, as it did not receive a B back, it did not it carried on as if it had received the B again I guess it was sat in the buffer or something?

rzk:
by calling serial.read() without detecting the input your serialGo variable will get random value.

No, you will either get the next character in the buffer, or -1 if there is nothing in the buffer.

This is not random.

I have added quite a bit to the program and it seems to work well.

#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "DHT.h"
#include <SoftwareSerial.h>
#include <arduinoFFT.h>;

//--------------- Declare Software serial pins -----------------------

SoftwareSerial mySerial(2, 3);            //RX, TX

//-------------- Declare the temp humid sensor -----------------------

#define DHTPIN 8                          // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11                     // DHT 11
DHT dht(DHTPIN, DHTTYPE);
float t;
float h;

//-------------- Declare the Battery voltage sensor ------------------

int batteryVoltageValue;
float Vout = 0.00;
float Vin = 0.00;
float R1 = 100000.00;                     // resistance of R1 (10K)
float R2 = 10000.00;                      // resistance of R2 (1K)

//-------------- Declare sound frequency varaiables -------------------

#define SAMPLES 128                       // samples-pt FFT Must be a base 2 number. Max 128 for Arduino Uno.
#define SAMPLING_FREQUENCY 1000           // ts = base on Nyquist, must be 2 times the highest expected frequency. 
arduinoFFT FFT = arduinoFFT();
unsigned int samplingPeriod;
unsigned long microSeconds;
double vReal[SAMPLES];                    // create vector of size of samles to hold real values
double vImag[SAMPLES];                    // create vector of size of samles to hold imaginary values
double frequency;

//-------------- Declare sleep wake varaibales ------------------------

volatile char sleepCnt = 2;               // makes the arduino sleep for ex amount of seconds 8 max.
volatile char sleepDelay = 0;             // makes the arduino sleep for ex amount of seconds 8 max.
bool wake = false;                        // Initialy set wake false

//---------------- Millis statment declarations ------------------------

unsigned long currentTime;
unsigned long previousTime = 0;

//--------------------- General variables ------------------------------

int connectionCount = 0;
char serialGo;                            // read the serial port if the correct caracter is recieved start sending data.
bool sendData = false;                    // Failsafe to stop data being sent at the wrong time.
const int statusLED = 7;                  // output pin declaration for each of the LEDs.
const int ledRed = 6;
const int ledBlue = 5;
const int powerPin = 10;                  // output pin declaration for the transistor that supplies power to the peripheral sensors.   

void setup() {
  dht.begin();                            // Start the Humidity and temp sensor.
  Serial.begin(9600);                     // Start the Serial ports at a baud rate of 9600.
  mySerial.begin(9600);
  pinMode(powerPin, OUTPUT);              // Set the power pin to an output.
  digitalWrite(powerPin, LOW);            // Set the pin Low.
  pinMode(statusLED, OUTPUT);             // Set the led pins to an outputs.
  pinMode(ledRed, OUTPUT);
  pinMode(ledBlue, OUTPUT);
  pinMode(batteryVoltageValue, INPUT);    // Set the Volate detection pin to an input.
  samplingPeriod = round(1000000 * (1.0 / SAMPLING_FREQUENCY)); // Period in microseconds
}

void loop() {
  serialGo = mySerial.read();
  currentTime = millis();

  if (sleepDelay <= 2 && wake == false) {       // Sleep delay is to extend the sleep period past the usual 8 seconds.
    sleepDelay++;
    Sleeping();
  }
  else if (sleepDelay > 2  && wake == false) {
    digitalWrite(powerPin, HIGH);
    wake = true;                                // make wake true
    sleepDelay = 0;                             // Reset the sleep delay to zero
    soundFreq();                                // Read the sound frequency
    battvoltage();                              // Read the Battery voltage
    h = dht.readHumidity();                     // Read Humidity
    t = dht.readTemperature();                  // Read temperature as Celsius
  }
  if (wake == true) {                           // on Wake Establish a connection by sending capital A when the recerver gets the A it sends B.
    while (mySerial.available() <= 0) {
        mySerial.print('A');                    // send a capital A
        Serial.print("A");
        digitalWrite(ledRed, HIGH);
        delay(300);
        connectionCount ++;
      if (connectionCount > 30) {
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        wake = false;
        sleepDelay = 0;
        digitalWrite(powerPin, LOW);
        Sleeping();
        break;
      }
      else if (serialGo == 'B') {
        sendData = true;
        wake = false;
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        Serial.print("I have received a B");
        break;
      }
    }
  }

  if (sendData == true) {
    while (mySerial.available() >= 1)
    {
      for (int i = 0; i < 2; i++) {
        digitalWrite(ledBlue, HIGH);
        Serial.println("Sending Data to reciever");
        mySerial.print('<');
        mySerial.print("Humidity:");
        mySerial.print(',');
        mySerial.print("Temperature:");
        mySerial.print(',');
        mySerial.print("Sound Frequency:");
        mySerial.print(',');
        mySerial.print("Battery Voltage:");
        mySerial.print(',');
        mySerial.print(h);
        mySerial.print(',');
        mySerial.print(t);
        mySerial.print(',');
        mySerial.print(frequency);
        mySerial.print(',');
        mySerial.print(Vin);
        mySerial.print('>');
        delay(1000);
      }
      sendData = false;
      digitalWrite(ledBlue, LOW);
      wake = false;
      digitalWrite(powerPin, LOW);
      break;
    }
    Sleeping();
  }
}

However, I would prefer to get rid of the delay in the while loop

 if (wake == true) {                           // on Wake Establish a connection by sending capital A when the recerver gets the A it sends B.
    while (mySerial.available() <= 0) {
        mySerial.print('A');                    // send a capital A
        Serial.print("A");
        digitalWrite(ledRed, HIGH);
        delay(300);
        connectionCount ++;
      if (connectionCount > 30) {
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        wake = false;
        sleepDelay = 0;
        digitalWrite(powerPin, LOW);
        Sleeping();
        break;
      }
      else if (serialGo == 'B') {
        sendData = true;
        wake = false;
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        Serial.print("I have received a B");
        break;
      }
    }
  }

In its current format, all seems to work well.
I then changed it to a millis() statement.

 if (wake == true) {                          // on Wake Establish a connection by sending capital A when the recerver gets the A it sends B.
    while (mySerial.available() <= 0) {
      currentTime = millis();
      if (currentTime - previousTime >= sendAdelay) {
        previousTime = currentTime;
        mySerial.print('A');   // send a capital A
        Serial.print("A");
        digitalWrite(ledRed, HIGH);
        connectionCount ++;
      }
      if (connectionCount > 30) {
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        wake = false;
        sleepDelay = 0;
        digitalWrite(powerPin, LOW);
        Sleeping();
        break;
      }
      else if (serialGo == 'B') {
        sendData = true;
        wake = false;
        connectionCount = 0;
        digitalWrite(ledRed, LOW);
        Serial.print("I have received a B");
        break;
      }
    }
  }

but after I tried this the sleep delays became random instead of sleeping and waking twice for 3 times it would randomly be sleep twice for 4 or even 5 times.

Sometimes after the first sleep cycle, the serialGo would receive the B, the serial.print would say Serial.print("I have received a B") but the digitalWrite(ledRed, LOW); would stay HIGH and all would go back to sleep even though the sendData variable had become true no data would be sent.

I also tried moving the serialGo = mySerial.read(); inside the detectors as had been mentioned before. while (mySerial.available() <= 0) and the while (mySerial.available() >= 1) however on doing this the program would freeze after sending ther first A.

Am I overthinking this and having a delay() isn't really that bad and am i missing something that is necessary with the serialGo = mySerial.read(); position?

again wrong concept of applying delay method.
you need to determine what your delay is?

  • stop executing program for a period of time
  • wait to execute program every period of time
led on
delay 1s  //stop program 1 second
led off
if (timenow - timepast >= 1s) //program wait this condition to be true then execute the program inside if
{
Led Change
}
do everything outside if when not true

you said your program already work well, you can stop overthink/overcode
now you need to
test in a long run, find bug, improve, and repeat.