Value in Serial arduino

But in practice, it does not work with esp8266. Please tell me what is the problem here

you are sending NL & CR

the code checks for NL (hence the line char endMarker = '\n'; )
If you send NL & CR there will be a CR in the next message so you don't geht "NO CARRIER" but something like "nlNO CARRIER". if this is in your "receivedChars" the strcmp will see a different string therefore the comparison isn't 0.

if you would send NL only it would work.

For your project it is important to know what your device you want to read is really sending at the end of NO CARRIER. a NL, a CR, both - may be nothing???
If you can provide precise brand/model/type and a datasheet of the protocol we might can help better.

No, I need a new line. Everything worked out. Thanks! So, I tested all the modes. And stayed on CR. I need a new line mode

Please tell me how to make it so that to activate "matched" I have to send "NO CARRIER
" twice

if (!strcmp(received Chars, "NO CARRIER")and(received Chars, "NO CARRIER"))

This is not true

introduce a (global) counter.
increase the counter if you have a match.
set the counter to 0 if you have a missmatch.
do something when the counter is 2.

This code does not work. I can't construct code from this. Or is it not so at all?

int counter;

if (counter == 2) { 
    if (!strcmp(receivedChars, "NO CARRIER") )
    Serial.println(F("matched")); // One single line added
  }

Please post full code.
Describe what the code should do
Describe what the code does.

"does not work" is not a sufficent bug report.

Here is the full code. When "NO CARRIER" appears twice in Serial, then the code should do something. For example, output to Serial "matched"

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
int counter;
void setup() {
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");
}

void loop() {
  recvWithEndMarker();
  showNewData();
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
   if (counter == 2) { 
    if (!strcmp(receivedChars, "NO CARRIER") )
    Serial.println(F("matched")); // One single line added
  }
}}

Serial

you have not implemented all steps I have described in #26.

Try this:

/*
   based on Example https://forum.arduino.cc/t/serial-input-basics-updated/382007

   https://forum.arduino.cc/t/value-in-serial-arduino/1039522/16
   will be deleted 2022-11
*/

// Example 2 - Receive with an end-marker

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
byte counter;
void setup() {
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");
}

void loop() {
  recvWithEndMarker();
  showNewData();
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;

    if (!strcmp(receivedChars, "NO CARRIER") )
    {
      Serial.println(F("matched"));
      counter++;
      if (counter >= 2)
      {
        Serial.println(F("and fire"));
      }
    }
    else
    {
      Serial.println(F("anything else - reset counter"));
      counter = 0;
    }
  }
}

"matched" will be printed when the given string was read.
"and fire" will be printed when at least two times the string was read successfully. if that should reset the counter ... reset the counter also here.

Thank you very much! I am grateful to you, sir)
I have the very last moment left in the code.
Initially, I wanted to do a project related to the sim800l board.
The idea of this. For example: when the MQ 2 sensor is triggered, the SIM800L dials the first number. Every time the phone does not pick up, the serial number displays the value "NO operator".
If the phone misses 2 calls, that is, 2 "NO OPERATOR", then sim800l calls the second number. With your help, I almost managed to implement it. But the problem is that when the sensor is triggered, it does not stop calling only the first number. Even if the value "WITHOUT MEDIA" is added. Please tell us how, in your opinion, this can be implemented?

This is the complete code

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
byte counter;
int mq2 =  A0;
int value;
#include <SoftwareSerial.h>
SoftwareSerial SIM800(0, 2);
void setup() {
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println("<Arduino is ready>");
  pinMode(mq2, INPUT);
}

void loop() {
  value = analogRead(mq2);
  if (value > 400)
  {
    SIM800.println("ATD+77754255040;"); //here to call the first number
    recvWithEndMarker();
    showNewData();
  }
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;

    if (!strcmp(receivedChars, "NO CARRIER") )
    {
      Serial.println(F("matched"));
      counter++;
      if (counter >= 2)
      {
        SIM800.println("ATD+77476138950;"); // here to call the second number
        Serial.println(F("and fire"));
        counter = 0;
      }
    }
    else
    {
      Serial.println(F("anything else - reset counter"));
      counter = 0;
    }
  }
}

for such complex activity flows I prefer to draw a state diagram. But I do not know if I have understood you correctly.
For example: what do you receive if a call was successful?
Or what should happen, when even the last call was not successful?
How long has the called number time to pick up the phone?

