Output Pins funktionieren bei ein und dem selben Befehl und dann wieder nicht.

Hej zusammen;),

ich versuche sehr erfolglos folgendes Poblem zu verstehen.

Der Sketch soll, je nach dem welcher Taster gedrückt wird, vier LED blinken lassen. In einem WS2812 Ring (SwBu_Indicator) soll ein Pixel anzeigen ob der "Warning_BT" gedrückt ist (rotes blinken) oder in konstanter Farbe leuchten ("Warning_BT" nicht gedrückt). Ein zweiter WS2812 Ring (MultiDisplay) soll entweder drei Pixel links oder rechts im Ryhtmus blinken (Abhänging von den Tastern "Left_BT" oder "Right_BT") oder alle sechs Pixel, wenn "Warning_BT" gedrückt wurde.

Folgendes passiert nun:

Drücke ich "Warning_BT" liefert der Sketch das was ich mir erwarte. Drücke ich "Left_BT" oder "Right_BT" passiert bei den LED und bei den "Multidisplay" Ws2812 Ring nichts.

Woran kann es liegen? Was mache ich flasch?

Technisches zum Aufbau:
Die Taster sind über eine Schmitt Trigger (Texas Instruments sn74hc14) Schaltung entprellt. Die Stromversorgung besteht aus zwei Polulo D36V6F5 DCDCwandler. Ein Wandler versorgt den Arduino Mega 2560 Pro Mini, Schalter/Taster, Schmitt Trigger Schaltung und die 5mm LED´s. Der andere Wandler versorgt die Neopixel. Jeder Neopixel Strang besitzt einen Elko mit 1000µF in der SPannungsversorgung. Derzeit betreibe ich den Aufbau mit 5mm LED. Im fertigen Zustand möchte ich mit den Ausgangspins die PWM Pins von Konstantstromquellen steuern.

LG
Hubert

Sketch.txt (15.3 KB)

Die Taster sind über eine Schmitt Trigger (Texas Instruments sn74hc14) Schaltung entprellt

Ein Schmitt-Trigger erzeugt eine Hysterese beim Schalten, aber entprellt allein keinen Taster. Höchstens in Kombination mit einem RC-Tiefpass, der aus dem Prellen einen langsamen Anstieg macht.

@michael_x

Danke für deine Antwort. Ich hätte statt Schmitt Trigger Schaltung besser schreiben sollen " Schmitt Trigger Tiefpassfilter". Dann wäre diese Missverständniss schon mal nicht passiert. :wink: ich gelobe Besserung :D!

LG

Ablenken hilft nicht immer :slight_smile:

Liegt dein Problem nun an den Tastern oder an der Neopixel-Ansteuerung?

Ich schaue mir wenn überhaupt (heute nicht mehr) lieber kleine Probleme an als große Sketche.

michael_x:
Liegt dein Problem nun an den Tastern oder an der Neopixel-Ansteuerung?

Mein Problem liegt bei den Outputs und bei den Neopixel welche am WS2812 Ring "MultiDisplay" (im Sketch auch so benannt) physisch vorhanden sind. Diese funktionieren wie erwartet wenn im Sketch das abläuft, was ich mit drücken des Taster "Warning_BT" erreichen wollte.
Die Sketchbereiche welche mit den Tastern "Left_BT" und "Right_BT" ausgelöst werden sollten funktionieren nicht so wie von mir gewollt. Die Outputs und die Pixel am WS2812 Ring "MultiDisplay" bleiben dauerhaft dunkel.

Laut einem Serial.print werden die beiden Taster aber vom Arduino mit LOW oder HIGH erkannt.

Der problematische Sketch ist, nach meinem Verständniss, nicht groß :o . Ich habe nur den nicht funktionierenden Code aus dem gesamten Sketch herausgelöst, aber alles vor LOOP so belassen was der Gesamtsketch benötigt. Deshalb ist der Sketch zu groß für die Ansicht im Forum.

m419:
Drücke ich "Warning_BT" liefert der Sketch das was ich mir erwarte. Drücke ich "Left_BT" oder "Right_BT" passiert bei den LED und bei den "Multidisplay" Ws2812 Ring nichts.

Woran kann es liegen? Was mache ich flasch?

Klassiker :slight_smile:
Ich habs mal runtergebrochen und kommentiert.

