Tasten und U8g2-lib

Hallo liebes Forum,
bin frisch hier angekommen weil ich vor einem Problem stehe.

Vorgeschichte: habe mir einen Arduino Nano V3 bestellt und nachdem ich ihn hatte überlegt, was ich damit anstellen möchte. Ergebnis: Ich möchte einen Trigger für die Kamera bauen, welcher auf diverse externe Auslöseevents reagiert, aber auch einene Timer-Events besitzen soll.

Aktuell habe ich folgendes:

Zur Auslösung nutze ich aktuell den Pin 13 (welcher ja auch die LED ansteuert, richtig?) mit einer Funktion, die wie folgt aussieht:

Funktion zum Auslösen der Kamera:

void takePicture(int timingMS, int breakMS, int howOften, int pin){
  for   (int   i =0; i >=howOften ; i ++ ) {                         
    digitalWrite (pin , HIGH); 
    delay(timingMS);             
    digitalWrite(pin , LOW);  
    delay(breakMS);             
  } 
}

Zu meinem Problem:
Ich nutze die Display-Bibliothek U8G2, welche gleich ein nettes Menü bereitstellt. Leider auch bisher die einzige Bibliothek die mit dem Display funktioniert. Auch wenn auf der Händlerseite was anderes steht.
Meine einzelnen Funktionen realisiere ich jetzt nicht über die Menüfunktionen von U8G2, sondern über die normalen Ausgabe-Funktionen. Funktioniert so weit sehr gut, aber wenn ich jetzt zum Auslösen komme geht es in die Hose, bzw. sind aktuell vermutlich zwei Fehler drin. Die Auslösefunktion (eben schon gepostet) scheint nicht zu funktionieren, die LED bleibt nämlich immer dunkel, ich erhalte aber beim Compilieren keine Fehler.

Code für das Display, über welches die Auslösezeit eingestellt wird und dann auch ausgelöst wird:

    while (digitalRead(cancel) == HIGH) {
      do {
        delay(10);
      } while (digitalRead(select) == LOW);
      u8g2.clearBuffer();
      u8g2.setCursor(5, 25);
      u8g2.print("BULB");
      u8g2.setCursor(5, 45);
      u8g2.print(String(triggerTime) + " ms");
      u8g2.sendBuffer();
      if (digitalRead(left) == HIGH) triggerTime = triggerTime + 1000;
      if ((triggerTime > 1000) and (digitalRead(right) == HIGH)) triggerTime = triggerTime - 1000; 
      if (digitalRead(select) == HIGH) {
        do {
          delay(10);
        } while (digitalRead(select) == LOW);
        takePicture(triggerTime, 0, 1, shutterPin);
        u8g2.clearBuffer();
        u8g2.setCursor(5, 25);
        u8g2.print("*** SHUTTER ***");
        u8g2.sendBuffer();
        delay (triggerTime);
      }
    }

Die beiden "do while"-Schleifen hab ich drin, um die Zeitverzögerung abzufangen, bis der jeweilige Pin-Status hergestellt ist und es nicht einfach einen "Durchmarsch" gibt.
Wenn ich diese Schleifen raus lasse, reagiert er auf nichts mehr. Wenn ich sie drin habe, kann ich die Werte von triggerTime verändern, aber nach einmaliger Bestätigung bleibt er in einer Schleife. Theoretisch sollte das Ganze aber ohne die beiden "do while"-Schleifen funktionieren. Oder hab ich einen Denkfehler?

Die Verkabelung für die Schalter läuft auf Masse, sollte also theoretisch auf "INPUT_PULLUP" gestellt sein, weil diese Anschlussvariante ist für U8G2 so beschrieben.
Aktuell betätige ich die einzelnen "Taster" nur durch Kabel, die ich auf dem Steck-Board kurzschließe, da ich noch auf die bestellten Folientaster warte.

Hier nochmal die Konstanten und Variablen:

const int shutterPin = 13; // =LED
const int cancel = 4;
const int up = 9;
const int down = 7;
const int left = 8;
const int right = 6;
const int select = 5;

const char *string_main_title = "PT v0.05a"; // UP TO 22 SIGNS
const char *string_list_main = 
  "1) Bulb         \n"
  "2) HDR          \n"
  "3) Countdown    \n"
  "4) Zeitraffer   \n"
  "5) Blitz        \n"
  "6) Schall       \n"
  "7) Lichtschranke\n"
  "8) Info         ";

int triggerTime = 1000;

Hier nochmal das Setup:

void setup(void) {
  u8g2.begin(/*Select=*/ select, /*Right/Next=*/ right, /*Left/Prev=*/ left, /*Up=*/ up, /*Down=*/ down, /*Home/Cancel=*/ cancel); // Arduboy 10 (Production)
  u8g2.setFont(u8g2_font_6x12_tr);
  u8g2.enableUTF8Print();
  pinMode(shutterPin, OUTPUT);
}

Ich hänge nochmal den kompletten Code als Datei an.

Ich hoffe Ihr habt eine Idee oder seht, was ich falsch mache, bzw. wo ich einen Denkfehler habe.

PT v0.05a.txt (5.79 KB)

Warum hängst Du nicht den ganzen Sketch direkt in den Beitrag?

Gruß Tommy

Hi!

Ich habe nur etwa das erste Viertel Deines Postings gelesen. Beim ersten Code-Schnipsel ist mir aufgefallen, dass die for-Schleife nicht funktionieren kann, weil die Bedingung falsch formuliert ist. Statt ">=" sollte dort wohl "<=" stehen. So wie es jetzt aussieht, wird der Schleifenkörper nie betreten.

Da das syntaktisch korrekt ist, bekommst Du (zumindest hierzu) keine Fehlermeldung. Allerdings wird halt auch nie ausgelöst.

Fang am besten noch einmal mit einem minimalen Code an, mit dem nur ausgelöst und dann gar nichts mehr getan wird. Mach erst dann weiter, wenn das funktioniert. Speichere den neuen Sketch unter einem neuen Namen - dann bleibt der bisherige Code erhalten und Du kannst ihn als Vorlage nutzen.

HTH

Gregor

  1. Da der Pin 13 direkt eine LED angeschlossen hat ist er nicht 100% geeignet als Eingeng zu funktionieren. Nimm ein anderes Pin; Auch die analogen Pins können als digitale Pins (D14 bis D19) verwendet werden.
  2. Die while do Konstruktion ist blockierend. Mach das mit millis und einer finite state machine.

Grüße Uwe

@Tommy56, weil ich es aus vielen Foren so kenne, dass es unerwünscht ist.
@gregorss, danke erstmal, das bringt mich weiter ... werde komplett die Bereiche, welche ich erstellen möchte einzeln coden und hinterher in den bestehenden Code ein"pflegen", damit es zum großen ganzen wird.
@uwefed, Pin13 ist als Ausgabe verwendet, da ich aktuell noch keine Kamera dran hängen werde. Später lege ich das noch um, wenn ich die Platine für den Trigger erstelle.
Welche FSM würdest Du empfehlen und warum mit millis?

Ich brauche immer länger für Antworten, da ich auf einem Kreuzfahrtschiff arbeite und das mit dem Internet hier ein wenig schwieriger ist. Nicht wundern also, wenns mal wieder länger dauert. :slight_smile:

Danke EUch so weit,
LG Ralf aka synth1203

synth1203:
@Tommy56, weil ich es aus vielen Foren so kenne, dass es unerwünscht ist.

Wir legen Wert auf den kompletten Sketch, da die Erfahrung zeigt, dass in >> 90% der Fehler im "geheimen" Teil des Codes liegt.
Besonders wichtig sind dabei Variablendeklarationen.

Bei Libs, die nicht zum Standardumfang der IDE/der Prozessorfamilie gehören ist auch ein Link auf die Herkunft sinnvoll, da es oft mehrere Libs zum gleichen Thema / mit gleichem Namen aber völlig verschiedenen Inhalten gibt.

Gruß Tommy

synth1203:
... werde komplett die Bereiche, welche ich erstellen möchte einzeln coden und hinterher in den bestehenden Code ein"pflegen", damit es zum großen ganzen wird.

Mach das eher nicht. Das Zusammenstricken mehrerer Programme bzw. -teile ist manchmal ziemlich schwierig, weil es z. B. Überschneidungen oder gleiche Variablennamen gibt.

Versioniere Deine Arbeit besser. Dann kannst Du notfalls wieder zu einer funktionierenden Fassung zurückkehren. „Versionieren“ hört sich zwar nach Sesselpuperkram an, aber es hilft sehr.

Gruß

Gregor

Wenn man weiß, dass man es zusammen führen will, ist es doch am Einfachsten doppelte Variablennamen zu vermeiden.
Wenn man sprechende Variablennamen verwendet (was man sowieso tun sollte), sollte das sowieso kaum zu Überschneidungen führen.

Gruß Tommy

Tommy56:
Wenn man weiß, dass man es zusammen führen will, ist es doch am Einfachsten doppelte Variablennamen zu vermeiden.
Wenn man sprechende Variablennamen verwendet (was man sowieso tun sollte), sollte das sowieso kaum zu Überschneidungen führen.

