BME280 unterbricht schleife

Hallo alle zusammen,

Ich arbeite mich in die Arduino Welt rein. Bisher habe ich an die 30 Arduinos und etliche ESP8266 rund ums haus verbaut und alles läuft wie gewünscht.

Am Wochenende bat mich meine Frau einen weiteren Sensor zu montieren da sie gerne noch Luftfeuchtigkeit in einem Raum gemessen haben wollte. Also in meine Werkstatt gegangen und geschaut was ich an passenden Sensoren zu Verfügung habe. Ein BME280 fiel mir da in die Hände, naja ok Overkill aber hey i2c schnell implementiert. Lets do it. Ich habe in besagtem Raum einen Arduino laufen der bisher 2 Dinge übernimmt. Erstens laufen da eine Menge Fenster Sensoren dran. Weiterhin die Sammelstörmeldung der BMZ sowie die Ausgelöst Meldung der BMZ. Zusätzlich hängen da noch 6 1wire Sensoren dran. Alle Zustände werden via Seriell übertragen dazu gibt es 2 Strings die ich woanders weiter verarbeite.
Ich dachte jetzt schnell den BME dran Software updaten und gut. Denkste erweitere ich das Script um den BME hängt sich das Ding auf und Serielle Kommunikation ist tot. Er sendet dann noch den Status der Fenster nach der abgelaufenen Zeit sendet er noch exakt "In "
Das wäre der String für die Temperatur Daten. Ab da ist dann auch Essig. Ich bin jetzt auf eure Hilfe angewiesen da ich wirklich keinerlei weitere ideen habe.

Also Fehlersuche:
Kabel geprüft? Check
Spannung am BME geprüft? Check
Sensor geprüft? Check hab hier auf besagtem Arduino Uno ein Sketch laufen lassen das nur den BME anspricht. Alle Werte kommen einwandfrei
Irgendwelche Fehler beim Kompilieren? Nein Kompiler läuft sauber ohne Fehler durch

Ich poste hier jetzt den Code rein. Ich weiß das er weder sauber ist noch optimal. Ich wette die art und weise wie ich die abfragen mache hätte man auch vereinfachen können. Ich bin sicherlich auch für alle Hilfestellungen dankbar was das angeht. Ich möchte nur gerne wenn möglich diesen Sensor zum laufen bekommen da er ja funktioniert.

Ich hätte jetzt gern den gesamten Code hier gepostet in Code Tags leider sagt er mir das dann meine Nachricht über 9000 Chars hat daher hänge ich die INO Datei hier an.

HWR_Raum.ino (12.2 KB)

An welcher Stelle wird denn dein Sketch unterbrochen ?

Hänge ein paar serielle Ausgaben auf den Monitor rein, um zu prüfen, wo es hängt.

Sich in den Sketch reinzuarbeiten ist für externe sehr schwer.
Es ist deutlich übersichtlicher, wenn du mit Funktionen arbeitest.

RAM voll?
Checke mal im laufenden Programm:

// Quelle: https://jeelabs.org/2011/05/22/atmega-memory-use/
int freeRam () {
   extern int __heap_start, *__brkval;
   int v;
   return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

falls es ein Atmega ist.

Gruß Tommy

Link auf die BME280 Lib? github oder sonstiges Repository
Rumgeraten fehlt mir da was im setup().
Welcher Beispiels-Sketch hat genau funktioniert?

und weil ich dabei bin:

  • jedes int überprüfen, ob es die Größe eines int braucht. const machen, was sich nicht ändern wird, z.b. deine Pins.
  • und du sollst dir dringend die Verwendung von Arrays anschauen. Du hast das so viel Code-Duplikate/Ähnliches ... das kannst wirklich stark vereinfachen wenn du den Umgang mit Arrays lernst.

Also dies ist der Beispielsketch der funktioniert.

#include "Seeed_BME280.h"
#include <Wire.h>

BME280 bme280;

void setup()
{
  Serial.begin(9600);
  if(!bme280.init()){
    Serial.println("Device error!");
  }
}

void loop()
{
  float pressure;

  //get and print temperatures
  Serial.print("Temp: ");
  Serial.print(bme280.getTemperature());
  Serial.println("C");//The unit for  Celsius because original arduino don't support speical symbols

  //get and print atmospheric pressure data
  Serial.print("Pressure: ");
  Serial.print(pressure = bme280.getPressure());
  Serial.println("Pa");

  //get and print altitude data
  Serial.print("Altitude: ");
  Serial.print(bme280.calcAltitude(pressure));
  Serial.println("m");

  //get and print humidity data
  Serial.print("Humidity: ");
  Serial.print(bme280.getHumidity());
  Serial.println("%");

  delay(1000);
}

Ich hab den Sensor auch an einigen anderen stellen sauber laufen mit genau diesen aufrufen.

Kannst du mir das mit den const genauer erklären?

Bei deiner intensiven Nutzung des Datentyps 'String' würde ich auch auf RAM Probleme tippen. Wahrscheinlich bringt der BME jetzt das Fass zum überlaufen.
Nach der Belegung deiner Pins tippe ich auf Nano oder Uno. Die sind ja nun nicht gerade üppig mit RAM ausgestattet. Da sollte man 'String' eigentlich gar nicht verwenden.

Also wird es allem anschein nach am RAM liegen. Gut ok soweit kann ich folgen.

Welche Alternative habe ich nun um die Nutzung von String zu umgehen?

und Ja es ist ein Arduino UNO

Ein kurzes Beispiel für eine Alternative würde mir reichen von da kann ich dann weiter arbeiten.

wie gesagt ein Lösungsansatz anhand von meiner Aufgabenstellung reicht.

wo ist das in deinem Sketch?

  if(!bme280.init()){
    Serial.println("Device error!");
  }

Welche Alternative habe ich nun um die Nutzung von String zu umgehen?

Musst du gar nicht!

Vorschlag:
Nur einen String verwenden und global definieren.
In Setup() diesen dann groß genug dimensionieren

Alternativ (mein üblicher Weg):
Ganz ohne die String Klasse zu verwenden

#include <Streaming.h>

/*
void sens()  // Funktion für BME280
{
  feucht = bme280.getHumidity();
  Pascal = bme280.getPressure();
  tempfl = bme280.getTemperature();
  Umwelt = "Umwelt-" + String(tempfl) + "-" + String(feucht) + "-" + String(Pascal); // String zusammenbauen
  Serial.println(Umwelt); // Seriell Drucken Umwelt String
}
*/



void sens()  // Funktion für BME280
{
  Serial << "Umwelt-" << bme280.getTemperature() 
         << "-"       << bme280.getHumidity()
         << "-"       << bme280.getPressure()
         << endl;
}

Auch auf die Zwischenvariablen kannst du verzichten.
Zumindest sehe ich keine Notwendigkeit leuchten.

Ganz ohne die String Klasse zu verwenden

Korr: Da ist dir sicher mir was durcheinander geraten. Die zweite Version braucht keine Strings
Statt + und String willst du doch sicher SmartHomeGuy verleiten, nach Streaming.h zu suchen.

verleiten, nach Streaming.h zu suchen.

Von mir aus kann er/sie/es auch endlose Serial.print() und Serial.println() Kaskaden schreiben.
Das ist mir alles vollkommen recht.

Statt + und String willst du doch

Er hat seinen Quellcode mit String Instanziierungen gepflastert.
Endlos viele malloc() realloc() und delete() sind die unmittelbare Folge.
Datenkopieraktionen ohne Ende.

Es geht auch ohne das String Gedöns, das wollte ich ihm/ihr zeigen.

Ob er es sich mit Streaming macht, ist mir dabei völlig egal.
Es ist nur ein Vorschlag.
Den kann er nehmen, oder im Regal liegen lassen.

Auch habe ich ZUERST genannt, wie man String besser einsetzt.

Es gibt sicherlich noch mehr Möglichkeiten, als die hier genannten, welche ebenso besser sind, weniger Ärger verursachen, als das ursprüngliche Vorgehen.


Da ist dir sicher was durcheinander geraten.

Was denn?

Sage es mir, bitte!

Was denn?
Sorry, hab die Kommentar-Zeichen übersehen.

Oh..
ok!

@combie

erstmal vielen dank für den Vorschlag mit dem Streaming. Wenn ich das jetzt richtig sehe brauche ich dort dann keinerlei variablen vordefinieren sondern kann einfach die Funktion einfügen also wird im Endeffekt der Rückgabe Wert eingetragen. Meine Frage hierzu wäre jetzt ist dies weniger RAM intensiv?

Weiterhin hast du gesagt ich könnte auch einen String Global definieren. Darf ich fragen was genau du damit meinst ?

Ich danke dir aber erstmal vielmals für deine Hinweise und ich werde mich jetzt mal mit dem Streaming beschäftigen

String buffer;

void setup() 
{
  buffer.reserve(200); // hier maximal Stringlänge einsetzen
  Serial.begin(9600);
}

void loop() 
{
  buffer = ""; // leeren
  buffer += "Umwelt-";
  buffer +=  bme280.getTemperature();
  buffer +=  "-";
  buffer +=  bme280.getHumidity();
  buffer +=  "-";  
  buffer +=  bme280.getPressure();
  Serial.println(buffer);
}

ah ok. Ich verstehe.

Rein Theoretisch müsste ich doch eigentlich, korrigiere mich wenn ich falsch liege den Buffer immer wieder nutzen können soll heißen für die anderen Strings fülle ich ihn einfach damit anstatt hier jetzt die werte des BME zu nutzten sehe ich das richtig?

den Buffer immer wieder nutzen

Genau das ist der Zweck der Übung.

Ich werde es direkt ausprobieren sobald ich aus dem Office wieder da bin. Ich danke dir schonmal für die Hilfe. Ich habe zumindest denke ich das beide varianten jetzt , wenn auch nicht in tiefe verstanden. Aber anhand deiner Beispiele kann ich jetzt weiter arbeiten und sollten noch Fragen kommen melde ich mich.

Ich markiere es als gelöst wenn nichts mehr anderes auftaucht.

Guten Abend zusammen,

ich habe jetzt die Vorschläge von hier aufgegriffen und meinen Sketch überarbeitet. Danke nochmals für die Hilfe und die Erklärungen.

Ich habe zumindest massig an Speicher eingespart :slight_smile:

Weiterhin habe ich etwas was ich immer wieder nutze in eine eigene Funktion ausgelagert was das ganze wie gesagt um etliches weniger Speicherlastig macht.

Anbei mein Sketch in der überarbeiteten Version.

Leider hängt er wieder an exakt der gleichen Stelle.

eine verwegene Idee die ich habe zu der ich mal gerne eure Meinung hören würde.

Kann es sein das millis und I2C nicht gut zusammen klar kommen?

Es hängt jedesmal beim Posten der werte der 1wire Sensoren.
Das aber nur wenn ich den BME mit drin habe.

#include <OneWire.h> 
#include <DallasTemperature.h>
#include <Seeed_BME280.h> // Implementieren der Seeed Bibliothek, ermöglicht die Kommunikation mit dem BME
#include <Wire.h>  // Implementieren der Wire Bibliothek, ermöglicht dem Arduino mit Geräten zu kommunizieren, welche das I²C Protokoll verwenden
 
BME280 bme280;     // Deklarieren der BME280 instanz

#define ONE_WIRE_BUS A0

OneWire oneWire(ONE_WIRE_BUS); // Deklarieren des 1Wire Bus
DallasTemperature sensors(&oneWire); 

int deviceCount = 0;
float tempC;
String buffer; // Deklarieren des Stringbuffers
 float feucht; // Deklarieren der Variablen für Feuchtigkeit
 float Pascal; // Deklarieren der Variablen für Luftdruck 
 float tempfl; // Deklarieren der Variablen für Temperatur des BME280


int ledPin = 13;  // LED connected to digital pin 13
int LinksFenster = 2;    // Fenster WZ Links
int LinksTuer = 3;       // Tür Terasse Links
int MitteFlLinks = 4;    // Tür Terasse Mitte Linker Flügel
int MitteFLRechts = 5;   // Tür Terasse Mitte Flügel Rechts
int Rechtstuer = 6;      // Tür Terasse Rechts
int RechtsFenster = 7;   // Fenster WZ Rechts
int HWRFenster = 8;      // Fenster Hauswirtschaftsraum
int Haustuer = 9;        // Haustür Kontakt
int Rauchmelder = 10;    // Rauchmelder Ausgelöst wenn 1
int Sammelstoerung = 11;  // Sammelstörung Rauchmelder Batterie usw...
int valLF = 0;           // variable für Fenster Links
int valLT = 0;           // variable für Tür Links
int valMTL = 0;          // variable für Mitte Tür Linker Flügel
int valMTR = 0;          // variable für Mitte Tür Rechter Flügel
int valRT = 0;           // variable für Rechte Tür
int valRF = 0;           // variable für Fenster Rechts
int valHWR = 0;          // variable für Fenster Hauswirtschaftsraum
int valHT = 0;           // variable für Haustür
int valSM = 0;           // variable für Sammelstörung
int valRM = 0;           // variable für Rauchmelder
boolean okToPrint1 = true; // 1 bis 10 sind Sendevariablen dies ermöglicht den String nur bei wertänderung zu senden 
boolean okToPrint2 = true;
boolean okToPrint3 = true;
boolean okToPrint4 = true;
boolean okToPrint5 = true;
boolean okToPrint6 = true;
boolean okToPrint7 = true;
boolean okToPrint8 = true;
boolean okToPrint9 = true;
boolean okToPrint10 = true;

float wert_sensor_1;  // 1 bis 6 Variablen für die 1Wire Sensoren
float wert_sensor_2;
float wert_sensor_3;
float wert_sensor_4;
float wert_sensor_5;
float wert_sensor_6;

DeviceAddress Sensor1 = { 0x28, 0x44, 0x48, 0xDB, 0x05, 0x00, 0x00, 0xC0 };  // Adressen der 1 Wire Sensoren 
DeviceAddress Sensor2 = { 0x28, 0x02, 0x3A, 0xDB, 0x05, 0x00, 0x00, 0xE9 }; 
DeviceAddress Sensor3 = { 0x28, 0x86, 0xC7, 0xDB, 0x05, 0x00, 0x00, 0x95 }; 
DeviceAddress Sensor4 = { 0x28, 0x21, 0xF1, 0xDA, 0x05, 0x00, 0x00, 0xDB }; 
DeviceAddress Sensor5 = { 0x28, 0x8F, 0x47, 0xDB, 0x05, 0x00, 0x00, 0xC8 }; 
DeviceAddress Sensor6 = { 0x28, 0xCF, 0x9B, 0xDB, 0x05, 0x00, 0x00, 0xC2 }; 

long vorhermillis = millis();
  
void setup() {
  
  pinMode(LinksFenster, INPUT_PULLUP); // Interne Pullups Aktivieren. Eingänge werden intern auf High gesetzt alle Signale werden gegen GND geschaltet
  pinMode(LinksTuer, INPUT_PULLUP);
  pinMode(MitteFlLinks, INPUT_PULLUP);
  pinMode(MitteFLRechts, INPUT_PULLUP);
  pinMode(Rechtstuer, INPUT_PULLUP);
  pinMode(RechtsFenster, INPUT_PULLUP);
  pinMode(HWRFenster, INPUT_PULLUP);
  pinMode(Haustuer, INPUT_PULLUP);
  pinMode(Rauchmelder, INPUT_PULLUP);
  pinMode(Sammelstoerung , INPUT_PULLUP);
  buffer.reserve(200); // hier maximal Stringlänge einsetzen
  Serial.begin(9600);                // Serielle Schnittstelle aktivieren und auf 9k6 Baud stellen
  sensors.begin();                   // 1 Wire initialisieren
 
}

void loop() {
  valLF = digitalRead(LinksFenster);   // Status der Input Pins in jedem durchlauf abfragen und den entsprechenden Variablen zuweisen
  valLT = digitalRead(LinksTuer);
  valMTL = digitalRead(MitteFlLinks);
  valMTR = digitalRead(MitteFLRechts);
  valRT = digitalRead(Rechtstuer);
  valRF = digitalRead(RechtsFenster);
  valHWR = digitalRead(HWRFenster); 
  valHT = digitalRead(Haustuer);
  valRM = digitalRead(Rauchmelder);
  valSM = digitalRead(Sammelstoerung);




  
  if (millis() - vorhermillis > 10000)  // Wenn Zeitwert größer dann .....
 {
   vorhermillis = millis();
  sensors.requestTemperatures();        // alle Sensoren im 1 Wire Bus um die Temperaturen bitten
   wert_sensor_1 = sensors.getTempC(Sensor1); // Sensoren 1 - 6 Temperatur den Variablen zuweisen
   wert_sensor_2 = sensors.getTempC(Sensor2);
   wert_sensor_3 = sensors.getTempC(Sensor3);
   wert_sensor_4 = sensors.getTempC(Sensor4);
   wert_sensor_5 = sensors.getTempC(Sensor5);
   wert_sensor_6 = sensors.getTempC(Sensor6);
  
   buffer = ""; // leeren
   buffer += "Innen:";
   buffer += wert_sensor_1;
   buffer += ":";
   buffer += wert_sensor_2;
   buffer += ":";
   buffer += wert_sensor_3;
   buffer += ":";
   buffer += wert_sensor_4;
   buffer += ":";
   buffer += wert_sensor_5;
   buffer += ":";
   buffer += wert_sensor_6;
   Serial.println(buffer);
   
   //Innen = "Innen:" + String(wert_sensor_1) + ":" + String(wert_sensor_2) + ":" + String(wert_sensor_3) + ":" + String(wert_sensor_4) + ":" + String(wert_sensor_5) + ":" + String(wert_sensor_6); // Sendestring aus Sensorwerten zusammenbauen und der Stringvari Innen zuweisen
   //Serial.println(Innen); // Seriell Zeilen Druck des Strings Innen

    sens(); // Aufrufen der BME280 abfrage
 } 
 
 
 // Ab hier Abfrage der Kontakte zusammenbau des Sendestrings und versenden bei Statusänderung eines Kontaktes Update ALLER!!! Kontakt Stati
  if(!valLF&&okToPrint1)
  {
    window();
    okToPrint1 = false;
  }
  if(valLF && !okToPrint1)
  {
    window();
    okToPrint1 = true;
  }

  
  if(!valLT&&okToPrint2)
  {
     window();
    okToPrint2 = false;
  }
  if(valLT && !okToPrint2)
  {

   window();
    
    okToPrint2 = true;
  }

  
  if(!valMTL&&okToPrint3)
  {
    window();
    okToPrint3 = false;
  }
  if(valMTL && !okToPrint3)
  {

     window();
    okToPrint3 = true;
  }

  
  if(!valMTR&&okToPrint4)
  {
    window();
    okToPrint4 = false;
  }
  if(valMTR && !okToPrint4)
  {

    window();
    okToPrint4 = true;
  }

  
  if(!valRT&&okToPrint5)
  {
     window();
    okToPrint5 = false;
  }
  if(valRT && !okToPrint5)
  {

    window();
    okToPrint5 = true;
  }

  
  if(!valRF&&okToPrint6)
  {
    window();
    okToPrint6 = false;
  }
  if(valRF && !okToPrint6)
  {

    window();
    
    okToPrint6 = true;
  }

  
  if(!valHWR&&okToPrint7)
  {
    window();
    okToPrint7 = false;
  }
  if(valHWR && !okToPrint7)
  {

    window();
    okToPrint7 = true;
  }
   if(!valHWR&&okToPrint8)
  {
    window();
    okToPrint8 = false;
  }
  if(valHT && !okToPrint8)
  {
    window();
    okToPrint8 = true;
  }
   if(!valHWR&&okToPrint9)
  {
     window();
    okToPrint9 = false;
  }
   if(valSM && !okToPrint9)
  {

   window();
    okToPrint9 = true;
  } 
   if(!valHWR&&okToPrint10)
  {
    window();
    okToPrint7 = false;
  }
   if(valRM && !okToPrint10)
  {
    window();
    okToPrint10 = true;
  }


}

void sens()  // Funktion für BME280
{
  buffer = ""; // leeren
  buffer += "Umwelt-";
  buffer +=  bme280.getTemperature();
  buffer +=  "-";
  buffer +=  bme280.getHumidity();
  buffer +=  "-"; 
  buffer +=  bme280.getPressure();
  Serial.println(buffer);

  
}

void window()
{
     buffer = ""; // leeren
     buffer += "Fenster,";
     buffer +=  valLF;
     buffer +=  ",";
     buffer +=  valLT;
     buffer +=  ","; 
     buffer +=  valMTL;
     buffer +=  ","; 
     buffer +=  valMTR;
     buffer +=  ","; 
     buffer +=  valRT;
     buffer +=  ","; 
     buffer +=  valRF;
     buffer +=  ","; 
     buffer +=  valHWR;
     buffer +=  ","; 
     buffer +=  valHT;
     buffer +=  ","; 
     buffer +=  valRM;
     buffer +=  ","; 
     buffer +=  valSM;
     Serial.println(buffer);  





}

Hi

millis() ist nur ein Rückgabewert, Der jede Millisekunde erhöht wird.
Das hat Nichts mit I²C zu tun.

Da Du scheinbar Speicherprobleme hast - Dir wurde schon geraten, die ganzen INT zu überdenken.
PINS sind const - Die werden sich im laufenden Sketch nicht mehr ändern - also const machen!
(dabei ist's sogar egal, ob's int oder, weil ausreichend, byte wäre) - ALLES, was der Kompiler fest 'verdrahten' kann, verdrahtet Der auch fest.
Da Du Ihm aber nicht sagst, daß z.B. der LED-Pin fest ist, wird Dieser IMMER aus dem Speicher ausgelesen - dauert länger, braucht Speicher, ist unnötig.

Variable für Fenster Links ... wird wohl 0 oder 1 sein, woll?
Ob man DAFÜR int braucht?
byte oder bool bräuchten die Hälfte an Platz.
Wenn man wirklich sparen will, kann man den Kram auch bitweise speichern - dann brauchen 8 Fenster 1 Byte, statt 8.

Ob man die DeviceAddress const machen kann (oder ob Das was bringt) ... kA - Versuch macht kluch ... (wobei ich die Sensoren suchen, eine fortlaufende Nummer in den User-Bytes speichern würde und Die dann daran zu erkennen suchte).

Deine pinMode-Orgie könnte man mit einem Array und einer FOR erschlagen - dürfte wieder Platz sparen.

Die ganzen Sensoren einlesen ginge ebenfalls per FOR

Dein Sensor-Request - hast Du DA den Hänger?
Dann wäre es möglich, daß das Request oder das anschließende Auslesen Dich ausbremst.
Selber stoße ich die Messung an und nach 750ms frage ich die (neuen) Werte ab (wenn ich in 12 Bit auslese, sonst schneller).
Müsste aber nachsehen, womit ich die Sensoren quäle.

okToPrint1 wird AUF JEDEN FALL umgedreht, also egal, welchen Status okToPrint? hat, window() wird aufgerufen und die Variable wird umgedreht ... mehrfachen Code kann man prima auslagern und zusammen fassen.
Edit
Ok - Da wird sich der 'letzte Zustand' gemerkt und bei Unterschied geprinten und umgedreht - an der Auslagerbarkeit ändert Das allerdings Nichts - Das ginge prima mit einer FOR, wenn die Werte aus einem Array kommen und als Abfrage würde ein != prima klappen - EINE Abfrage für beide gesuchten Möglichkeiten.
/Edit

Wenn wir damit fertig sind, kommen wir auf Minus-Platz ...

Was habe ich nicht verstanden? Was machen Deine dreiundzwölfzig okToPrint-Dinger?
Außer, daß der Code ins Unermessliche aufgebläht wird!

Auch habe ich nicht verstanden, WO der Hänger sein soll und WIE sich Dieser zeigt.

MfG