Arduino UNO + SIM800L - 向服务器发送数据

Arduino UNO + SIM800L - sending data to server

我正在使用带有调制解调器 sim800l 的 arduino UNO 板。我想用它每 10 秒向服务器 mysql 发送一次数据。当我在 arduino IDE 中打开串口监视器时一切正常(数据正在保存到 mysql 数据库)但是当串口监视器关闭时就不起作用了。

我想远程使用我的系统,连接到移动电源。但只有当我打开 arduino IDE 串行监视器时它才有效。

如何编辑代码使微控制器在不连接计算机和打开串口监视器的情况下工作?

#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());
  }
}

我不确定 Serial 的底层实现,但是可能会无限等待正在发生的 Serial.println()

并且阅读关于 Serial.flush() 的文档,它似乎也可能是无限等待串行输出在它之前完成的原因 returns。

因为 Serial.println() 似乎使用 Serial.write() 功能来做它的事情我想如果你没有设备在某个时候从串行端口读取,写缓冲区就会变满并导致Serial.println() 来阻止。参见 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().

请参阅 Serial.flush() 函数 https://www.arduino.cc/reference/en/language/functions/communication/serial/flush/ 的解释,其中注释:

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.

并查看这篇文章,https://www.baldengineer.com/when-do-you-use-the-arduinos-to-use-serial-flush.html 上面写着

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.

这句话的关键是“外向”。 Serial.flush() 没有 正如许多人所想的那样清空“传入”缓冲区。它暂停你的 在刷新传输缓冲区时编程。

我会在使用 Serial.println() 进行任何输出之前使用 Serial.availableForWrite() 函数,如果可用字节数表明写入缓冲区已满,则跳过输出。

可能最好的方法是作为 Setup() 函数的一部分,在执行 Serial.begin() 之后检查写入缓冲区大小,并将其存储在一个全局变量中,然后您可以使用该变量来查看写缓冲区是否清空。

请参阅 https://www.instructables.com/id/Arduino-Serial/,其中有这样的话:

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()

另见 https://www.arduino.cc/reference/en/language/functions/communication/serial/availableforwrite/

还有if (Serial)可以用来检查端口是否可用。 https://www.arduino.cc/reference/en/language/functions/communication/serial/ifserial/ 但是我怀疑更多的是检查请求的端口是否可用,而不是检查端口是否真的在 link.

另一端的设备上运行

还有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.

建议的操作步骤

首先,我认为 Setup() 函数中的 Serial.flush() 不是必需的,可以安全地删除它。虽然这使得控制台在 Setup() 期间立即输出,但它确实引入了等待远程情况,在这种情况下没有设备从串行线路读取以清空输出缓冲区。

我还建议,对于您执行的每一行 Serial.println(),首先检查 Serial.availableForWrite() 可用的缓冲区字节数,如:

int firstAvailableForWrite = 0;

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

然后在您要写入的地方使用类似于以下示例的 if 语句对其进行修改:

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

或者您也可以创建如下所示的函数:

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

    return iCount;
}

那么无论你想在哪里使用 Serial.println() 你都可以使用 serialPrintLineIfAvailable() 就像 serialPrintLineIfAvailable("Config SIM900...");