Исправление последовательной связи, условие доступности последовательных данных проверяется даже после считывания всех отправленных данных.

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

В установке все датчики подключены к плате Uno, которая последовательно передает данные на esp8266.

Контакт 2 Uno подключен к контакту 2 esp8266

Контакт 3 Uno подключен к контакту 3 esp8266

Сейчас платы питаются от USB-портов компьютера.

Насколько я понимаю, после считывания всех данных Serial.available() становится равным 0 и цикл while() больше не будет выполняться, но снова работал и считывал данные... чтобы не отправлять одни и те же данные снова и снова (в FireBase), я использовал логические значения, чтобы позаботиться о них.

Данные должны быть доступны только один раз в 30 секунд, поэтому после полного чтения строки я мог видеть, что pgm вошел в цикл while() и считывает одно/два значения

// загружен на esp8266 Lolin(wemos) d1 r2 и mini

#include<ESP8266WiFi.h>
#include<FirebaseArduino.h>
#include<SoftwareSerial.h>

// Установите их для запуска примера.
#define FIREBASE_HOST "@#$%^.firebaseio.com"
#define FIREBASE_AUTH "********"

#define WIFI_SSID "###########"
#define WIFI_PASSWORD "&^*^*%$#"

SoftwareSerial esp(D2,D3);

плавающий temp_fb;
float gas_fb;
float hum_fb;

unsigned long last_chk = 0 ;
беззнаковое долгое время истекло;

bool t_ar, h_ar, g_ar = false; //проверка прихода всех данных отправки b4

символ р;
Строка cu_st = "c";

число найдено = 1;

недействительная установка () {
Серийный.начать(9600);
особ.начало(4800);

// подключаемся к вайфаю.
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print ("подключение");
в то время как (WiFi.status ()! = WL_CONNECTED) {
Серийный.принт(".");
delay(500);
}

Serial.println («подключено:»);
Serial.println(WiFi.localIP());

Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

пустой цикл ()
{
time_elapsed = миллисекунды ();
если (прошедшее время - последняя_проверка > 5000){
Serial.print("проверка данных от arduino...\tfeeder state\t");
Serial.println(cu_st);
last_chk = прошедшее_время;
time_elapsed = миллисекунды ();
}
в то время как (особенно доступно ()> 0)
{
если (найдено == 1)
{
Serial.println("...найдены данные...............") ;
найдено = 0;
}
г = esp.read();
//Serial.print("первый символ\t"); просто для отладки
//Серийный.println(r);
переключатель (г)
{

случай 'т':
{
Serial.println("Получил...");
т_ар = правда;
temp_fb = esp.readStringUntil(',').toFloat();
перерыв ;
}

случай 'г':
{
Serial.println("получил г...");
г_ар = правда;

gas_fb = esp.readStringUntil(',').toFloat();;
перерыв ;
}

случай «ч»:
{
Serial.println("получил ч...");
h_ar = правда;

hum_fb = esp.readStringUntil(',').toFloat();
перерыв ;
}

случай «с»:
{
cu_st = "с" ;
Firebase.setString («кормушка», «c»);
}
по умолчанию: перерыв;

}

}

найдено = 1;

если (g_ar и t_ar и h_ar)
{
//запись в firebase
Serial.println("сейчас получил набор.. на фб");
Firebase.setFloat("ДАТЧИК ГАЗАInst",gas_fb);
Firebase.setFloat("ДАТЧИК ВЛАЖНОСТИInst", hum_fb);
Firebase.setFloat ("TEMP SENSORinst", temp_fb);
Firebase.pushFloat("ДАТЧИК ГАЗА",gas_fb);
Firebase.pushFloat("ДАТЧИК ВЛАЖНОСТИ" ,hum_fb);
Firebase.pushFloat («ДАТЧИК ТЕМПЕРАТУРЫ», temp_fb);
}

t_ar, h_ar, g_ar = ложь;

cu_st = Firebase.getString («фидер»);


если (cu_st == "о")
{
Serial.println("\t\trecd req to feed");
esp.print('о');
}

}

Arduino отправляет данные каждые 30 секунд. Сервопривод, подключенный к Arduino, дрожал каждый раз, когда отправлялись данные (очевидно, из-за недостаточного питания для всех подключенных устройств, а также из-за того, что и Softwareserial, и сервопривод имели одинаковый таймер), поэтому я добавил светодиод только для пробы
По какой-то причине всегда выполняется блок if в close_feed().


// uploaded to esp8266 Lolin(wemos) d1 r2 and mini 

#include<ESP8266WiFi.h>
#include<FirebaseArduino.h>
#include<SoftwareSerial.h> 

// Set these to run example.
#define FIREBASE_HOST "@#$%^.firebaseio.com" 
#define FIREBASE_AUTH "********" 

#define WIFI_SSID "###########"
#define WIFI_PASSWORD "&^*^*%$#" 

SoftwareSerial esp(D2,D3);

float temp_fb;
float gas_fb;
float hum_fb;

unsigned long last_chk = 0 ; 
unsigned long time_elapsed; 

bool t_ar , h_ar , g_ar = false ; //chk arrival of all data b4 sending

char r;  
String cu_st = "c"; 

int found = 1;

void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting"); 
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop() 
{
  time_elapsed = millis(); 
  if(time_elapsed - last_chk > 5000){ 
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  { 
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     } 
     r = esp.read(); 
     //Serial.print("first char\t"); just for debugging purposes 
     //Serial.println(r); 
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.readStringUntil(',').toFloat(); 
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.readStringUntil(',').toFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;

        hum_fb = esp.readStringUntil(',').toFloat();
        break ;   
      }

      case 'c':  
      {
        cu_st = "c" ;
        Firebase.setString("feeder" ,"c");
      }
      default: break; 

     }

  }

  found = 1 ; 

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase  
     Serial.println("got the set.. to fb now"); 
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;

  cu_st = Firebase.getString("feeder");


   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed"); 
    esp.print('o');   
   }

} 