void loop()
{
  if (digitalRead(Left_BT) == 1)  // Wenn die Taste ausgelöst
  {
    IND_SwitchCase_Val = 1; // Merke Dir eine 1
  }
  else
  {
    IND_SwitchCase_Val = 0;  // Wenn die Taste nicht ausgelöst, überschreibe mit 0
  }
  if (digitalRead(Right_BT) == 1)   // Wenn die Taste ausgelöst
  {
    IND_SwitchCase_Val = 2; // Merke Dir eine 2
  }
  else
  {
    IND_SwitchCase_Val = 0; // Wenn die Taste nicht ausgelöst, überschreibe mit 0
  }
  if (WarningCase_Val == 1)  // Wenn gesetzt
  {
    IND_SwitchCase_Val = 3; // merke Dir eine 3
  }
  else
  {
    IND_SwitchCase_Val = 0; Wenn die Taste nicht ausgelöst, überschreibe mit 0
  }

  Update_Indicator();
}//Endbrace loop

void Update_Indicator()
{
  switch (IND_SwitchCase_Val)
  {
    case 0:
      break;
    case 1:
      break;
    case 2:
      break;
    case 3:
      break;
  }
}//Endbrace Update_Indicator

Eigentlich sollte Dir jetzt aufgefallen sein, was passiert.

Noch ein Hinweis: Auch wenn Du nicht aktiv IND_SwitchCase_Val höher als 3 setzt, so schreib in das switch/case Konstrukt als letztes ein

default:
break;

rein. Wenn da aus irgendwelchen Gründen nicht 0-3 drin steht, kommst Du da nicht wieder raus.

(deleted)

Moin,

Spielverderber :wink: Er sollte ja selbst drauf kommen...

Aber:

Peter-CAD-HST:
Die Variable IND_SwitchCase_Val bleibt immer NULL

Nene. Die ist 0. NULL ist was anderes.

(deleted)

Danke euch beiden für eure Hilfe, aber ich fürchte ich verstehe es immer noch nicht. :cry:

@my_xy_projekt:

leider fällt mir nicht auf was das Problem ist.

@Peter-CAD-HST

Auf welchen Wert sollte die Variable "IND_SwitchCase_Val" zurück gesetzt werden?

Edit:

Oder meint ihr mit euren Hinweisen, dass ich für IND_SwitchCase_Val 1 bis 2 einen eigenen OFF-Zustand definieren muss?

Noch ein Hinweis: Auch wenn Du nicht aktiv IND_SwitchCase_Val höher als 3 setzt, so schreib in das switch/case Konstrukt als letztes ein

default:

break;



rein. Wenn da aus irgendwelchen Gründen nicht 0-3 drin steht, kommst Du da nicht wieder raus.

Was soll das bringen?
Wo und wie soll man da raus kommen?

m419:
Danke euch beiden für eure Hilfe, aber ich fürchte ich verstehe es immer noch nicht. :cry:
leider fällt mir nicht auf was das Problem ist.

Na dann helf ich mal nach und hoffe das erklären zu können:

Dein Sketch macht Folgendes: (NACHEINANDER)
Wenn Bedinung:
if (digitalRead(Left_BT) == 1)
erfüllt:
IND_SwitchCase_Val = 1;
nicht erfüllt:
IND_SwitchCase_Val = 0;

Wenn Bedingung
if (digitalRead(Right_BT) == 1)
erfüllt:
IND_SwitchCase_Val = 2;
nicht erfüllt:
IND_SwitchCase_Val = 0;

Wenn Bedingung
if (WarningCase_Val == 1)
erfüllt:
IND_SwitchCase_Val = 3;
nicht erfüllt:
IND_SwitchCase_Val = 0;

Wenn Du jetzt von oben nach unten durchgehst, passiert was?
Die Bedingung Left_BT ist erfüllt - das bekommst Du auch bei Dir im seriellen Monitor angezeigt - IND_SwitchCase_Val setzt Du auf 1
ABER!!!
Die Bedingung Right_BT ist nicht erfüllt. - auch das bekommst im SerMon angezeigt. Was Du vernachlässigst ist die Reaktion darauf: IND_SwitchCase_Val = 0;

Warum funktioniert
if (WarningCase_Val == 1)
immer?

Es gibt danach keinen Code, der IND_SwitchCase_Val wieder auf 0 setzt.

Also nochmal in Kurzfassung:
Während Du in der ersten Bedingung noch den Status setzt, löscht Du diesen wieder in der nächsten Bedingung.
Gleiches gilt für Bedingung 2 kohärent .
Nur bei Bedingung 3 == TRUE kommst Du nicht in Schwierigkeiten, weil kein nachfolgendes ändern von IND_SwitchCase_Val erfolgt.

Du musst also versuchen, das nach dem ändern des Status DIESER auch übergeben wird.

Das geht u.a. auch so: (ungetestet aber Logik zeigend)