if you just return to check the sensor, but the sensor is still > 400 the calls will start immediately again.
Imho there needs something like a "cool down periode" or something similar...

why have you checked all the time for "NO CARRIER" when you now need a "NO OPERATOR"?

Come up with proposals.

Diagram of the whole code

so only NO CARRIER should bring you to the next Step of calling the next number?
even BUSY and ERROR will loop endless to call the same number over and over again?

1 Like

If the value "BUSY" and "ERROR" will be repeated indefinitely, that is, up to mq2 normal state.
If there is "NO CARRIER" then lead to the next step.

after a "BUSY" or a "ERROR" you don't check the MQ2 value. So it is an endless loop.
Doesn't look good for me.

1 Like

Yes, this is an infinite loop, I wanted to say that if the value in mq2 drops, then it should not ring. We can do this using else{}

I would use a finite state machine (FSM) to jump through different states.
Your diagram still doesn't make sense for me, may be it is my bad English.
However, this is what I would do based on my diagram:

There are 5 states of the state machine.
The sensor is getting read in state CHECK
if the criterion is met, the first contact (index 0) will be called. Now we have to jump to the next state "CALLED1" (we have done the first call)
on success (meaning we receive a "NO CARRIER") we jump back to CHECK.
on error (received anything else) we try the contact again (still index 0); but now we jump forward to CALLED2 (we have done the second call)
two times contact 0, two times contact 1.
If the final contact fails we jump back to CHECK
if the final contact fails we jump back to CHECK

I know there is some copy/pasted code, but I hope this visualizes what the state machine is considered to do.

P.S.: I simulate the SIM800 to HW-Serial.

/*
   based on Example https://forum.arduino.cc/t/serial-input-basics-updated/382007

   https://forum.arduino.cc/t/value-in-serial-arduino/1039522/16
   will be deleted 2022-11
*/

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;

constexpr byte mq2Pin {A0};     // GPIO for MQ2 Sensor
constexpr byte testPin {A3};    // GPIO with a button to GND to do testing

enum class State {CHECK, CALLED1, CALLED2, CALLED3, CALLED4} state;  // states for the finite state machine
enum Response {SUCCESS, UNKNOWN, NOTHING};  // Response codes from the serial parser

//#include <SoftwareSerial.h>
//SoftwareSerial SIM800(0, 2);

//simulate local:
HardwareSerial &SIM800 = Serial; // handles SIM800 as Reference to Serial for local tests

const char contact[][12]
{
  "77754255040",
  "77476138950"
};

void callNumber(byte index)
{
  Serial.print(F("call ")); Serial.println(contact[index]);
  SIM800.print("ATD+");
  SIM800.print(contact[index]);
  SIM800.println(";");
}

void setup() {
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println(F("\n<Arduino is ready>"));
  pinMode(mq2Pin, INPUT);
  pinMode(testPin, INPUT_PULLUP);
}

void loop() {
  recvWithEndMarker();
  int result = -1;
  int sensorValue = 0;
  int testValue = HIGH;
  switch (state)
  {
    case State::CHECK :
      result = showNewData(); // this will show and delete incoming characters
      sensorValue = analogRead(mq2Pin);
      testValue = digitalRead(testPin);
      if (sensorValue > 400 || testValue == LOW)
      {
        Serial.println(F("Sensor fired"));
        callNumber(0);
        state = State::CALLED1;
        Serial.println(F("jump to CALLED1"));
      }
      break;
    case State::CALLED1 :
      result = showNewData();
      if (result == Response::SUCCESS)
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(0);
        state = State::CALLED2;
        Serial.println(F("jump to CALLED2"));
      }
      break;
    case State::CALLED2 :
      result = showNewData();
      if (result == Response::SUCCESS) 
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(0);
        state = State::CALLED3;
        Serial.println(F("jump to CALLED3"));
      }
      break;
    case State::CALLED3 :
      result = showNewData();
      if (result == Response::SUCCESS) 
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(1);
        state = State::CALLED4;
        Serial.println(F("jump to CALLED4"));
      }
      break;
    case State::CALLED4 :
      result = showNewData();
      if (result == Response::SUCCESS)
      { 
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(1);
        state = State::CHECK; // tried all contacts two times, back to check the sensor
        Serial.println(F("jump back to CHECK"));
      }
      break;
  }
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