Некоторым образом некоторые блоки выполняются даже тогда, когда они не должны выполняться. Я написал код, но не могу понять, где он дает сбой, использовал много серийных отпечатков, чтобы посмотреть, как работает код, но только еще больше меня запутал!

Если кто-нибудь сможет взглянуть на этот код и указать на недостатки... буду очень признателен.

РЕДАКТИРОВАТЬ: я изменил код, как предложено ниже, но теперь Arduino получает случайные данные в качестве входных данных (изображение прилагается) Я также добавил измененный код (я знаю, что этот пост становится все больше и больше, но я подумал, что внесение изменений в уже существующий код здесь не улучшит читабельность)

//uploaded to arduino Uno 
#include <SoftwareSerial.h>
#include<TimerOne.h>


SoftwareSerial ArduinoUno(3,2);
#include<Servo.h>
#include "DHT.h"

//Servo feeder;

int send_rate = 30000; //every 30 secs send data
unsigned long last_time_stamp = 0;
unsigned long cur_time = 0;

String sen_vals = "";
#define led 13
int feeding = 0 ;
const int gas = 0;//gas sensor o/p
#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  ArduinoUno.begin(4800);
  pinMode(led,OUTPUT);
  //feeder.attach(11);
  //feeder.write(85);
  Timer1.initialize(10000); //every 10 millisecond check for arrival of feed command
  Timer1.attachInterrupt(feed_cmd); //chk feed_cmd for every 10 mS
   dht.begin();

  pinMode (3,INPUT); //recieve from esp
  pinMode (2,OUTPUT); //transmit to esp


}

void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();

    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0);
       feeding = 1;
       ArduinoUno.print("c");
       valve = "";
    }
  }
}

void close_feed()
{
  if(feeding == 1)
  {

    feeding = 0;
    delay(5000);
    //feeder.write(85);
    digitalWrite(led,LOW);
    Serial.println("I am closing feeder");

   }
}

void send_data()
{
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  String ht = String('h')+String(h)+String(',')+String('t')+String(t)+String(',');

  float raw_v = analogRead(gas);  
  String g = String('g')+String(raw_v)+String(',');

  sen_vals = ht + g ;

  Serial.println(sen_vals);
  ArduinoUno.print(sen_vals);
}

void loop()
{
  // put your main code here, to run repeatedly:

  close_feed();
  cur_time = millis();
  if(cur_time > last_time_stamp + send_rate)
  {

    last_time_stamp = cur_time;
    send_data();

  }

}