void loop()
{
 if (digitalRead(Left_BT) == 1)  // Wenn die Taste ausgelöst
  {
    IND_SwitchCase_Val = 1; // Merke Dir eine 1
Update_Indicator();
  }
  else
  {
    IND_SwitchCase_Val = 0;  // Wenn die Taste nicht ausgelöst, überschreibe mit 0
  }
  if (digitalRead(Right_BT) == 1)   // Wenn die Taste ausgelöst
  {
    IND_SwitchCase_Val = 2; // Merke Dir eine 2
Update_Indicator();
  }
  else
  {
    IND_SwitchCase_Val = 0; // Wenn die Taste nicht ausgelöst, überschreibe mit 0
  }

ABER ACHTUNG!
Das geht nur, solange Taste gedrückt ist. Mit Deinem ELSE Zweig sorgst Du dafür, das
IND_SwitchCase_Val = 0;
IMMER erfüllt sein wird....

combie:
Was soll das bringen?
Wo und wie soll man da raus kommen?

IND_SwitchCase_Val = 4;

my_xy_projekt:
IND_SwitchCase_Val = 4;

Das ist keine Antwort.

Also die Frage noch mal klarer:

default: break;
Was soll dieser "Fall" bringen?

Bringt in diesem Fall so wohl eher nix.

Aber im Grundsatz bin ich da bei my_xy_projekt:
Es hat sich als gute Praxis erwiesen, falls irgendwann in sieben Wochen mal einer mit einer 4 oder 17 ankommt.
Dann allerdings wäre eine Fehlermeldung der Art "unbehandelter Fall, bitte nachbessern!" im default-Zweig hilfreich.

default:
  Serial.print(F("unbehandelter Fall: "));
  Serial.println(IND_SwitchCase_Val);
  break;

Es gibt in manchen Firmen Richtlinien, die sowas vorschreiben (als abhängig Beschäftigter kommentiere ich das nicht weiter...). Über Misra-C, Lint, Coverity und Konsorten müssen wir ja nicht philosphieren.

Naja....
Über irgendwelche Richtlinien, will ich ja gar nicht diskutieren.

Wenn da aus irgendwelchen Gründen nicht 0-3 drin steht, kommst Du da nicht wieder raus.

Was das heißen soll?

Woraus kommen?
Und wie soll ein leerer Fall dabei helfen?


Aber was solls, ich gebe auf, und werde es wohl nie erfahren....

Hallo,

ich würde die Pin Orgie aufräumen und alle Pins getrennt in Input/Output Arrays werfen und mittels Index drübergehen.
Dabei kann man bei erkannten Tasterdruck eine Indexnummer einem Zwischenspeicher zuweisen.
Mittels nachfolgendem switch case kann man an Hand der Indexnummer eine Aktion ausführen lassen. Hier wäre ein leeres default im switch case sinnvoll um eventuelle Fehler im nichts tun abzufangen.
Ich empfehle dem TO sich mit Strukturen und Arrays zu befassen. Sonst endet das im Kaos und jeder Fehler ist mit jeder neuen Codezeile schwerer findbar.

Hier wäre ein leeres default im switch case sinnvoll um eventuelle Fehler im nichts tun abzufangen.

Auch das verstehe ich nicht.
Wie ein leeres default einen Fehler abfangen kann.....
Schlimmer noch, es kann Fehler verbergen.

Klar, kann man da eine Meldung (toter Code) unter bringen, welche nie gezeigt wird.
Mag beim debuggen Sinn machen, aber sonst...

Das mit den magischen Nummern, im switch, ist sowieso etwas ungeschickt, oder?
Beispiel:

  enum Test {a,b,c} t=a;

  switch(t)
  {
    case a: break;
    // default: ;
  }

Sagt:

....ino:45:9: warning: enumeration value 'b' not handled in switch [-Wswitch]
   45 |   switch(t)
      |         ^
....ino:45:9: warning: enumeration value 'c' not handled in switch [-Wswitch]

Das halte ich für eine feine Meldung!
Welche einem bei der Fehlersuche wirklich hilft.

Allerdings wirkt sich dann ein aktivieren der Zeile " default: ; " unglücklich aus, die Meldung wird nicht mehr gezeigt. Wozu auch, es werden ja jetzt b und c auch abgehandelt.

Ich hoffe ich konnte so meine Abneigung gegen, magische Zahlen im Code, toten Code und gegen leere default darlegen.

Nichts gegen den default Fall, wenn er Sinn macht, dann gut, aber in der genannten Situation sehe ich das nicht. Da machen ganz andere Sachen viel mehr Sinn, als ein leerer default Fall.
z.B. der Einsatz von Enum

Eigentlich ist es das "kommst Du da nicht wieder raus" was mir am meisten aufstößt. Denn das verstehe ich überhaupt nicht. Halte es (bislang) für eine Fehlinformation, welche mehr Probleme schafft, als es löst.
Ein switch ist doch keine Sackgasse, in der man verhungert, oder so.

Meine Empfehlung:
Weg mit dem leeren default, an der Stelle, und stattdessen eine Aufzählung für die Fälle.
Dann ist das eine saubere Nummer, wo nix anbrennen kann.
Einem sogar zur Kompilezeit, die Irrtümer vorgehalten werden.

.

my_xy_projekt:
Na dann helf ich mal nach und hoffe das erklären zu können:

Nach einigen Tagen mit zuviel um die Ohren, habe ich deinen Beitrag nun mehr überflogen als gelesen. Ich denke aber das ich damit dem Verstehen deutlich näher komme. Vielen Dank jedenfalls :slight_smile:

m419:
...habe ich deinen Beitrag nun mehr überflogen als gelesen. Ich denke aber das ich damit dem Verstehen deutlich näher komme. Vielen Dank jedenfalls :slight_smile:

Na, ist nicht ganz so schlimm, wie es erscheint.
Der Eine oder Andere - und ich auch - muss sich immer wieder erst darein versetzen, was der Fragesteller für ein Wissen hat.

Darum:
Mit Deinen ELSE-Zweigen setzt Du immer den Inhalt der Variablen auf 0.
Damit werden die Aktionen die Du eigentlich willst am Ende nicht ausgeführt - ausser bei der letzten Abfrage....

Anstelle der Zuweisungen im ELSE müsstest Du am Anfang die Variable mit 0 (oder einem andren sonst ungenutzten Wert) initialisieren UND JEDEN Status abfragen und der Variablen einen davon abhängigen Wert geben um dann das entsprechende case aufzurufen.

Der Wert 0 (oder der von Dir festgelegte Wert) wäre dann ein Wert, der keine aktive Aktion durch eine Verzweigung im case: auslösen muss
Um aber zu sehen, ob der Wert in dem switch-case-Konstrukt verarbeitet wurde, brauchst Du den default: Bereich.

Ist der Wert unbehandelt, kommt es im Falle der Verwendung von enum zur Kompilerwarnung. Ob die berechtigt ist, wäre dann Deine, und nur Deine, ureigenste Entscheidung.
Das default: natürlich nicht einfach mit break; endet, ist eigentlich klar - also muss da was rein, was Dir ggfls. hilft zu erkennen, ob die 0 durch den Block gelaufen ist.
wno158 hat das schon mal vorberetet :wink:

[edit] - auch wenn Doc_Arduino da schon was vorgegeben hat, habe ich Deinen Sketch auf das Nötigste runtergebrochen, mit dem Du austesten kannst, was tasächlich passiert. Wenn ich nicht alle nicht genutzten vars gelöscht habe, sehe es mir nach....

const int Warning_BT = 28;    // Button to activate/diactivate the "hazard flasher" mode of the indicator lights
const int Left_BT = 19;       // Switch setting to activate/diactivate the direction indicator lights an the left side
const int Right_BT = 18;      // Switch setting to activate/diactivate the direction indicator lights an the right side


bool Warning_Stat = 0;      //Indicates if the Button was pressed
bool WarningCase_Val = 0;   //Holds "1" or "0"
bool Warning_LastStat = 0;  //Holds the last Status of the Button

bool Left_Stat = 0;
bool Right_Stat = 0;

int IND_SwitchCase_Val = 0;   // Case Value for the function "Update_Indicator();"

void setup()
{
  Serial.begin (9600);
  pinMode (Warning_BT, INPUT);
  pinMode (Left_BT, INPUT);
  pinMode (Right_BT, INPUT);
}


void loop()
{
  IND_SwitchCase_Val = 0;
  if (digitalRead (Left_BT) == 1)
  {
    Left_Stat = 1;
    IND_SwitchCase_Val = 1;
  }
  if (digitalRead (Right_BT) == 1)
  {
    Right_Stat = 1;
    IND_SwitchCase_Val = 2;
  }
  Warning_Stat = digitalRead (Warning_BT);
  if (Warning_Stat != Warning_LastStat)
  {
    Warning_LastStat = !Warning_LastStat;
    WarningCase_Val = WarningCase_Val - Warning_Stat;
  }
  if (WarningCase_Val == 1)
  {
    IND_SwitchCase_Val = 3;
  }
  Serial.print ("Right Status: ");
  Serial.print (Right_Stat);
  Serial.print (", Left Status; ");
  Serial.println (Left_Stat);
  Update_Indicator();
}

void Update_Indicator()
{
  switch (IND_SwitchCase_Val)
  {
    case 1:
      {
        Serial.println ("case 1");
      }
      break;
    case 2:
      {
        Serial.println ("case 2");
      }
      break;
    case 3:
      {
        Serial.println ("case 3");
      }
      break;
    default:
      {
        Serial.print (F ("IND_SwitchCase_VAL"));
        Serial.print (IND_SwitchCase_Val);
        Serial.println (F ("ungenutzt"));
      }
  }
}