Arduino UNO + SIM800L - отправка данных на сервер - PullRequest
2 голосов
/ 25 января 2020

Я использую плату Arduino UNO с модемом sim800l. Я хочу использовать его для отправки данных на сервер mysql каждые 10 секунд. Все работает нормально, когда у меня открыт последовательный монитор в Arduino IDE (данные сохраняются в базе данных mysql), но когда последовательный монитор выключен, то не работает.

Я хочу использовать системный пульт, подключенный в powerbank. Но это работает только тогда, когда я открыл последовательный монитор 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());
  }
}

1 Ответ

1 голос
/ 25 января 2020

Я не уверен насчет базовой реализации Serial, однако может произойти какое-то бесконечное ожидание происходящего Serial.println().

И чтение документации по Serial.flush() Похоже, что это также может быть причиной бесконечного ожидания окончания вывода последовательного выхода до sh.

Поскольку 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.flu sh ()

Описание

Ожидает завершения передачи исходящих последовательных данных. (До Arduino 1.0 вместо этого удалялись все буферизованные входящие последовательные данные.)

flu sh () наследуется от служебного класса Stream.

И см. Эту статью https://www.baldengineer.com/when-do-you-use-the-arduinos-to-use-serial-flush.html с надписью "

Что делает Serial.flu sh ()?

Из ссылки на Arduino для Serial.flu sh ( находится на этой странице):

Ожидание завершения передачи исходящих последовательных данных.

Ключ этого оператора - "исходящий". Serial.flu sh () не очищает «входящий» буфер, как думают многие. Он приостанавливает вашу программу, пока очищается буфер передачи.

Я бы использовал функцию Serial.availableForWrite() перед выполнением любого вывода с использованием Serial.println() и если число доступных байтов указывает на то, что буфер записи заполняется, пропустите вывод.

Вероятно, наилучшим подходом будет использование функции Setup() для проверки размера буфера записи после делать Serial.begin() и хранить это в глобальной переменной Файл, который вы затем используете для проверки, очищается ли буфер записи или нет.

См. https://www.instructables.com/id/Arduino-Serial/, в котором говорится:

Шаг 3: Команда: 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.

Возвращает

Количество байтов, доступных для чтения.

Рекомендуется курс действий

Прежде всего, я не вижу необходимости Serial.flush() в функции Setup(), и ее можно безопасно удалить. Хотя это делает вывод на консоль немедленным во время 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...");

...