Multiple serial ports!How to use Sensor_Serial.listen() and fonaSerial->listen()

Hi there!
Note: My question has been edited according to the changes in my program till now(reply#13).
I'm using Arduino UNO, Tiny Sine 3G GSM shield and a sensor (output values 0-1000)

I have written my code to read the sensor values from pin 12. But the code fails to enter the void loop () therefore failing to print the sensor value & send SMS to mobile. Can anyone explain to why I'm not able to see the values in Serial Monitor or get an SMS?

OUTPUT: FONA OK & prints IMEI number and nothing after that...

Thank you.

test.ino (4.45 KB)

Hi,

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks. Tom.. :slight_smile:

// the setup routine runs once when you press reset:
#include "Adafruit_FONA.h"
#include <SoftwareSerial.h>

#define FONA_TX 2
#define FONA_RX 3
#define FONA_RST 4

// this is a large buffer for replies
char replybuffer[255];
char buffer[24];
char r[10];


SoftwareSerial C_Serial(12,13);  //Sets up a virtual serial port
                                    //Using pin 12 for Rx //and pin 13 for Tx

SoftwareSerial fonaSS = SoftwareSerial(FONA_TX,FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

// Hardware serial is also possible!
//  HardwareSerial *fonaSerial = &Serial1;

// Use this for FONA 800 and 808s
//Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Use this one for FONA 3G
Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);

uint8_t type;
byte readC[] = {0xFF, 0X01, 0X86, 0X00, 0X00, 0X00, 0X00, 0X00,0X79};  //Command packet to read C (see app note)
byte response[] = {0,0,0,0,0,0,0,0,0};  //create an array to store the response

//multiplier for value. default is 1. set to 25 for O2 25% 
int valMultiplier = 1;

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(9600);         //Opens the main serial port to communicate with the computer
  C_Serial.begin(9600);    //Opens the virtual serial port with a baud of 9600
  Serial.println(F("FONA basic test"));
  Serial.println(F("Initializing....(May take 3 seconds)"));
  fonaSerial->begin(4800);
  if (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    while (1);
}

type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  switch (type) {
    case FONA800L:
      Serial.println(F("FONA 800L")); break;
    case FONA800H:
      Serial.println(F("FONA 800H")); break;
    case FONA808_V1:
      Serial.println(F("FONA 808 (v1)")); break;
    case FONA808_V2:
      Serial.println(F("FONA 808 (v2)")); break;
    case FONA3G_A:
      Serial.println(F("FONA 3G (American)")); break;
    case FONA3G_E:
      Serial.println(F("FONA 3G (European)")); break;
    default: 
      Serial.println(F("???")); break;
  }
  
  // Print module IMEI number.
  char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
  uint8_t imeiLen = fona.getIMEI(imei);
  if (imeiLen > 0) {
    Serial.print("Module IMEI: "); Serial.println(imei);
  }

  // Optionally configure a GPRS APN, username, and password.
  // You might need to do this to access your network's GPRS/data
  // network.  Contact your provider for the exact APN, username,
  // and password values.  Username and password are optional and
  // can be removed, but APN is required.
  fona.setGPRSNetworkSettings(F("yesinternet"), F("your username"), F("your password"));

  // Optionally configure HTTP gets to follow redirects over SSL.
  // Default is not to follow SSL redirects, however if you uncomment
  // the following line then redirects over SSL will be followed.
  //fona.setHTTPSRedirect(true);
}

void loop() 
{
  sendRequest(readC);
  float valC = getValue(response);
    Serial.print("C = ");
    Serial.println(valC);
  static unsigned long startTime = 0;
    if (valC < 500)
        startTime = millis();
        dtostrf(valC, 3, 2, r);
      sprintf(buffer, "%s High Level", r);
    if (millis() - startTime > 1UL*60UL*1000UL) {  // Has it been 15 minutes since the value was below 500?
        //sendAlert();
        fona.sendSMS("0xxxxxxx", buffer); //mobile number
  }
  
  //delay(1000);
}

void sendRequest(byte packet[])
{
  while(!C_Serial.available())  //keep sending request until we start to get a response
  {
    C_Serial.write(readC,9);
    delay(50);
  }
  
  int timeout=0;  //set a timeoute counter
  while(C_Serial.available() < 9 ) //Wait to get a 9 byte response
  {
    timeout++;  
    if(timeout > 10)    //if it takes to long there was probably an error
      {
        while(C_Serial.available())  //flush whatever we have
          C_Serial.read();
          
          break;                        //exit and try again
      }
      delay(50);
  }
  
  for (int i=0; i < 9; i++)
  {
    response[i] = C_Serial.read();
  }  
}