Ja, doppelte Variablennamen zu vermeiden ist ziemlich einfach. Mit Überschneidungen meine ich eher Codeteile mit ähnlicher oder gleicher Funktionalität.

Meiner Erfahrung nach ist es das beste, funktionierende Codeteile bzw. Teil-Codes in Tabs „auszulagern“ und im „Hauptsketch“ nur noch entsprechende Funktionsaufrufe zu notieren. Das hält den Hauptsketch schön schlank und führt zu Code, der besser zu warten oder anzupassen ist.

Gruß

Gregor

Ja, so mache ich es auch. Die Tabs mäglichst so angelegt, dass man sie problemlos in neue Projekte übernehmen kann (ok, man könnte auch eine Lib draus machen).

Trotzdem halte ich es für sinnvoll, Tests von technischen Einzelheiten (Module, NTP, ...) erst mal allein auszutesten und nicht im Verbund der gesamten Applikation.

Gruß Tommy

Hallo Ihr Lieben,
letztenendes haben die einzelnen Funktionen nur geringe Unterschiede.
Grundsätzlich wird das Ganze noch ziemlich lange dauern, bis es fertig ist, einerseits weil ich nicht so häufig dazu komme, wie ich Lust habe und andererseits, weil ich auch nicht so einfach an dann später benötigte Hardware komme, wie zu Hause.
Alleine zum löten muss ich einen Termin bei einem Kollegen machen .......

Meine einzelnen Funktionsteile sollten theoretisch auch durch einfaches Zusammenfügen mit dem Menü funktionieren, diverse Variablen müssen sogar immer gleich sein und so viele Variablen werde ich letzenendes gar nicht haben. I.d.R. sind es nur Auslösezeit, Auslöseverzögerung, Bracketing-Anzahl, Verschubzeiten fürs Bracketing, welche ich aber wohl "in time" berechnen werde.
Die Auslöseverzögerung werde ich global aufs alle Funktionsteile wo sie notwendig sind laufen lassen.
Später kommen dann noch die Hardwarevariablen dazu, wenn ich auch die passenden Teile hier habe.

Werde mich jetzt die Tage erstmal in die State-Machine einlesen.
Gute N8, muss morgen früh raus.
LG Ralf aka synth1203

synth1203:
@Tommy56, weil ich es aus vielen Foren so kenne, dass es unerwünscht ist.
@gregorss, danke erstmal, das bringt mich weiter ... werde komplett die Bereiche, welche ich erstellen möchte einzeln coden und hinterher in den bestehenden Code ein"pflegen", damit es zum großen ganzen wird.
@uwefed, Pin13 ist als Ausgabe verwendet, da ich aktuell noch keine Kamera dran hängen werde. Später lege ich das noch um, wenn ich die Platine für den Trigger erstelle.
Welche FSM würdest Du empfehlen und warum mit millis?

Ich brauche immer länger für Antworten, da ich auf einem Kreuzfahrtschiff arbeite und das mit dem Internet hier ein wenig schwieriger ist. Nicht wundern also, wenns mal wieder länger dauert. :slight_smile:

Danke EUch so weit,
LG Ralf aka synth1203

Hier ist es erwünscht den gesamten Sketch zu posten da wie schon gesagt der fehler fast immer im ungeposteten Teil ist bzw erst durch Kenntnis des gesamten Sketches die Fehler sich eröffnen. ZB Du definierst am Anfang des Sketches ein Array mit 5 Elementen, Postest dannaber den Teil wo das Array mit 6 Elementen verwendet wird. Ein Eklatanter Fehler den man nicht finden kann wenn man die Variablendefinition nicht kennt.

Pin 13 als Ausgang ist kein Problem.

Weil man immer auf Tastatureingaben reagieren muß. Wenn Du mit Do While einen Eingang kontrollierst, kannst Du es nicht mit anderen machen.

Darf ich neugierig sein; Wo schipperst gerade herum?

Grüße Uwe

Tommy56:
Trotzdem halte ich es für sinnvoll, Tests von technischen Einzelheiten (Module, NTP, ...) erst mal allein auszutesten und nicht im Verbund der gesamten Applikation.

Wenn es um Dinge geht, die man separat testen/kennenlernen kann, ist es absolut sinnvoll, das in eigenen Sketchen zu tun. Als ich z. B. den TSSP4P38 (IR-Taster) kennenlernen wollte, habe ich das zunächst separat gemacht und das Ding erst anschließend mit anderen Teilen kombiniert. Wäre dabei etwas schiefgelaufen, hätte ich gewusst, dass ich es separat schon hinbekommen habe.