void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting"); 
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop() 
{
  time_elapsed = millis(); 
  if(time_elapsed - last_chk > 5000){ 
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  { 
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     } 
     r = esp.read(); 
     //Serial.print("first char\t");
     //Serial.println(r); 
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.parseFloat(); 
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.parseFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;
        hum_fb = esp.parseFloat();
        break ;   
      }
      default: break; 

     }

  }

  found = 1 ; 

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase  
     Serial.println("got the set.. to fb now"); 
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;
  if (cu_st == "c")
  {
    sent = 0; 
  }
  cu_st = Firebase.getString("feeder");  
   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed"); 
    if(sent == 0)
    {
      esp.print('o');
      sent =1; 
      cu_st = "c";    
      Serial.println("setting feeder to close in firebase");
      Firebase.setString("feeder" ,"c");

   }

  }
}   

здесь'картинка со случайным символом Спасибо за ваше время!!!

, 👍0


1 ответ


1

Я не могу точно определить источник наблюдаемых вами проблем, поскольку описания проблем недостаточно четкие. Но есть некоторые очевидные проблемы/потенциал для улучшения вашего кода.

В коде Uno:

  • Абсолютно необязательно использовать прерывание по таймеру для чтения интерфейса SoftwareSerial. Вместо этого вы должны написать свою функцию loop() неблокирующей, что означает, что она не ждет, пока что-то произойдет, но тем временем будет выполнять другой код (чтобы не было задержки в close_feed ()). Затем вы можете просто прочитать последовательные данные в функции цикла. Таким образом вы сохраняете таймер.

  • В send_data() вы используете класс String для объединения строки удобочитаемых данных, а затем отправки ее. Использование класса String таким образом является злом, поскольку при каждой операции concat он будет выделять новый буфер для строки, удаляя старый. Это делает швейцарский сыр из вашей памяти кучи (так называемая фрагментация кучи). Это может привести к нестабильности. Прочтите запись в блоге Маженко о пороках строк Arduino. информация. Вместо объединения вы должны просто печатать информацию одну за другой:

    Serial.print("h");
    Serial.print(h);
    Serial.print(",t");
    Serial.print(t);
    

    и так далее.

  • Ваша обработка функции millis() должна отличаться. Он будет перенесен через 52 дня. Чтобы ваш код не работал неправильно в это время, вам нужно всегда учитывать разницу во времени:

    if(cur_time - last_time_stamp > send_rate)
    

    вместо

    if(cur_time > last_time_stamp + send_rate)
    

В коде ESP:

  • Ваш код чтения SoftwareSerial кажется мне странным, но я думаю, что он должен работать. Я бы ввел протокол сообщений для потока данных, что означает пометить конец полного сообщения (сообщение, содержащее один кадр со всеми соответствующими данными) специальным символом-разделителем, например, символом новой строки \n. Затем вы можете прочитать сообщение до этого символа в буфер, а затем обработать сообщение целиком.

Вот что я могу сказать на данный момент. Если вам нужен более сфокусированный ответ, вы должны более подробно описать симптомы (какое поведение вы видите и чего вы ожидали).

,

спасибо за указание на некоторые хорошие практики и детали... сработает..., @Somasundharam Sampath

Что касается вопросов, я изо всех сил пытаюсь выразить это словами... Например. Когда pgm запускается, pblm нет, но когда я даю команду открыть из приложения, он просто начинает непрерывно печатать «Я закрываю фидер», это не должно происходить правильно, потому что мы установили «кормление». =0` и единственный способ попасть в блок `if` `close_feed()` - это если `feed_cmd()` снова вызывается, но этого не должно происходить потому что мы уже читали из поступающего сериала.. Надеюсь, я объяснил свою проблему!!!, @Somasundharam Sampath

Вы постоянно отправляете символ подачи o на основе значения Firebase "feeder". Это значение сбрасывается сразу после того, как вы его установили? Если нет, то это означает, что если значение Firebase «feeder» остается «o», esp будет постоянно отправлять символ «o», что заставит Arduino постоянно закрывать фидер., @chrisl

Да, теперь я понимаю поток.... Но я подумал, что как только Arduino получит открытый cmd, отправив `"c"` в esp, который, в свою очередь, запишет в firebase , этого не должно происходить. перепишу так, чтобы esp сам отправлял `"c"` в firebase сразу после отправки open cmd в arduino... отвечая, я подумал, что, возможно, изменение значения происходит слишком быстро, и `"c"` считывается с пропуском `"o"` cmd ), @Somasundharam Sampath

Вы должны отправить команду «o» только один раз в Uno. Даже если вы сразу отправите «c» обратно в ESP, ESP, скорее всего, уже отправит несколько команд «o» в Uno. Так что просто отправьте его один раз, а не постоянно, @chrisl

какие-либо предположения относительно того, почему это новое поведение произошло.?, @Somasundharam Sampath