unsigned long getValue(byte packet[])
{
    int high = packet[2];                        //high byte for value is 3rd byte in packet in the packet
    int low = packet[3];                         //low byte for value is 4th byte in the packet
   
  
    unsigned long val = high*256 + low;                //Combine high byte and low byte with this formula to get value
    return val* valMultiplier;
}

Rishi_me:
OUTPUT: FONA OK & prints IMEI number and nothing after that...

How does it get to the IMEI number without displaying "Found " and the FONA type?!?

 type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  switch (type) {
    case FONA800L:
      Serial.println(F("FONA 800L")); break;
    case FONA800H:
      Serial.println(F("FONA 800H")); break;
    case FONA808_V1:
      Serial.println(F("FONA 808 (v1)")); break;
    case FONA808_V2:
      Serial.println(F("FONA 808 (v2)")); break;
    case FONA3G_A:
      Serial.println(F("FONA 3G (American)")); break;
    case FONA3G_E:
      Serial.println(F("FONA 3G (European)")); break;
    default: 
      Serial.println(F("???")); break;
  }
  
  // Print module IMEI number.

This bit of code could easily hang your program before any output happens:

  while(!C_Serial.available())  //keep sending request until we start to get a response
  {
    C_Serial.write(readC,9);
    delay(50);
  }

Add more Serial output to find out if you enter that loop and never get out.

Scratching me head over this one:

char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!

Did you forget to read your own comment? If the IMEI is indeed 16 bytes, it will clobber the stack, and when setup() returns, the program will wander off to la-la land.

Regards,
Ray L.

@johnwasser ... I meant to say the program is perfectly running until void loop, sorry about that I should have mentioned that before.

And YES you were right, after commenting this part of the code:

{
//  while(!C_Serial.available())  //keep sending request until we start to get a response
//  {
//    C_Serial.write(readC,9);
//    delay(50);
//  }

OUTPUT:FONA basic test
Initializing....(May take 3 seconds)
Attempting to open comm with ATs
---> AT
<--- OK
---> ATE0
<--- OK
---> ATE0
<--- OK
---> AT+CVHU=0
<--- OK
---> ATI
<--- Manufacturer: SIMCOM INCORPORATED
Model: SIMCOM_SIM5320E
Revision: SIM5320E_V1.5
IMEI: 861311008040262
+GCAP: +CGSM,+DS,+ES

OK

---> AT+CPMS="ME"
<--- +CPMS: 19,255,19,255,19,255
FONA is OK
Found FONA 3G (European)
---> AT+GSN
<--- 861311008040262
Module IMEI: 86XXXXXXXXXX
C = 4294967295
---> AT+CMGF=1
<--- OK
---> AT+CMGS="0xxxxxxx"
<--- >

4294967300.00 High Level
^Z

  1. Can you please help me with the output, I'm not able to read the sensor connected to pin 12 ? I mean my valC variable is not reading the sensor value which is "0" .. Can you please look into this?
  2. with regards to this part of the code: Sorry I used your part of the code here for checking sensor value for 1 minute and then sending the SMS
 if (valC < 500)
        startTime = millis();
        dtostrf(valC, 3, 2, r);
      sprintf(buffer, "%s High Level", r);
    if (millis() - startTime > 15UL*60UL*1000UL) {  // Has it been 15 minutes since the value was below 500?
        //sendAlert();
        fona.sendSMS("0XXXXXXX", buffer); //mobile number
  }

but I'm getting SMS's every 1 sec ?

Rishi_me:

Module IMEI: 861311008040262

C = 4294967295

4294967300.00 High Level



1. Can you please help me with the output, as the expected output is '0' and the above output is showing " 4294967300.00 High Level"

I can't see enough of your code to figure out where that number is coming from. Please post the whole sketch again, after using auto-format to clean up the indentations.

Rishi_me:
2. with regards to this part of the code:

 if (valC < 500)

startTime = millis();
       dtostrf(valC, 3, 2, r);
     sprintf(buffer, "%s High Level", r);
   if (millis() - startTime > 15UL60UL1000UL) {  // Has it been 15 minutes since the value was below 500?
       //sendAlert();
       fona.sendSMS("0424737176", buffer); //mobile number
 }



but I'm getting SMS's every 1 sec ?

You forgot to put a "startTime = millis();" inside the "if (fifteen minutes has passed) {" so it waits at least another 15 minutes before sending another message.

Thank for helping me out @johnwasser

// the setup routine runs once when you press reset:
#include "Adafruit_FONA.h"

#define FONA_TX 2
#define FONA_RX 3
#define FONA_RST 4

// this is a large buffer for replies
char replybuffer[255];
char buffer[24];
char r[10];
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines 
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX,FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
SoftwareSerial Sensor_Serial(12,13);
 
// Hardware serial is also possible!
//  HardwareSerial *fonaSerial = &Serial1;

// Use this for FONA 800 and 808s
//Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Use this one for FONA 3G
Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);

