3

我正在使用带有调制解调器 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());
  }
}
4

1 回答 1

2

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

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

由于Serial.println()似乎使用该Serial.write()功能来完成它的事情,我想如果您在某个时候没有从串行端口读取的设备,则写入缓冲区已满并导致Serial.println()阻塞。见https://www.arduino.cc/reference/en/language/functions/communication/serial/write/

注意事项和警告

从 Arduino IDE 1.0 开始,串行传输是异步的。如果传输缓冲区中有足够的空白空间,Serial.write() 将在任何字符通过串行传输之前返回。如果传输缓冲区已满,则 Serial.write() 将阻塞,直到缓冲区中有足够的空间。为避免阻塞对 Serial.write() 的调用,您可以首先使用 availableForWrite() 检查传输缓冲区中的可用空间量。

请参阅此Serial.flush()功能说明https://www.arduino.cc/reference/en/language/functions/communication/serial/flush/其中注释:

Serial.flush()

描述

等待传出串行数据的传输完成。(在 Arduino 1.0 之前,这会删除任何缓冲的传入串行数据。)

flush() 继承自 Stream 实用程序类。

并看到这篇文章,https://www.baldengineer.com/when-do-you-use-the-arduinos-to-use-serial-flush.html说“

Serial.flush() 做什么?

来自 Serial.flush 的 Arduino 参考(可在此页面上找到):

等待传出串行数据的传输完成。

该声明的关键是“外向”。Serial.flush() 并没有像许多人想象的那样清空“传入”缓冲区。它会在刷新传输缓冲区时暂停您的程序。

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

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

请参阅https://www.instructables.com/id/Arduino-Serial/有这样的说法:

第三步:命令:AvailableForWrite()

描述

在不阻塞写入操作的情况下,获取可用于写入串行缓冲区的字节数(字符)。

句法

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/ 但是我怀疑这更多的是检查请求的端口是否可用,而不是端口是否实际运行链路另一端的设备。

还有Serial.available() https://www.arduino.cc/reference/en/language/functions/communication/serial/available/

Serial.available()

描述

获取可用于从串行端口读取的字节数(字符)。这是已经到达并存储在串行接收缓冲区(包含 64 个字节)中的数据。

Serial.available() 继承自 Stream 实用程序类。

句法

Serial.available()

参数

Serial:串口对象。请参阅串行主页上每个板的可用串行端口列表。

退货

可读取的字节数。

建议的行动方案

首先,我认为函数中的Serial.flush()inSetup()不是必需的,可以安全地删除它。虽然这使得控制台输出在 期间立即进行,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()as inserialPrintLineIfAvailable("Config SIM900...");

于 2020-01-25T17:53:27.977 回答