ein Stück Code funktioniert nicht

#7412284
Lesenswert?

Hallo,

könnte mir vielleicht jemmand helfen, das nachfolgende kleine Programmschnipsel eines ESP32 / Arduinocode zu sanieren?

Die Aufgabe ist, daß von zwei DS18B20-Temperaturen die Unter-bzw. Übertemperaturen durch kleine schwarze Kreise signalisiert werden sollen.

Dazu habe ich vier if-Anweisungen geschrieben, die leider gar nicht so funktionieren, wie das gedacht war: wenn beide Temperaturen das Minimum (<18.0) unterschreiten, sind beide Kreise von temp_links aktiviert. Wenn die rechte Temperatur das Maximum (>23.0) überschreitet, sind beide Kreise vom temp_rechts aktiviert. Manchmal funktioniert es richtig, aber das ist die Ausnahme. Man könnte denken, daß vom vorangegangenen Durchlauf noch etwas hängen gebleiben sei, aber es wird ja alles gelöscht und neu geschrieben. Daran sollte es also nicht liegen. Ich lasse zur Kontrolle die temp-Werte seriell ausdrucken, sie sind alle richtig.

Irgend etwas an den If-Befehlen mache ich falsch, aber was?

Hier das Stück des Programm:

1
// temporär zur Kontrolle, ob die richtigen temp_Werte die Alarmierungssequenz erreichen
2
temp_links = sensors1.getTempCByIndex(0);    
3
Serial.print("temp_links     ");            
4
Serial.println(temp_links);
5
temp_rechts = sensors2.getTempCByIndex(0);  
6
Serial.print("temp_rechts    ");             
7
Serial.println(temp_rechts);                 
8

9
// Alarmierung (funktioniert nicht richtig)
10
if (temp_links < 18.0) {
11
  display.fillCircle(30, 40, 10, GxEPD_BLACK);}
12
if (temp_links > 23.0) {                     
13
  display.fillCircle(30, 98, 10, GxEPD_BLACK);}
14

15
if (temp_rechts < 18.0) {
16
  display.fillCircle(220, 40, 10, GxEPD_BLACK);}
17
if (temp_rechts > 23.0) {
18
  display.fillCircle(220, 98, 10, GxEPD_BLACK);}
19

20
  display.update();            // hiermit wird die neue Display-konfiguration auf das Display geschrieben
#7412297
Lesenswert?

Wo werden denn die einmal gezeichneten Kreise wieder abgelöscht?

Dass Konstrukt mit den 2 ifs würde ich auch durch ein else if ersetzen. Denn beides kann ja nicht sein.

Also evtl so?

1
if (temp_links < 18.0)
2
{
3
  display.fillCircle(30, 98, 10, GxEPD_WHITE);
4
  display.fillCircle(30, 40, 10, GxEPD_BLACK);
5
}
6
else if (temp_links > 23.0)
7
{ 
8
  display.fillCircle(30, 40, 10, GxEPD_WHITE);                    
9
  display.fillCircle(30, 98, 10, GxEPD_BLACK);
10
}

Edit: zu spät 😄

#7412309
Lesenswert?

Dann zeig deinen kompletten Code. Das ist der Grund wieso hier immer alle Salami schreien.

Egon M. schrieb:

nein, nicht gezielt gelöscht, der Displayinhalt wird mit display.update(); komplett neu geschrieben.

Das ist der Grund wieso wir auf löschen oder überschreiben hingewiesen haben. In vielen Libraries wird mit Update nur erneut der Puffer auf das Display geschrieben. Du musst aber den Kreis den du nicht möchtest zuerst aus dem Puffer entfernen bevor er geschrieben wird. Der Puffer kann je nach Hardware im uC (Librarie) oder im Display selbst sein...

#7412324
Lesenswert?

N. M. schrieb:

Wo werden denn die einmal gezeichneten Kreise wieder abgelöscht?

ich werde Deinen Vorschlag probieren , aber ich glaube, das mit GxEPD_WHITE hilft nicht weiter. Weshalb? Weil die schwarzen Kreise automatisch verschwinden, wenn sich ein anderer Temperaturzustand einstellt.

Z.B. temp_links unter 18.0 mit den beiden Kreisen, wo einer nicht hingehört (Abb1),