uint8_t type;

byte readCO[] = {0xFF, 0X01, 0X86, 0X00, 0X00, 0X00, 0X00, 0X00,0X79};  //Command packet to read CO (see app note)

byte response[] = {0,0,0,0,0,0,0,0,0};  //create an array to store the response

//multiplier for value. default is 1. set to 25 for O2 25% 
int valMultiplier = 1;

void setup() {
  while (!Serial);

  Serial.begin(9600);
  Sensor_Serial.begin(9600);    //Opens the virtual serial port with a baud of 9600
  Serial.println(F("FONA basic test"));
  Serial.println(F("Initializing....(May take 3 seconds)"));
 
  fonaSerial->begin(4800);
  if (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    while (1);
  }
  type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  switch (type) {
    case FONA800L:
      Serial.println(F("FONA 800L")); break;
    case FONA800H:
      Serial.println(F("FONA 800H")); break;
    case FONA808_V1:
      Serial.println(F("FONA 808 (v1)")); break;
    case FONA808_V2:
      Serial.println(F("FONA 808 (v2)")); break;
    case FONA3G_A:
      Serial.println(F("FONA 3G (American)")); break;
    case FONA3G_E:
      Serial.println(F("FONA 3G (European)")); break;
    default: 
      Serial.println(F("???")); break;
  }
  
  // Print module IMEI number.
//  char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
//  uint8_t imeiLen = fona.getIMEI(imei);
//  if (imeiLen > 0) {
//    Serial.print("Module IMEI: "); Serial.println(imei);
//  }

  // Optionally configure a GPRS APN, username, and password.
  // You might need to do this to access your network's GPRS/data
  // network.  Contact your provider for the exact APN, username,
  // and password values.  Username and password are optional and
  // can be removed, but APN is required.
              //fona.setGPRSNetworkSettings(F("yesinternet"), F("your username"), F("your password"));

  // Optionally configure HTTP gets to follow redirects over SSL.
  // Default is not to follow SSL redirects, however if you uncomment
  // the following line then redirects over SSL will be followed.
  //fona.setHTTPSRedirect(true);
}
void loop() 
{
  sendRequest(readCO);
  unsigned long valCO = getValue(response);
  static unsigned long startTime = 0;
  if (digitalRead(valCO) < 500)
    dtostrf(valCO, 3, 2, r);
    sprintf(buffer, "%s High Level", r);
  Serial.print("CO = ");
  Serial.println(valCO);
  //delay(1000);
  if (millis() - startTime > 15UL*60UL*1000UL) {  // Has it been 15 minutes since the value was below 500?
    //sendAlert();
      startTime = millis();
      fona.sendSMS("0XXXXXX", buffer);
}
  }

void sendRequest(byte packet[])
{
//  while(!Sensor_Serial.available())  //keep sending request until we start to get a response
//  {
//    Sensor_Serial.write(readCO,9);
//    delay(50);
//  }
  
  int timeout=0;  //set a timeoute counter
  while(Sensor_Serial.available() < 9 ) //Wait to get a 9 byte response
  {
    timeout++;  
    if(timeout > 10)    //if it takes to long there was probably an error
      {
        while(Sensor_Serial.available())  //flush whatever we have
          Sensor_Serial.read();
          
          break;                        //exit and try again
      }
      delay(50);
  }
  
  for (int i=0; i < 9; i++)
  {
    response[i] = Sensor_Serial.read();
  }  
}

