c++arduinoat-commandarduino-c++sim800

Arduino UNO + SIM800L - sending data to server


I am using arduino UNO board, with modem sim800l. I want use it to send data to server mysql every 10 seconds. Everything is working fine when I have serial monitor open in arduino IDE (data is being saved to the mysql database)but when serial monitor is off then does not work.

I want use my system remote, connected to the powerbank. But it works only when I have opened arduino IDE serial monitor.

How to edit the code so that the microcontroller works without connecting to a computer and an open serial monitor?

#include <SoftwareSerial.h>
SoftwareSerial gprsSerial(7, 8);

void setup()
{
  gprsSerial.begin(19200);
  Serial.begin(19200);

  Serial.println("Config SIM900...");
  delay(2000);
  Serial.println("Done!...");
  gprsSerial.flush();
  Serial.flush();

  // attach or detach from GPRS service 
  gprsSerial.println("AT+CGATT?");
  delay(100);
  toSerial();


  // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"APN\",\"internet\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=1,1");
  delay(2000);
  toSerial();
}


void loop()
{
   // initialize http service
   gprsSerial.println("AT+HTTPINIT");
   delay(2000); 
   toSerial();

   // set http param value
   gprsSerial.println("AT+HTTPPARA=\"URL\",\"http://server.net/test.php?data1=2&data2=3\""); 
   delay(2000);
   toSerial();

   // set http action type 0 = GET, 1 = POST, 2 = HEAD
   gprsSerial.println("AT+HTTPACTION=0");
   delay(6000);
   toSerial();

   // read server response
   gprsSerial.println("AT+HTTPREAD"); 
   delay(1000);
   toSerial();

   gprsSerial.println("");
   gprsSerial.println("AT+HTTPTERM");
   toSerial();
   delay(300);

   gprsSerial.println("");
   delay(10000);
}

void toSerial()
{
  while(gprsSerial.available()!=0)
  {
    Serial.write(gprsSerial.read());
  }
}

Solution

  • I'm not sure about the underlying implementation of Serial however there may be some kind of an infinite wait for the Serial.println() that is happening.

    And reading the documentation on Serial.flush() it appears that it may also be the cause of an infinite wait for the serial output to finish before it returns.

    Since Serial.println() seems to use the Serial.write() functionality to do its thing I would suppose that if you have no device reading from the serial port at some point the write buffer is getting full and causing the Serial.println() to block. See https://www.arduino.cc/reference/en/language/functions/communication/serial/write/

    Notes and Warnings

    As of Arduino IDE 1.0, serial transmission is asynchronous. If there is enough empty space in the transmit buffer, Serial.write() will return before any characters are transmitted over serial. If the transmit buffer is full then Serial.write() will block until there is enough space in the buffer. To avoid blocking calls to Serial.write(), you can first check the amount of free space in the transmit buffer using availableForWrite().

    See this explanation of the Serial.flush() function https://www.arduino.cc/reference/en/language/functions/communication/serial/flush/ which notes:

    Serial.flush()

    Description

    Waits for the transmission of outgoing serial data to complete. (Prior to Arduino 1.0, this instead removed any buffered incoming serial data.)

    flush() inherits from the Stream utility class.

    And see this article, https://www.baldengineer.com/when-do-you-use-the-arduinos-to-use-serial-flush.html which says"

    What does Serial.flush() do?

    From the Arduino reference for Serial.flush (found on this page):

    Waits for the transmission of outgoing serial data to complete.

    The key to that statement is “outgoing”. Serial.flush() doesn’t empty the “incoming” buffer as many people think. It pauses your program while the transmit buffer is flushed.

    I would use the Serial.availableForWrite() function before doing any output using Serial.println() and if the number of bytes available indicates that the write buffer is getting full then skip the output.

    Probably the best approach would be as part of the Setup() function to check the write buffer size after doing the Serial.begin() and store that in a global variable which you then use to check to see if the write buffer is getting emptied or not.

    See https://www.instructables.com/id/Arduino-Serial/ which has this to say:

    Step 3: Command : ​ AvailableForWrite()

    Description

    Get the number of bytes (characters) available for writing in the serial buffer without blocking the write operation.

    Syntax

    Serial.availableForWrite()

    See also https://www.arduino.cc/reference/en/language/functions/communication/serial/availableforwrite/

    There is also if (Serial) which can be used to check if the port is available. https://www.arduino.cc/reference/en/language/functions/communication/serial/ifserial/ however I suspect that it is more of a check that the requested port is available rather than whether the port is actually functioning with a device on the other end of the link.

    And there is also the Serial.available() https://www.arduino.cc/reference/en/language/functions/communication/serial/available/

    Serial.available()

    Description

    Get the number of bytes (characters) available for reading from the serial port. This is data that’s already arrived and stored in the serial receive buffer (which holds 64 bytes).

    Serial.available() inherits from the Stream utility class.

    Syntax

    Serial.available()

    Parameters

    Serial: serial port object. See the list of available serial ports for each board on the Serial main page.

    Returns

    The number of bytes available to read.

    Suggested course of action

    First of all, I don't see that the Serial.flush() in the Setup() function is necessary and it could be safely removed. While this makes the console output immediate during the Setup() it does introduce a wait for the remote case in which there is no device reading from the serial line to empty the output buffer.

    I also suggest that for each line you do Serial.println() you do a check on the number of bytes of buffer available with Serial.availableForWrite() first as in:

    int firstAvailableForWrite = 0;
    
    void Setup ()
    {
        // set up everything you do then add the following statement
        firstAvailableForWrite = Serial.availableForWrite();
    }
    

    Then where ever you are going to do a write modify that with an if statement similar to the following example:

    if (Serial.availableForWrite() >= firstAvailableForWrite) Serial.println("Config SIM900...");
    

    Or you could also create a function something like the following:

    int serialPrintLineIfAvailable (char *aszLine)
    {
        int iCount = 0;
        if (Serial.availableForWrite() >= firstAvailableForWrite) iCount = Serial.println(aszLine);
    
        return iCount;
    }
    

    Then wherever you want to use Serial.println() you would instead use serialPrintLineIfAvailable() as in serialPrintLineIfAvailable("Config SIM900...");