dann verschwindet bei Erhöhung temp_links über 23.0 einer der beiden rückstandslos und an anderer Stelle erscheint ein anderer (diesmal eine richtige Version) (Abb2).

Und Abb3 dürfte es auch nicht geben

Angehängte Dateien:
#7412327
Lesenswert?

N. M. schrieb:

Dann zeig deinen kompletten Code. Das ist der Grund wieso hier immer alle Salami schreien.

Ich habe mir extra Mühe gegeben, nur den fraglichen Kram zu übermitteln, damit man es sich nicht mühsam aus dem größeren Programm heraussuchen muß.

Aber geheim ist der allerweltcode durchaus nicht:

1
 //  EPD-kpl-01-230507
2
// kompilierbar, Serial.print funktioniert, Lilygo auch
3
// erster Versuch mit lilygo213
4
// GxEPD_Hello World Example by Jean-Marc Zingg
5
// unnötiges Kram muß noch entfernt werden! 
6
// Created by Jean-Marc Zingg based on demo code from Good Display,
7
// available on http://www.e-paper-display.com/download_list//downloadcategoryid=34&isMode=false.html
8

9
// include library, include base class, make path known
10

11
// DS18B20-Zubehörs.................................................
12
#include <OneWire.h>
13
#include <DallasTemperature.h>
14

15
#define ONE_WIRE_BUS_1 13
16
#define ONE_WIRE_BUS_2 15
17

18
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
19
OneWire oneWire1(ONE_WIRE_BUS_1);
20
OneWire oneWire2(ONE_WIRE_BUS_2);
21

22
// Pass our oneWire reference to Dallas Temperature.
23
DallasTemperature sensors1(&oneWire1);
24
DallasTemperature sensors2(&oneWire2);
25
// Ende des DS18B20-Zubehörs........................................
26

27
// EPD-Zubehör:-----------------------------------------------------
28
#include <GxEPD.h>
29
#include <GxDEPG0213BN/GxDEPG0213BN.h>    // 2.13" b/w 128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
30
#include GxEPD_BitmapExamples
31

32
// FreeFonts from Adafruit_GFX
33
#include <Fonts/FreeMonoBold9pt7b.h>
34
#include <Fonts/FreeMonoBold12pt7b.h>
35
#include <Fonts/FreeMonoBold18pt7b.h>
36
#include <Fonts/FreeMonoBold24pt7b.h>
37

38
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
39
#include <GxIO/GxIO.h>
40

41

42
#if defined(ESP32)
43
GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
44
GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4
45

46
#elif defined(ARDUINO_AVR_MEGA2560)
47
GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
48
//GxIO_Class io(SPI, /*CS=*/ 10, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9, CS on 10 (for CS same as on UNO, for SPI on ICSP use)
49
GxEPD_Class display(io, /*RST=*/ 9, /*BUSY=*/ 7); // default selection of (9), 7
50
#else
51
GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
52
GxEPD_Class display(io, /*RST=*/ 9, /*BUSY=*/ 7); // default selection of (9), 7
53
#endif
54
// Ende des EPD-Zubehörs----------------------------------------------
55

56
float temp_links, temp_rechts;
57

58
void setup() {
59

60
// für DS18B20:
61
   delay(3000);
62
   Serial.begin(115200);
63
   Serial.println("2-DS18B20-230506");
64
  sensors1.begin();
65
  sensors2.begin(); 
66

67
// für EPD  
68
   display.init(115200); // enable diagnostic output on Serial
69
//  display.powerDown();       //  ist das nötig?
70
}
71

72
void loop() {
73

74
// für DS16B20:  request to all devices on the bus
75
sensors1.requestTemperatures(); // Send the command to get temperatures
76
sensors2.requestTemperatures();
77
// We use the function ByIndex, and as an example get the temperature from the first sensor only.
78
Serial.print("Temperatur am Sensor 1 (Pin 13 - links ) ist: ");
79
Serial.println(sensors1.getTempCByIndex(0));
80
Serial.print("Temperatur am Sensor 2 (Pin 15 - rechts) ist: ");
81
Serial.println(sensors2.getTempCByIndex(0));
82

83
// für EPD:
84
  Ausgabe();
85
  delay(15000);
86
// esp_deep_sleep(120000);                   // Zeitangabe stimmt nicht 
87
};
88

89

