Зависает Ардуино Uno. Ошибки или неоптимальное написание скетча?

logger
Offline
Зарегистрирован: 21.06.2018

Добрый день, уважаемые форумчане.

 

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

Три напряжения и три силы тока на аналоговых входах Ардуино-UNO, плюс к тому датчик температуры по OneWire.

 

Ардуино опрашивает каждый из датчиков 100раз, затем осредняет и результат добавляет в пакет для отправки. Раз в две минуты весь пакет отправляется на сервер через ESP8266.

 

«На столе» всё работает продолжительно, без замечаний. При подключении к  «живым» устройствам, на которых постоянно меняются параметры, Ардуино сразу или через время зависает и может висеть несколько часов, потом сама восстанавливается и продолжает работать. Быстрая перезагрузка не помогает. Длительная перезагрузка помогает, но система снова виснет.

 

Отключение части датчиков иногда помогает, но системы (чтобы уверенно сказать что какой-то из них перегружает Ардуино) я не увидел.

 

Подскажите, пожалуйста, правильно ли организована работа моего скетча?

 

 
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
 
long nextTime = 100000;                       // Служебная переменная
//*-- Настройки контроллера
#define SSID "-------"                        // Название точки доступа     
#define PASS "-------"                        // Пароль                     
String IP = "--------";                       // Адрес сервера 
#define esp_bitrate 9600                      // Скорость передачи данных между arduino и ESP8266
#define rxpin 10                              //RX
#define txpin 11                              //TX
#define one_wire_pin 2                        // Вход для подключения датчиков тем-ры
#define AnalogIn0 A0                          // Аналоговый вход 0  (Напряжение АКБ)
#define AnalogIn1 A1          
#define AnalogIn2 A2          
#define AnalogIn3 A3          
#define AnalogIn4 A4          
#define AnalogIn5 A5          
 
//*-- Параметры полученные при регистрации на сайте
String ID = "-------";                              // ID                                             (!)
String KEY = "-------";                        // Код доступа                                (!)
long interval = 120000;                      // Периодичность отправки пакетов на сервер (120 секунд)
//*-- Работа с несколькими датчиками по одной шине
OneWire oneWire(one_wire_pin);
DallasTemperature sensors(&oneWire);
//*-- Software Serial
SoftwareSerial espSerial( rxpin, txpin );    // RX, TX
//*-- GET Information
String GET = "GET /get?cid=" + ID + "&key=" + KEY;              // GET request
String HOST = "Host: " + IP + "\r\n\r\n";
 
void setup() {
  Serial.begin(esp_bitrate);
  espSerial.begin(esp_bitrate);
  sensors.begin();                          //Инициализация опроса датчиков температуры DS18B20 (если используются)
  sendespSerial("AT");
  delay(2000);
  if (espSerial.find("OK"))
  {
    Serial.println("RECEIVED ESP: OK\nData ready to sent!");
    connectWiFi();
  }
}
void loop() {
  //*-- Измерение температуры
  sensors.requestTemperatures();
  int t1 = round(sensors.getTempCByIndex(0));
  delay(2000);
  String T1 = String(t1);                                       // turn integer to string
 
 
  //*-- Измерение напряжения делителем (делается 100 замеров и усредняется)
    float Volt32 = 0;
    for (int i = 0; i < 100; i++) {
      Volt32 = Volt32 + (0.03 * analogRead(AnalogIn5)) / 100;             // Пропорция 30,72/4,8В 4.77v
      delay(1);  
    }
    String Uakb = String(Volt32);
 
    float VoltPanel = 0;
    for (int i = 0; i < 100; i++) {
      VoltPanel = VoltPanel + (0.15 * analogRead(AnalogIn4)) / 100;        // Пропорция 153,6/4,8В
      delay(1);     
    }
    String Upan = String(VoltPanel);
 
    float Volt16 = 0;
    for (int i = 0; i < 100; i++) {
      Volt16 = Volt16 + (0.015 * analogRead(AnalogIn3)) / 100;             // Пропорция 15,36/4,8В 
      delay(1);
    }
    String Uakb2 = String(Volt16);
 
    float AmpPanel = 0;                                               // Панели, от 0 до 7 Ампер, измеряется 50-ти амперным датчиком
    if(analogRead(AnalogIn2) < 510) {
      AmpPanel = 0.01;
      delay(1);
    }
    else {   
    for (int i = 0; i < 100; i++) {
      AmpPanel = AmpPanel + (0.00122 * (analogRead(AnalogIn2) - 510));          // Чувств. датчика 40mV/А  
      delay(1);
    }
    }
    String TokPanel = String(AmpPanel);
   
    
    float AmpSKZ = 0;                                                // СКЗ-40, от 0 до 40 Ампер, измеряется 50-ти амперным датчиком
    if (analogRead(AnalogIn1) > 510) {
      AmpSKZ = 0.01;
      delay(1);
    }
    else {
    for (int i = 0; i < 100; i++) {                                 // измерения на датчике тока в диапазоне 0-2.5в, где 2.5в соответствуют 0.00А, а 0в соответствует 50.0А
     AmpSKZ = AmpSKZ + (0.00122 * (510 - analogRead(AnalogIn1)));               // Чувств. датчика 40mV/А
      delay(1);
    }
    }
    String TokSKZ = String(AmpSKZ);
  
 
    float AmpDD = 0;                                                  // DualDSP, от 0 до 100 Ампер, измеряется 100 амперным датчиком
                                                                     // возможны отрицательные значения (при зарядке батарей от сети)
    for (int i = 0; i < 100; i++) {
      AmpDD = AmpDD + (0.0024414 * (analogRead(AnalogIn0) - 510));               // Чувств. датчика 20mV/А 
      delay(1);
    }
    String TokDD = String(AmpDD);
 
 
   if ( millis() - nextTime > (interval - 4215) ) {
      // Отправляем пакет на сервер,                                                                       
      update_param(T1, Uakb, Upan, Uakb2, TokPanel, TokSKZ, TokDD);                                                                             
      nextTime = millis();
      }
}
 