Gruß

Gregor

Hallo Ihr Lieben, bin die Tage leider zu nix gekommen, nur zur Vorbereitung meines mittlerweile erhaltenen Gehäuses. Ach ja und eine Folientastatur habe ich bestellt.

Muss schauen, wie ich die nächsten 2 Wochen zu irgendwas komme, da mein Team ein wenig dezimiert wurde. Heisst leider Mehrarbeit und Wenigerfreizeit.

@uwefed ... darfst Du... AIDAperla - Metropolenroute ab Hamburg.

Kann mir jemand eine gute Beschreibung/Erklärung zur State-Machine in Deutsch geben?

Würde es gerne zwischendurch lesen, aber da komm ich im Moment an englischsprachige Texte nicht ran ... bei denen schalt ich zur Zeit sofort nach den ersten zwei Sätzen ab. :frowning:

THNX, LG Ralf aka synth1203

synth1203:
Kann mir jemand eine gute Beschreibung/Erklärung zur State-Machine in Deutsch geben?

Guck hier. Beachte auch die Folgeseite.

Gruß

Gregor

So, ich hab mich mal über das Thema heute in der Pause her gemacht ...
ich versuch es mal abzureissen in kurz und würde Euch mal darum bitten zu sagen,
ob ich richtig liege, oder es falsch verstanden habe.

Ich habe folgendes:
3 Zustände = Funktionen des Triggers

1 BULB
2 Zeitraffer
3 HDR

Hier würde ich aber diese aussen vor lassen ...
... nächster Schritt wäre wenn eine dieser Funktionen ausgeführt wird,
dort habe ich dann

1 Dauerschleife (Warteposition) wie bei einem Beispiel mit der Fußgänger/Autoampel, die Autoampel bleibt die ganze Zeit grün, die Fußgängerampel rot.
2 Eingabe/Änderung zu ändernder Variabel: bei Betätigung von zwei möglichen Tastern (ggf. je nach Funktion)
3 Eingabe/Änderung von Variableninhalt: bei Betätigung von anderen zwei möglichen Tastern
4 Auslösung bei Betätigung von Auslösetaster
5 Abbruch der Schleife, somit Rückkehr zum Menü

Senn ich das Ganze jetzt wie folgt programmiere:

void loop()
menüabfrage
switch(menüpunkt)
 case menüpunkt1:
  while abbruch== false {
  Tastenabfrage
  switch(Tastenabfrage):
   case 2:
     Eingabe/Änderung von zu ändernder Variable
   break;
   case 3:
     Eingabe/Änderung von Variableninhalt (Zeit) (je nach Ergebnis von case2)
   break;
   case 4:
     Auslösung, zurück zur Tastenabfrage
   break;
   case 5:
     Abbruch, zurück zur Menüabfrage : abbruch = TRUE
   break;
  }
 break;
 case menüpunkt2:
   [...]
 break;
[...]

:confused:

Das ist die einzige Umsetzung, die für mich passen könnte ... glaube ich, richtig? Falsch?
Hier müsste ich dann ja wie schon beschrieben eine Schleife einbauen, die gemeinsam mit Case5 abbricht, oder?

Danke, LG Ralf aka synth1203

synth1203:
Kann mir jemand eine gute Beschreibung/Erklärung zur State-Machine in Deutsch geben?

Wenn Du hier im Forum nach "agmue anleitung" suchst, stößt Du auf von mir verfaßte Texte. Ob die für Dich "gut" sind, wird sich dann herausstellen. "Anleitung: Endlicher Automat mit millis()" enthält auch ein schönes Programm von Rudi.

synth1203:
... glaube ich, richtig? Falsch?

Die Richtung dürfte stimmen. Etwas irritiert mich while, das sollte nicht nötig sein und ist zusätzlich blockierend.

Der schon erwähnte Rudi hat sich in jedes Programm eine Herzschlag-LED eingebaut. Nur wenn die ohne merkliche Rhythmusstörungen blinkt, läuft das Programm gut, also ohne Blockaden. Ausnahmen bestätigen diese Regel.

synth1203:
Ich hänge nochmal den kompletten Code als Datei an.

Ich sehe da nur Menüpunkte bis "5) Blitz", siehst Du mehr?

PT.png

Bei Seeluft könnte Korrosion ein Thema werden, besonders bei den kleinen Spannungen. Aber da hast Du sicherlich Erfahrung.

PT.png