90
//...................................................
91
void Ausgabe(){
92
char text1[10];
93
dtostrf(temp_links , 5, 1, text1);  
94
char text2[10];
95
dtostrf(temp_rechts, 5, 1, text2);  
96
  
97
display.setRotation(1);
98
// select a suitable font in Adafruit_GFX
99
display.setFont(&FreeMonoBold24pt7b);
100
display.setTextColor(GxEPD_BLACK);
101
int16_t tbx, tby; uint16_t tbw, tbh; // boundary box window
102
display.getTextBounds(text1, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for origin 0, 0, fortunately (negative tby!)
103
display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white)
104
 
105
display.drawRect(4, 6,  242, 120,  GxEPD_BLACK);    // Rechteck am Rand
106
display.setCursor(45, 50);
107
display.print(text1);
108
display.setCursor(45, 110);
109
display.print(text2);  
110

111
// temporär zur Kontrolle, ob die richtigen temp_Werte die Alarmierungssequenz erreichen
112
temp_links = sensors1.getTempCByIndex(0);    
113
Serial.print("temp_links     ");            
114
Serial.println(temp_links);
115
temp_rechts = sensors2.getTempCByIndex(0);  
116
Serial.print("temp_rechts    ");             
117
Serial.println(temp_rechts);                 
118

119
// Alarmierung (funktioniert nicht richtig)
120
if (temp_links < 18.0) {
121
  display.fillCircle(30, 40, 10, GxEPD_BLACK);}
122
if (temp_links > 23.0) {                     
123
  display.fillCircle(30, 98, 10, GxEPD_BLACK);}
124

125
if (temp_rechts < 18.0) {
126
  display.fillCircle(220, 40, 10, GxEPD_BLACK);}
127
if (temp_rechts > 23.0) {
128
  display.fillCircle(220, 98, 10, GxEPD_BLACK);}
129

130
  display.update();            // hiermit wird die neue Display-konfiguration auf das Display geschrieben
131
}

Bitte sieh Dir die Bilder aus meinem vorletzten Post an. Wie mir scheint, ist es nicht eine Frage. ob alte Kreise gelöscht oder überschrieben werden. Es erscheinen vielmehr Kreise, wo sie gar nicht hingehören und irgendwie sind sie in der Lage, wieder zu verschwinden. Ich vermute, mit den if-Befehlen habe ich etwas falsch gemacht.

VG

#7412336
Lesenswert?

Ich denke, dass x und y bei den fillCircles falsch sind. Die beiden Kreise der temp_links-Vergleiche sind nicht die beiden oberen Kreise, sondern die beiden linken, ...

Korrekt:

1
if (temp_links < 18.0)
2
  display.fillCircle(30, 40, 10, GxEPD_BLACK);
3
if (temp_links > 23.0)
4
  display.fillCircle(220, 40, 10, GxEPD_BLACK);
5

6
if (temp_rechts < 18.0)
7
  display.fillCircle(30, 98, 10, GxEPD_BLACK);
8
if (temp_rechts > 23.0)
9
  display.fillCircle(220, 98, 10, GxEPD_BLACK);
#7412359
Lesenswert?

Egon M. schrieb:

Aber geheim ist der allerweltcode durchaus nicht: ...

So schwer kann das doch nicht sein. Was meinst du, was mit dem Hinweis:

1
"Wichtige Regeln - erst lesen, dann posten!
2
...
3
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang"

gemeint sein könnte?

Egon M. schrieb:

Wie mir scheint, ist es nicht eine Frage. ob alte Kreise gelöscht oder überschrieben werden.

Die Kreise löscht du mit dem Funktionsaufruf in deiner Zeile 103

1
display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white)

und das ist ganz entscheidend, um das Verhalten deines Programms zu verstehen, wie du ja auch an den Rückfragen gemerkt haben dürftest.

Wie Foobar schon richtig angemerkt hat, werden die gezeichneten Kreise so angezeigt, wie in deinem Programm kodiert:

1
+--------------------+
2
¦ L<18   TempL  R<18 ¦
3
¦                    ¦
4
¦ L>23   TempR  R>23 ¦
5
+--------------------+