//*-- Функции --*//
//*--Функция отправки в порт ESP и терминал
void sendespSerial(String cmd) {
  Serial.print("SEND: ");
  Serial.println(cmd);
  espSerial.println(cmd);
}
 
 
//*-- Соединение с точкой доступа
boolean connectWiFi() {
  espSerial.println("AT+CWMODE=1");                             // Режим работы "клиент"
  delay(2000);
  String cmd = "AT+CWJAP=\"";                                   // Подключение к точке доступа
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";
  sendespSerial(cmd);
  delay(5000);
  if (espSerial.find("OK"))
  {
    Serial.println("Connect: OK");
    return true;
  }
  else
  {
    Serial.println("Connect: Error");
    return false;
  }
 
  cmd = "AT+CIPMUX=0";                                           // Режим одиночного соединения
  sendespSerial( cmd );
  if ( espSerial.find( "Error") )
  {
    Serial.print( "RECEIVED: Error" );
    return false;
  }
}
 
//*--- Отправка данных на сервер, если есть параметры, так же дописать через запятую с указанием типа, например: String T3
//  void update_param( String T1, String Uakb, String Upan, String Uakb2, String TokPanel, String TokSKZ, String TokDD) {
 
void update_param( String T1, String Uakb, String Upan, String Uakb2, String TokPanel, String TokSKZ, String TokDD) {
  
  String cmd = "AT+CIPSTART=\"TCP\",\"";                       // Setup TCP connection
  cmd += IP;
  cmd += "\",80";
  sendespSerial(cmd);
  delay(1000);
 
  if ( espSerial.find( "Error" ) )
  {
    Serial.print( "RECEIVED: Error\nExit1" );
    connectWiFi();
    return;
  }
 
  // Отправка строки на сервер
//  cmd = GET + "&p1=" + T1 + "&p2=" + Uakb + "&p3=" + Upan+ "&p4=" + Uakb2 + "&p5=" + TokPanel + "&p6=" + TokSKZ + "&p7=" +  TokDD ;
  cmd = GET + "&p1=" + T1 + "&p2=" + Uakb + "&p3=" + Upan+ "&p4=" + Uakb2 + "&p5=" + TokPanel + "&p6=" + TokSKZ + "&p7=" +  TokDD; 
 
  cmd += " HTTP/1.1\r\n"  + HOST;
  espSerial.print( "AT+CIPSEND=" );
  espSerial.println( cmd.length() );
  if (espSerial.find( ">" ) )
  {
    Serial.print(">");
    Serial.print(cmd);
    espSerial.print(cmd);
    delay(30);
  }
  else
  {
    sendespSerial( "AT+CIPCLOSE" );                            //close TCP connection
  }
  if ( espSerial.find("OK") )
  {
    Serial.println( "RECEIVED: OK" );
  }
  else
  {
    Serial.println( "RECEIVED: Error\nExit2" );
    connectWiFi();
  }
}
 
bwn
Offline
Зарегистрирован: 25.08.2014

Вставьте для начала код нормально (в общих есть тема) и дайте схему.

logger
Offline
Зарегистрирован: 21.06.2018

Спасибо. Сейчас разберусь, сделаю.

logger
Offline
Зарегистрирован: 21.06.2018
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