unsigned long getValue(byte packet[])
{
    int high = packet[2];                        //high byte for value is 3rd byte in packet in the packet
    int low = packet[3];                         //low byte for value is 4th byte in the packet
   
  
    unsigned long val = high*256 + low;                //Combine high byte and low byte with this formula to get value
    return val* valMultiplier;
}
  if (digitalRead(valCO) < 500)

?!? The result of a digitalRead() will always be 0 (LOW) or 1 (HIGH). This is an obvious mistake.

It looks like your "response" packet contains 0xFF and 0xFF in 2 and 3 and that gets turned into 0xFFFFFFFF when returned as an unsigned long. I don't know why dtostrf() is putting 14 bytes into your buffer instead of 4 but your 'r' buffer is only 10 bytes long and that will cause errors. Why are you trying to display an unsigned long value as a three-character float?!?

Please read the comments after void loop for better understanding of my problem

// the setup routine runs once when you press reset:
#include "Adafruit_FONA.h"

#define FONA_TX 2
#define FONA_RX 3
#define FONA_RST 4

// this is a large buffer for replies
//char replybuffer[255];
char buffer[50];
char r[6];
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines 
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX,FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
SoftwareSerial Sensor_Serial(12,13);
 
// Hardware serial is also possible!
//  HardwareSerial *fonaSerial = &Serial1;

// Use this for FONA 800 and 808s
//Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Use this one for FONA 3G
Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);

uint8_t type;

byte readCO[] = {0xFF, 0X01, 0X86, 0X00, 0X00, 0X00, 0X00, 0X00,0X79};  //Command packet to read CO (see app note)

byte response[] = {0,0,0,0,0,0,0,0,0};  //create an array to store the response

//multiplier for value. default is 1. 
int valMultiplier = 1;

void setup() {
  while (!Serial);

  Serial.begin(9600);
  Sensor_Serial.begin(9600);    //Opens the virtual serial port with a baud of 9600
  Serial.println(F("FONA basic test"));
  Serial.println(F("Initializing....(May take 3 seconds)"));
 
  fonaSerial->begin(4800);
  if (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    while (1);
  }
  type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  switch (type) {
    case FONA800L:
      Serial.println(F("FONA 800L")); break;
    case FONA800H:
      Serial.println(F("FONA 800H")); break;
    case FONA808_V1:
      Serial.println(F("FONA 808 (v1)")); break;
    case FONA808_V2:
      Serial.println(F("FONA 808 (v2)")); break;
    case FONA3G_A:
      Serial.println(F("FONA 3G (American)")); break;
    case FONA3G_E:
      Serial.println(F("FONA 3G (European)")); break;
    default: 
      Serial.println(F("???")); break;
  }
  
  
}
void loop() 
{
    sendRequest(readCO);
    unsigned long valCO = getValue(response);
    static unsigned long startTime = 0;
    if (valCO < 500)
    
   dtostrf(valCO, 3, 2, r); // I don't know how to covert the unsigned long variable to string and I know //this part does the float to string conversion
    sprintf(buffer, "%s High  Level", r);// this part helps SEND SMS
    Serial.print("CO  = ");
    Serial.println(valCO);
    if (millis() - startTime > 1UL*60UL*1000UL) {  // Has it been 1 minute since the value was below 500?
    //sendAlert();
      startTime = millis();
      fona.sendSMS("0XXXXXXX", buffer);
     }
  }

void sendRequest(byte packet[])
{
  while(!Sensor_Serial.available())  // If this part works the entire code works I think!!
//keep sending request until we start to get a response
  {
    //Sensor_Serial.write(readCO,9);
    delay(50);
  }
  
  int timeout=0;  //set a timeoute counter
  while(Sensor_Serial.available() < 9 ) //Wait to get a 9 byte response
  {
    timeout++;  
    if(timeout > 10)    //if it takes to long there was probably an error
      {
        while(Sensor_Serial.available())  //flush whatever we have
          Sensor_Serial.read();
          
          break;                        //exit and try again
      }
      delay(50);
  }
  
  for (int i=0; i < 9; i++)
  {
    response[i] = Sensor_Serial.read();
  }  
}

unsigned long getValue(byte packet[])
{
    int high = packet[2];                        //high byte for value is 3rd byte in packet in the packet
    int low = packet[3];                         //low byte for value is 4th byte in the packet
   
  
    unsigned long val = high*256 + low;                //Combine high byte and low byte with this formula to get value
    return val* valMultiplier;
}