Ein Tipp zu den Photos: Wenn deine Kamera auf den kurzen Abstand nicht fokussieren kann, gehe weiter weg vom Objekt und schneide hinterher aus. Bei einem schärferen Bild würde man auch den dünnen Rand vom Funktionsaufruf in deiner Zeile 105 erkennen können und müsste nicht raten.

#7412385
Lesenswert?

p.s. Um solche Fehler zu vermeide, hilft klarerer Quelltext.

Definiere die Koordinaten für die Kreise besser als Konstanten (z.B. KREISX_LOW, KREISX_HIGH, POSY_L, POSY_R) und streue sie nicht als "magic numbers" in den Quelltext ein. Die Cursorkoordinaten für die Textausgabe können sich dann auch auf diese Konstanten beziehen, z.B. für den linken Sensor in der Art "display.setCursor(TEXTX, POSY_L+TEXTY_OFFSET);".

Dann wird es auch einfach, später irgendetwas auf dem Display zu verschieben, ohne sich die Beziehung zwischen den Zahlen wieder klar machen zu müssen und irgendetwas zu vergessen. In deinem jetzigen Code ist z.B. die Zeilenausrichtung von Punkten und Text für die obere Zeile anders als für die untere (2 Pixel Unterschied).

Die Variablen mit dem anzuzeigenden Text passend dazu zu benennen, wäre auch klarer, also z.B. textL/textR an Stelle von text1/text2.

Beitrag #7412477 wurde von einem Moderator gelöscht.
#7412487
Lesenswert?

Bei der Ausgabe werden

  • erst temp_links und temp_rechts in Strings umgewandelt
  • dann auf dem Display ausgegeben
  • dann werden neue Messwerte in temp_links und temp_rechts eingelesen
  • aufgrund der neuen Messwerte werden die Kreise gezeichnet

Da in der loop ein delay von 15 Sekunden ist, weichen diese Werte stark voneinander ab. Soll das so sein?

#7412532
Lesenswert?

man muss doch sicher auch nicht alle 15 Sekunden einen neuen Font initialisieren und das Display neu drehen? Das würde ich einmal im Setup machen. Dann würde man auch sehen, dass die Kreise eben nicht auf magische Weise verschwinden. geil ist natürlich andererseits, dass man einfach so, ohne nachzudenken dtostrf() verwenden kann, keine Kommas schieben muss oder andere Verrenkungen machen muss und auch die Texte der seriellen Ausgaben einfach so in den RAM packen kann. ich schreib da immer ein (F("TEXT")) hin. Hier ist ja genug RAM vorhanden.

#7412619
Lesenswert?

Axel R. schrieb:

man muss doch sicher auch nicht alle 15 Sekunden einen neuen Font initialisieren und das Display neu drehen?

Nein, ich werde auf 1-5 min gehen, weil die Temperaturen quasi konstant sind (Aqurienwasser). Allerdings muß ich mir das mit dem deep sleep noch genauer ansehen, bisher hat der ESP32 nicht darauf reagiert.

Die 15 sec habe in der Testphase eingestellt, damit ich nicht so lange warten muß.

Und bei dem Übertragen ins setup stimme ich Dir zu, das werde ich ändern.

VG

knut735

#7412632
Lesenswert?

Εrnst B. schrieb:

Warum packst du jeden DS18B20 an seinen eigenen OneWire Bus?

Das habe ich gemacht, weil ich es nicht besser wußte und auch noch keine Beschreibung der neueren Busversion (gesucht und) gefunden habe.

Ich bin es noch gewohnt von PT100, DS18B20 usw., da hatte man jeweils einen PIN und mußte dann reihum abfragen.

Ist ja heutzutage wunderbar einfach geworden mit den libraries für alles und jedes. Allerdings gibt es nicht immer ein Manual.

#7412644
Lesenswert?

Hallo mani

da Du nun den ganzen Code gesehen hast, hätte ich eine Frage zu einem Problem am Rande. Vielleicht fällt Dir etwas ein:

Die Anzeige geht nach. Wenn sich die Temperatur entspr. ändert, erscheint schon der Kreis und noch die alte Temperatur. Erst beim nächsten Durchlauf zeigt siich die neue Temperatur und der Kreis.

Und wenn ich neu starte, wird zunächst 0 angezeict, obwohl im Code doch zuerst die DS18B20 abgefragt und danach display.print(text1); folgt. Sollte doch nicht 0 sein.

