3
votes

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());
  }
}
1
You already have this question open. Edit it instead of asking a new one. (or at least delete that one!)Roberto Caboni
The language you're using here is C++ with no C++ standard library. The C tag doesn't apply at all.Antti Haapala
Please stop using delay like that. You must read and parse the responses received from the modem.hlovdal
@RichardChambers Thank you for your comprehensive answer. I am very grateful for that. Tomorrow I will work on it and let you know if it worked. I haven't used your advice yet but for now I know that after pressing the RESET button on the arduino UNO microcontroller the system starts and works but sometimes it stops and does not work without pressing the RESET button again.Martin
Hmmm. That behavior does lend support to the idea that something in your program is running into a wait state due to needing some resource. The RESET button restarts the system and your program is then free to run until it once more needs some resource and needs to wait until it is available. I suspect in your case the resource is serial output buffer space due to no device consuming the characters from the serial port. I'm curious as to how large is the serial output buffer and how many bytes are you writing out. Could you print the value of Serial.availableForWrite() in Setup()?Richard Chambers

1 Answers

2
votes

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...");