Stop calling it void loop. It's just called loop().

@johnwasser:

  1. I forgot to edit that part of the code where I used digitalRead(valCO) but please ignore "digitalRead" its just valCO<500.

johnwasser:
Why are you trying to display an unsigned long value as a three-character float?!?

dtostrf(valCO, 3, 2, r); // I don't know how to covert the unsigned long variable to string and I know //this part does the float to string conversion
sprintf(buffer, "%s High  Level", r);

I have used this part of the code for another program where my valCO was a float variable but here I'm using unsigned long variable for valCO. If I use float for valCO then OUTPUT: CO= ovf
My expected output range is 0-1000, so I think even if I use unsigned long it shouldn't be a problem but the program is somehow refusing to enter

void sendRequest(byte packet[])
{
  while(!Sensor_Serial.available())  // If this part works the entire code works I think!!
//keep sending request until we start to get a response
  {
    Sensor_Serial.write(readCO,9);
    delay(50);
  }

Any fix for this as I think this part hold the key to my output..

    unsigned long valCO = getValue(response);
    static unsigned long startTime = 0;
    if (valCO < 500)
   
   dtostrf(valCO, 3, 2, r); // I don't know how to covert the unsigned long variable to string

Then you need to do some research or ask. Pretending that the long is an int, and adding two decimal places is stupid.

sprintf() is the sledgehammer to deal with this nail. ultoa() is the ball peen hammer.

I appreciate your time for posting comment @PaulS but I think the main problem is with the software serial ports. If I comment:

void sendRequest(byte packet[])
{
  //while(!Sensor_Serial.available())  // If this part works the entire code works I think!!
//keep sending request until we start to get a response
 // {
  //  Sensor_Serial.write(readCO,9);
  //  delay(50);
  }

this part of the code its at least returning some error value for valCO. Well I can use float for my valCO:

float valCO = getValue(response);
 static unsigned long startTime = 0;
 if (valCO < 500)
 dtostrf(valCO, 3, 2, r); // I don't know how to covert the unsigned long variable to string
 sprintf(buffer, "%s High Level", r);

and as expected the code worked until printing the IMEI number ... How to better deal with software serial ports as at the moment I am trying to access both the software serial ports at the same time which I shouldn't be doing. I need my sensor and GSM to work simultaneously.

How do I use Sensor_Serial.listen() and fonaSerial->listen() as I need both the serial ports to work hand in hand? Thank you.

How do I use Sensor_Serial.listen() and fonaSerial->listen() as I need both the serial ports to work hand in hand?

I'm not sure what you mean by "hand in hand", but, if you are asking how to use listen() to listen to two different software serial ports at the same time, the answer is quite simple.

You can't.

How do I use Sensor_Serial.listen() and fonaSerial->listen() as I need both the serial ports to work hand in hand?

You can't. Which part of this is unclear:

If using multiple software serial ports, only one can receive data at a time.

From the Official Description.

It would be most reliable if you could put one of those devices on the Serial pins. It looks like the sensor has a formatted read command, so it would ignore all the debug prints. You would have to temporarily disconnect the sensor TX pin from the Arduino RX pin 0 to upload new sketches over USB. Then connect the FONA to pins 8 & 9 and use AltSoftSerial instead of SoftwareSerial:

#define sensorPort Serial
AltSoftSerial fonaPort; // always 8 & 9 on an UNO

   ...

void sendRequest(byte packet[])
{
  while(!sensorPort.available())  //keep sending request until we start to get a response
  {
    sensorPort.write(readC,9);

No data would be lost from the FONA while sending to or receiving from the sensor.

The next most reliable approach would be to use AltSoftSerial for the FONA and NeoSWSerial for the sensor:

NeoSWSerial sensorPort( 12, 13 );
AltSoftSerial fonaPort; // always 8 & 9 on an UNO

You could lose some data from the FONA while sending the read command to the sensor. No data from the FONA would be lost while receiving from the sensor.

There is no other combination of libraries that allows receiving from both devices at the same time, without losing data from one or the other device.

Both libraries are available from the Arduino IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries.

Thanks @dev I tried the program using Serial1 for my sensor and its working perfectly!. I will take your suggestions in using AltSoftSerial and NeoSWSerial instead of serial for my program and will update the results of it.