long nextTime = 100000;                       // Служебная переменная
//*-- Настройки контроллера
#define SSID "-------"                        // Название точки доступа     
#define PASS "-------"                        // Пароль                     
String IP = "--------";                       // Адрес сервера 
#define esp_bitrate 9600                      // Скорость передачи данных между arduino и ESP8266
#define rxpin 10                              //RX
#define txpin 11                              //TX
#define one_wire_pin 2                        // Вход для подключения датчиков тем-ры
#define AnalogIn0 A0                          // Аналоговый вход 0  (Напряжение АКБ)
#define AnalogIn1 A1          
#define AnalogIn2 A2          
#define AnalogIn3 A3          
#define AnalogIn4 A4          
#define AnalogIn5 A5          

//*-- Параметры полученные при регистрации на сайте
String ID = "-------";                              // ID                                             (!)
String KEY = "-------";                        // Код доступа                                (!)
long interval = 120000;                      // Периодичность отправки пакетов на сервер (120 секунд)
//*-- Работа с несколькими датчиками по одной шине
OneWire oneWire(one_wire_pin);
DallasTemperature sensors(&oneWire);
//*-- Software Serial
SoftwareSerial espSerial( rxpin, txpin );    // RX, TX
//*-- GET Information
String GET = "GET /get?cid=" + ID + "&key=" + KEY;              // GET request
String HOST = "Host: " + IP + "\r\n\r\n";

void setup() {
  Serial.begin(esp_bitrate);
  espSerial.begin(esp_bitrate);
  sensors.begin();                          //Инициализация опроса датчиков температуры DS18B20 (если используются)
  sendespSerial("AT");
  delay(2000);
  if (espSerial.find("OK"))
  {
    Serial.println("RECEIVED ESP: OK\nData ready to sent!");
    connectWiFi();
  }
}
void loop() {
  //*-- Измерение температуры
  sensors.requestTemperatures();
  int t1 = round(sensors.getTempCByIndex(0));
  delay(2000);
  String T1 = String(t1);                                       // turn integer to string


  //*-- Измерение напряжения делителем (делается 100 замеров и усредняется)
    float Volt32 = 0;
    for (int i = 0; i < 100; i++) {
      Volt32 = Volt32 + (0.03 * analogRead(AnalogIn5)) / 100;             // Пропорция 30,72/4,8В 4.77v
      delay(1);  
    }
    String Uakb = String(Volt32);

    float VoltPanel = 0;
    for (int i = 0; i < 100; i++) {
      VoltPanel = VoltPanel + (0.15 * analogRead(AnalogIn4)) / 100;        // Пропорция 153,6/4,8В
      delay(1);     
    }
    String Upan = String(VoltPanel);

    float Volt16 = 0;
    for (int i = 0; i < 100; i++) {
      Volt16 = Volt16 + (0.015 * analogRead(AnalogIn3)) / 100;             // Пропорция 15,36/4,8В 
      delay(1);
    }
    String Uakb2 = String(Volt16);

    float AmpPanel = 0;                                               // Панели, от 0 до 7 Ампер, измеряется 50-ти амперным датчиком
    if(analogRead(AnalogIn2) < 510) {
      AmpPanel = 0.01;
      delay(1);
    }
    else {   
    for (int i = 0; i < 100; i++) {
      AmpPanel = AmpPanel + (0.00122 * (analogRead(AnalogIn2) - 510));          // Чувств. датчика 40mV/А  
      delay(1);
    }
    }
    String TokPanel = String(AmpPanel);
   
    
    float AmpSKZ = 0;                                                // СКЗ-40, от 0 до 40 Ампер, измеряется 50-ти амперным датчиком
    if (analogRead(AnalogIn1) > 510) {
      AmpSKZ = 0.01;
      delay(1);
    }
    else {
    for (int i = 0; i < 100; i++) {                                 // измерения на датчике тока в диапазоне 0-2.5в, где 2.5в соответствуют 0.00А, а 0в соответствует 50.0А
     AmpSKZ = AmpSKZ + (0.00122 * (510 - analogRead(AnalogIn1)));               // Чувств. датчика 40mV/А
      delay(1);
    }
    }
    String TokSKZ = String(AmpSKZ);
  

    float AmpDD = 0;                                                  // DualDSP, от 0 до 100 Ампер, измеряется 100 амперным датчиком
                                                                     // возможны отрицательные значения (при зарядке батарей от сети)
    for (int i = 0; i < 100; i++) {
      AmpDD = AmpDD + (0.0024414 * (analogRead(AnalogIn0) - 510));               // Чувств. датчика 20mV/А 
      delay(1);
    }
    String TokDD = String(AmpDD);


   if ( millis() - nextTime > (interval - 4215) ) {
      // Отправляем пакет на сервер,                                                                       
      update_param(T1, Uakb, Upan, Uakb2, TokPanel, TokSKZ, TokDD);                                                                             
      nextTime = millis();
      }
}