int showNewData() {
  if (newData == true) {
    Serial.print(F("<in>"));
    Serial.println(receivedChars);
    newData = false;
    if (!strcmp(receivedChars, "NO CARRIER"))
    {
      return Response::SUCCESS;  // sucessful
    }
    return Response::UNKNOWN;
  }
  return Response::NOTHING;
}

this concept allows lot of extensions. Timeouts, new states, different handling based on the SIM response and much more.

I would suggest you bring your diagram to a valid state - I still don't believe that yours is correct.

Thank you very much for your work. I'm grateful.
It seems I couldn't get my point across correctly. The code is slightly wrong.
When the mq2 is triggered, the SIM800L should ring the first definition number. If everything is normal, sim800h can return to Serial "ok". If "ERROR" sim800l should ring again. If the call went through and the person rejected the call, then the sim800h should ring endlessly. And if you missed the call twice, the Sim800l should go to the second number. And so on endlessly.

I hope the diagram is clearer now

I edited a little for my project.
But there is one problem.
After receiving a response from Sim800l, the code does not respond to this.
That is, if sim800h sends a response "NO CARRIER", the code does nothing. If you manually write "NO CARRIER" in Serial, the code will work. Please tell me what this is related to)

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;

constexpr byte mq2Pin {A0};     // GPIO for MQ2 Sensor

enum class State {CHECK, CALLED1, CALLED2, CALLED3, CALLED4} state;  // states for the finite state machine
enum Response {SUCCESS, UNKNOWN, NOTHING};  // Response codes from the serial parser

#include <SoftwareSerial.h>
SoftwareSerial SIM800(0, 2);

const char contact[][12]
{
  "77754255040",
  "77476138950"
};

void callNumber(byte index)
{
  Serial.print(F("call ")); Serial.println(contact[index]);
  SIM800.print("ATD+");
  SIM800.print(contact[index]);
  SIM800.println(";");
}

void setup() {
  Serial.begin(9600);
  SIM800.begin(9600);
  Serial.println(F("\n<Arduino is ready>"));
  pinMode(mq2Pin, INPUT);
}

void loop() {

  recvWithEndMarker();
  int result = -1;
  int sensorValue = 0;
  switch (state)
  {
    case State::CHECK :
      result = showNewData(); // this will show and delete incoming characters
      sensorValue = analogRead(mq2Pin);
      if (sensorValue > 400)
      {
        Serial.println(F("Sensor fired"));
        callNumber(0);
        state = State::CALLED1;
        Serial.println(F("jump to CALLED1"));
      }
      break;
    case State::CALLED1 :
      result = showNewData();
      if (result == Response::SUCCESS)
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(0);
        state = State::CALLED2;
        Serial.println(F("jump to CALLED2"));
      }
      break;
    case State::CALLED2 :
      result = showNewData();
      if (result == Response::SUCCESS)
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(0);
        state = State::CALLED3;
        Serial.println(F("jump to CALLED3"));
      }
      break;
    case State::CALLED3 :
      result = showNewData();
      if (result == Response::SUCCESS)
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(1);
        state = State::CALLED4;
        Serial.println(F("jump to CALLED4"));
      }
      break;
    case State::CALLED4 :
      result = showNewData();
      if (result == Response::SUCCESS)
      {
        Serial.println(F("call was SUCCESS"));
        state = State::CHECK;
        Serial.println(F("jump to CHECK"));
      }
      else if (result == Response::UNKNOWN)
      {
        callNumber(1);
        state = State::CHECK; // tried all contacts two times, back to check the sensor
        Serial.println(F("jump back to CHECK"));
      }
      break;
  }
  if (SIM800.available())           // Ожидаем прихода данных (ответа) от модема...
    Serial.write(SIM800.read());    // ...и выводим их в Serial

}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

int showNewData() {
  if (newData == true) {
    Serial.print(F("<in>"));
    Serial.println(receivedChars);
    newData = false;

    if (!strcmp(receivedChars, "BUSY"))
    {
      return Response::SUCCESS;  // sucessful
    }

    if (!strcmp(receivedChars, "NO CARRIER"))
    {
      return Response::UNKNOWN;  // sucessful
    }


    if (!strcmp(receivedChars, "ERROR"))
    {
      return Response::SUCCESS;  // sucessful
    }

    if (!strcmp(receivedChars, "OK"))
    {
      return Response::NOTHING;  // sucessful
    }


    return Response::NOTHING;
  }
  return Response::NOTHING;
}

Try printing the length of receivedChars before comparing it with "NO CARRIER"