@agmue danke für den Link, werde es mir morgen aufm Tablet speichern und dann die Tage mal durch arbeiten.

Wenn Du bei Dir die Taste "nach oben" oder mehrfach die Taste "nach unten" betätigst dann siehst Du die restlichen Menüpunkte. :wink: Schön zu sehen, wie es auf einem funktionstüchtigen Display aussieht, meines hat leider einen Defekt und einen weißen Streifen am Rand.

While weil: das Menü von U8g2 übernimmt alles davor. Erst in den einzelnen Bereichen benutze ich die State-Machine, die normale Hauptprogrammschleife muss ich also hier ersetzen für die State-Machine.
Beim letzten Status = betätigen der Taste "cancel" wird die Do-While-Schleife direkt beendet, theoretisch sollte es also passen.

Ich hab das heute früh schon so weit mal umgesetzt, nur für den BULB-Modus, habe allerdings noch bei der Tasten-Abfrage irgendwo ein Problem. Sobald ich mit dem Notebook online komme poste ich den aktuellen/neuen Quelltext, kann aber noch dauern.

Seeluft macht im Schiff zum Glück relativ wenig aus ... plane aber das Gehäuse wenn wirklich alles passt auch abzudichten, so weit möglich.

LG Ralf aka synth

EDIT: Problem mit der Tasten-Abfrage ist behoben. Muss mich echt noch an die Groß-/kleinschreibung gewöhnen, komplett anders wie gewohnt.

Jetzt mach ich mich über millis her ... aktuell ist die Auslösung noch mit delay(x) gelöst ...
damit ich auch auf dem Display einen Countdown anzeigen kann, wie lange die Auslösung noch dauert, oder schon dauert.

EDIT2: So, ich hab erstmal angefangen ein paar Funktionen einzusetzen, damit es übersichtlicher wird und bin dabei auf ein Problem gestoßen ... sorry, nur Code-Schnipsel weil abgeschrieben ...
Es handelt sich um eine Ausgabe-Funktion für das Display, damit ich nicht immer die Positionierungen und Co. mit setzen muss.

void DisplayOutput(String line1, String line2){
  u8g2.clearBuffer();
  u8g2.setCursor(5,15);
  u8g2.print(line1);
  u8g2.setCursor(5,25);
  u8g2.print(line2);
  u8g2.sendBuffer();
}

Aufrufen tue ich jetzt wie folgt:

mode = "BULB";
ZeitInMS = 1000;
DisplayOutput(mode, String(ZeitInMS/1000) + " s");

Ergebnis: leerer Bildschirm

Wenn ich in der Funktion "DisplayOutput" direkt bei u8g2.print() das "line1" durch einen String ersetze funktioniert alles.

Ich kann doch Strings übergeben oder hab ich was verpasst?
THNX, LG Ralf aka synth1203

Lass Dir doch einfach mal in DisplayOutput die Werte auf den seriellen Monitor ausgeben.

Gruß Tommy

synth1203:
Wenn Du bei Dir die Taste "nach oben" oder mehrfach die Taste "nach unten" betätigst dann siehst Du die restlichen Menüpunkte. :wink:

Yep!

synth1203:
Seeluft macht im Schiff zum Glück relativ wenig aus ... plane aber das Gehäuse wenn wirklich alles passt auch abzudichten, so weit möglich.

An der Küste und auf den Inseln sehe ich halt viel V4A.

synth1203:
Ich kann doch Strings übergeben oder hab ich was verpasst?

Kannst Du und ein kleines Testprogramm zeigt es:

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// U8g2 Contructor List (Frame Buffer)
// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected
// U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R2, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// End of constructor list                U8G2_R2 = 180° gedreht

int ZeitInMS;
String mode;

void setup(void) {
  u8g2.begin();
  u8g2.enableUTF8Print();    // enable UTF8 support for the Arduino print() function
  u8g2.setFont(u8g2_font_6x12_tr);
}

void loop(void) {
  mode = "BULB";
  ZeitInMS = 1000;
  DisplayOutput(mode, String(ZeitInMS / 1000) + " s");
  delay(1000);
  mode = "Zeitraffer";
  ZeitInMS = 2000;
  DisplayOutput(mode, String(ZeitInMS / 1000) + " s");
  delay(1000);
}

void DisplayOutput(String line1, String line2) {
  u8g2.clearBuffer();
  u8g2.setCursor(5, 15);
  u8g2.print(line1);
  u8g2.setCursor(5, 25);
  u8g2.print(line2);
  u8g2.sendBuffer();
}

Übrigens auf dem UNO: Globale Variablen verwenden 74% des dynamischen Speichers.