//*-- Функции --*//
//*--Функция отправки в порт ESP и терминал
void sendespSerial(String cmd) {
  Serial.print("SEND: ");
  Serial.println(cmd);
  espSerial.println(cmd);
}


//*-- Соединение с точкой доступа
boolean connectWiFi() {
  espSerial.println("AT+CWMODE=1");                             // Режим работы "клиент"
  delay(2000);
  String cmd = "AT+CWJAP=\"";                                   // Подключение к точке доступа
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";
  sendespSerial(cmd);
  delay(5000);
  if (espSerial.find("OK"))
  {
    Serial.println("Connect: OK");
    return true;
  }
  else
  {
    Serial.println("Connect: Error");
    return false;
  }

  cmd = "AT+CIPMUX=0";                                           // Режим одиночного соединения
  sendespSerial( cmd );
  if ( espSerial.find( "Error") )
  {
    Serial.print( "RECEIVED: Error" );
    return false;
  }
}

//*--- Отправка данных на сервер, если есть параметры, так же дописать через запятую с указанием типа, например: String T3
//  void update_param( String T1, String Uakb, String Upan, String Uakb2, String TokPanel, String TokSKZ, String TokDD) {

void update_param( String T1, String Uakb, String Upan, String Uakb2, String TokPanel, String TokSKZ, String TokDD) {
  
  String cmd = "AT+CIPSTART=\"TCP\",\"";                       // Setup TCP connection
  cmd += IP;
  cmd += "\",80";
  sendespSerial(cmd);
  delay(1000);

  if ( espSerial.find( "Error" ) )
  {
    Serial.print( "RECEIVED: Error\nExit1" );
    connectWiFi();
    return;
  }

  // Отправка строки на сервер
//  cmd = GET + "&p1=" + T1 + "&p2=" + Uakb + "&p3=" + Upan+ "&p4=" + Uakb2 + "&p5=" + TokPanel + "&p6=" + TokSKZ + "&p7=" +  TokDD ;
  cmd = GET + "&p1=" + T1 + "&p2=" + Uakb + "&p3=" + Upan+ "&p4=" + Uakb2 + "&p5=" + TokPanel + "&p6=" + TokSKZ + "&p7=" +  TokDD; 

  cmd += " HTTP/1.1\r\n"  + HOST;
  espSerial.print( "AT+CIPSEND=" );
  espSerial.println( cmd.length() );
  if (espSerial.find( ">" ) )
  {
    Serial.print(">");
    Serial.print(cmd);
    espSerial.print(cmd);
    delay(30);
  }
  else
  {
    sendespSerial( "AT+CIPCLOSE" );                            //close TCP connection
  }
  if ( espSerial.find("OK") )
  {
    Serial.println( "RECEIVED: OK" );
  }
  else
  {
    Serial.println( "RECEIVED: Error\nExit2" );
    connectWiFi();
  }
}

 

logger
Offline
Зарегистрирован: 21.06.2018

Со схемой сложнее. Не подумал, что она нужна. 

Три делителя напряжений, три датчика тока  ACS758, обвязка соединения с платой Wi-Fi

Сегодня уже ночь. Завтра нарисую и выложу.

andryn
Offline
Зарегистрирован: 08.06.2018

logger пишет:

Подскажите, пожалуйста, правильно ли организована работа моего скетча?

В целом нормально, но лучше избавиться от таких конструкций:

Volt32 = Volt32 + (0.03 * analogRead(AnalogIn5)) / 100;

Лучше вычичсления делать в целых числах, а форматировать при выводе.

Так же фукция  update_param принимает кучу стрингов. Лучше передать в нее лонги, а их форматирванием заняться в самой фунции.

Может просто не хватать памяти....

logger
Offline
Зарегистрирован: 21.06.2018

Спасибо. Понял. Буду исправлять.

 

logger
Offline
Зарегистрирован: 21.06.2018

logger
Offline
Зарегистрирован: 21.06.2018

Схема нарисовалась вот такая.

Три датчика тока, три делителя напряжения (на 16в, на 32в и на 150в)

Вышло так, что "масса" общая для всех приборов.

В DC-DC конверторе "минус" входа и выхода общий. На контролере солнечных батарей - тоже общий.

На инверторе - не знаю.

Для экономии я собрал вместе и посадил на один конденсатор питание датчиков тока ACS758.

"на столе" всё работает, но какой частоты токи используют приборы и может ли это мешать Ардуино - даже предположить не могу.

Как считаете, не нужно ли где-то разделить всё это хозяйство по питанию?