Das Nachgehen stört im laufenden Betrieb eigentlich nicht, aber es ist unschön.

VG knut735

#7412658
Lesenswert?

Egon M. schrieb:

Die Anzeige geht nach. Wenn sich die Temperatur entspr. ändert, erscheint schon der Kreis und noch die alte Temperatur. Erst beim nächsten Durchlauf zeigt siich die neue Temperatur und der Kreis.

Das war doch der Einwand, dass in deinem Code temp_links und temp_rechts erst nach der Textausgabe auf dem Display mit Messdaten gefüttert werden, dh. immer alte (oder eben noch keine) gültigen Daten angezeigt werden.

Bernhard M. schrieb:

Bei der Ausgabe werden

  • erst temp_links und temp_rechts in Strings umgewandelt
  • dann auf dem Display ausgegeben
  • dann werden neue Messwerte in temp_links und temp_rechts eingelesen
  • aufgrund der neuen Messwerte werden die Kreise gezeichnet
#7412674
Lesenswert?

Egon M. schrieb:

Und wenn ich neu starte, wird zunächst 0 angezeict, obwohl im Code doch zuerst die DS18B20 abgefragt und danach display.print(text1); folgt. Sollte doch nicht 0 sein.

Die DS18B20 sind sehr langsam. Deshalb kann man die Temperatur-Messung zweiteilen. Zuerst Messung anstoßen, dann hat der µC lange Zeit, was anderes zu tun oder zu schlafen, und dann, nach ~750ms, kann man den Messwert abholen.

Dein Code wartet zwischen dem sensors1.requestTemperatures(); und sensors1.getTempCByIndex(0);

evtl. nicht lange genug.

Müsste man in der Bibliothek(s-Dokumentation) nachsehen, auf den ersten Blick könnte ein extra delay, eine Schleife

1
while (!(sensors1.isConversionComplete() && sensors2.isConversionComplete()) yield();

oder ein sensorsX.setWaitForConversion(true); im setup

helfen.

Edit: Ah, Ich war bei der Seriellen Ausgabe, nicht bei dem Grafik-Code. & das setWaitForConversion(true) ist eh default.

#7412789
Lesenswert?

Jens G. schrieb:

Ja, warum wohl - weil Du zuerst die Temp. ausgibst, dann erst die Temp. ermittelst, dann den Kreis zeichnest.

Ja, da beschreibst Du das Dilemma genau: der Kreis sollte zuletzt gezeichnet werden und er erscheint in Wirklichkeit zuerst und die Temperatur wird später ausgegeben, obwohl sie doch zuerst ermittelt wurde.

Nun gut, wenn die DS18B20_Abfrage zu lange dauert - woher weiß dann der Kreis so schnell, daß er erscheinen soll?

VG

#7412800
Lesenswert?

Egon M. schrieb:

Jens G. schrieb:

Ja, warum wohl - weil Du zuerst die Temp. ausgibst, dann erst die Temp. ermittelst, dann den Kreis zeichnest.

Ja, da beschreibst Du das Dilemma genau: der Kreis sollte zuletzt gezeichnet werden und er erscheint in Wirklichkeit zuerst und die Temperatur wird später ausgegeben, obwohl sie doch zuerst ermittelt wurde.

Nun gut, wenn die DS18B20_Abfrage zu lange dauert - woher weiß dann der Kreis so schnell, daß er erscheinen soll?

VG

Du scheinst irgendwie nichts begriffen zu haben ...

Gast #7412817
Lesenswert?

Egon M. schrieb:

temp_links = sensors1.getTempCByIndex(0); temp_rechts = sensors2.getTempCByIndex(0);

Du musst diese beiden Zeilen nach oben an den Beginn der Funktion Ausgabe() verschieben, noch vor

dtostrf(temp_links , 5, 1, text1);
dtostrf(temp_rechts, 5, 1, text2);

Ansonsten erzeugst du die Textausgabe nicht von der aktuellen Temperatur (links/rechts) sondern von der vorherigen Messung die vor 15 Sekunden stattfand.

Noch etwas:

float temp_links, temp_rechts;

Da du diese beiden Variablen nur innerhalb der Funktion Ausgabe() verwendest, gehören diese Zeilen in die Funktion verschoben. Wenn du das machst, wird dein obiger Fehler vielleicht auch offensichtlicher.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren