Hilfe bei Programm-Bug mit AtMega8 benötigt

OP #7952713
Lesenswert?

Hallo,

ich habe mir ein kleines Programm für eine selbstgebastelte Rollladensteuerung geschrieben und kämpfe gerade mit einem Problem, welches ich überhaupt nicht verstehe. Das Programm steuert einen Motor (rechts/linkslauf) welcher über Nockenschalter (CamUp, CamDown) abgeschaltet wird. Der Rollladen kann über den Schalter SwitchAutoOn zwischen Automatik und Manuell gesteuert werden. Im Automatikmodus wird der Rollladen über einen Fotowiderstand gesteuert. Im manuellen Modus wird über Taster (ButtonDown, ButtonUp und ButtonStop + Nockenschalter gesteuert. Zusätzlich gibt es noch ein Funkmodul welches an die anderen Rollläden den Trigger für Auf oder Ab sendet. Die Hardware funktioniert da ich den Rollladen schon seit Jahren betreibe. Jetzt habe ich aus Langeweile einige Programmteile geändert und hänge an einer Stelle die ich nicht verstehe.

In der Unterfunktion „Schalter“ wird eine Case Schrittkette ausgeführt. Dort hänge ich im Case Schritt 2 wenn auf die Nockenschalter gewartet wird. Warum auch immer werden in diesem Schritt die CamUp und CamDown Merker nicht ausgewertet. Betätige ich den ButtonStop oder ist der Errorcounter Erreicht, wird die Kette fortgesetzt. Nur eben auf CamUp und CamDown wird nicht reagiert. Die zwei Variablen werden in der Unterfunktion „MAP_INPUTS“ gesetzt. Noch zur Info – im Case Schritt 0 wird auch auf die zwei Variablen abgefragt. Dort funktioniert die If Bedingung abhängig vom Zustand der Nockenschalter. Nur im Case Schritt 2 nicht als ob die zwei Variablen irgendwie überschrieben werden. In dem Schritt habe ich mir testweiße die Zustände der zwei Variablen auf dem Display angezeigt. Dort sehe ich wie der Zustand zwischen 0 und 1 wechselt, wenn ich die Schalter betätige.

Es wäre super, wenn jemand die Case Kette + Mapping der Eingänge anschauen könnte. Alles andere in dem Programm funktioniert wie ich es möchte. Nur eben das erkennen der Nockenschalter im Case 2 nicht. Sollte etwas grober Unfug in dem Programm sein freue ich mich über eine Info 😊

Ich arbeite mit Microchip Studio V7.

Viele Grüße Thomas

Angehängte Dateien:
: Bearbeitet durch User
#7952733
Lesenswert?

Ich habs nur mal fix durch die KI gejagt, nicht selbst geschaut. Die KI sagt folgendes, schau mal nach ob es das ist und gib gern ein Zeichen ob es passt oder nicht:

⚙️ Fehlerursache

Der Kernfehler liegt in der Logik der Abfrage und in der Polarität deiner Eingänge.

Du liest die Nockenschalter nicht invertiert ein, d. h.:

1
CamUp = (PINC & (1<<iCamUp));     // ergibt 0 oder !=0
2
CamDown = (PINC & (1<<iCamDown)); // ergibt 0 oder !=0

→ Wenn der Pin geschlossen (LOW) ist, liefert CamUp = 0. → Wenn der Pin offen (HIGH) ist (wegen Pull-Up), liefert CamUp != 0 (meist 0x20 oder 0x10).

In der Logik deiner Schrittkette verwendest du aber beides durcheinander:

Fall Abfrage Erwartete Logik Schritt 0 (Start) (CamDown == 0) → Rollladen kann runterfahren OK, Schalter geschlossen = „unten nicht erreicht“ Schritt 2 (Stop) (CamDown == 1) → Rollladen hat unten erreicht ❌ Hier liegt der Fehler: du prüfst auf 1, aber dein Eingang liefert 0, wenn geschlossen!

Damit wartest du in Schritt 2 auf den Zustand „CamDown == 1“, also nicht betätigt, während du eigentlich „CamDown == 0“ (betätigt) brauchst.

✅ Lösung

Ändere in Case 2 die Abfrage folgendermaßen:

1
case 2:
2
  LED = Toggle1s;
3
  Errorcounter++;
4

5
  if ((Errorcounter >= (Abschaltung * 100)) || ((SwitchAutoOn == 0) && (ButtonStop == 1)))
6
  {
7
      RelaisOn = 0;
8
      SwitchStep++;
9
  }
10

11
  // Richtige Polarität!
12
  if (((DownFlag == 1) && (CamDown == 0)) || ((UpFlag == 1) && (CamUp == 0)))
13
  {
14
      RelaisOn = 0;
15
      SwitchStep++;
16
  }
17
  break;

👉 Begründung:

Du verwendest Pullups, also: Taster/Nockenschalter geschlossen → Pegel LOW → 0

Daher ist „ausgelöst“ = 0 und nicht 1.

🧠 Warum es im Schritt 0 trotzdem funktioniert

In Schritt 0 fragst du genau so ab:

1
if ((CamDown == 0) && (ButtonDown == 1) && (DownFlag == 0))

→ Das ist korrekt, deswegen funktioniert’s dort. In Schritt 2 war nur die Polarität verdreht.

💡 Empfehlung zur Robustheit

Damit du das nie wieder verwechselst, definiere dir am Anfang saubere Makros:

1
#define IS_ACTIVE(x)   ((x) == 0)   // low-aktiv
2
#define IS_INACTIVE(x) ((x) != 0)

und nutze dann:

1
if ((DownFlag == 1) && IS_ACTIVE(CamDown))

Gib den Eingangsbits sprechende Namen mit ihrer Logikrichtung:

1
uint8_t CamDown_ActiveLow;

oder

1
CamDown = !(PINC & (1<<iCamDown));

Dann arbeitest du im Code immer mit 0 = aus, 1 = an und sparst dir späteres Umdenken.

🔍 Optionaler Check

Wenn du im Display siehst: „CamDown = 0“ während Schalter gedrückt → korrekt. Dann sollte nach der Änderung oben der Fall direkt erkannt und SwitchStep weitergeschaltet werden.

📋 Fazit

Der Fehler ist kein Timing- oder Interrupt-Problem, sondern: Falsche Polarität der Nockenschalter in der Bedingung von Case 2.

Änderung:

1
- if (((DownFlag == 1) && (CamDown == 1)) || ((UpFlag == 1) && (CamUp == 1)))
2
+ if (((DownFlag == 1) && (CamDown == 0)) || ((UpFlag == 1) && (CamUp == 0)))

Danach sollte dein Rollladen sofort wieder sauber stoppen, wenn der Endschalter erreicht ist.

#7952746
Lesenswert?

Sebastian R. schrieb:

Ich glaube nicht, dass in diesem Forum jemand gewillt ist, irgendwelchen KI-Text zu überprüfen.

Da muss man sich nur eine einzige Zeile ansehen. Wenn eine KI noch nicht einmal in der Lage ist, die operator precedence gescheit und nicht doppelt und dreifach gemoppelt und umklammert anzuwenden, kann der Rest auch nur Schwachsinn sein.

== bindet stärker als && und das stärker als ||.

Just sayin'

#7952749
Lesenswert?

Sebastian R. schrieb:

Ich glaube nicht, dass in diesem Forum jemand gewillt ist, irgendwelchen KI-Text zu überprüfen.

Das verlangt auch keiner von den Mitgliedern und dem TE ist es selbst überlassen die Info zu nutzen.

Nemopuk schrieb:

Da hat die KI wie erwartet viel irreführenden Text fabuliert.

Ich sehe Kritik an der KI, aber ich sehe keine, nicht irreführende, Lösung von dir. Actus non verba.

#7952757
Lesenswert?

Norbert schrieb:

Wenn eine KI noch nicht einmal in der Lage ist, die operator precedence gescheit und nicht doppelt und dreifach gemoppelt und umklammert anzuwenden, kann der Rest auch nur Schwachsinn sein.

Die Basis ist der Quelltext aus dem Eingangspost...man kann der KI das aber durchaus mitteilen das anders zu machen. In dem Fall verändert sie aber wenig am Originalquelltext um es besser nachvollziehbar zu halten. Aber wie gesagt, man muss die KI nicht nutzen, ähnlich wie Smartphones, das Internet oder das Auto. Wurde damals auch alles verteufelt, heute nicht mehr wegzudenken. Wobei im Nachbarthread grad ein Handy ohne alles gesucht wird, Ausnahmen bestätigen die Regel ;).

Aber auch in deinem Post sehe ich nur Kritik an der KI, aber keine Lösung des Problems.

OP #7952758
Lesenswert?

Norbert schrieb:

Sebastian R. schrieb:

Ich glaube nicht, dass in diesem Forum jemand gewillt ist, irgendwelchen KI-Text zu überprüfen.

Da muss man sich nur eine einzige Zeile ansehen. Wenn eine KI noch nicht einmal in der Lage ist, die operator precedence gescheit und nicht doppelt und dreifach gemoppelt und umklammert anzuwenden, kann der Rest auch nur Schwachsinn sein.

== bindet stärker als && und das stärker als ||.

Just sayin'

Es klappt aber auch nicht wenn ich nur einen Ausdruck verwende.

if ( CamDown == 1 ) { RelaisOn = 0; SwitchStep++; }

#7952762
Lesenswert?

1
CamUp = (PINC &(1<<iCamUp));
2
CamDown = (PINC &(1<<iCamDown));
  • CamUp ist nicht 0 oder 1 sondern 0 oder 0x20
  • CamDown ist nicht 0 oder 1 sondern 0 oder 0x10

Du vergleichst aber auf "1". Variablen die als boolsche Werte verwendet werden sollte man niemals explizit auf einen Werte prüfen. Statt "(CamUp == 1)" einfach "(CamUp)", wahlweise ohne Klammern.

: Bearbeitet durch User
Persönliche Seite #7952767
Lesenswert?

Andreas M. schrieb:

1
> CamUp = (PINC &(1<<iCamUp));
2
> CamDown = (PINC &(1<<iCamDown));
  • CamUp ist nicht 0 oder 1 sondern 0 oder 0x20
  • CamDown ist nicht 0 oder 1 sondern 0 oder 0x10

Du vergleichst aber auf "1". Variablen die als boolsche Werte verwendet werden sollte man niemals explizit auf einen Werte prüfen. Statt "(CamUp == 1)" einfach "(CamUp)", wahlweise ohne Klammern.

Oder einfach

1
// In/Out flags
2
bool CamUp, CamDown, ButtonUp, ButtonDown, ButtonStop, SwitchAutoOn, ...

statt uint8_t.

: Bearbeitet durch User
OP #7952782
Lesenswert?

Andreas M. schrieb:

1
> CamUp = (PINC &(1<<iCamUp));
2
> CamDown = (PINC &(1<<iCamDown));
3
>
  • CamUp ist nicht 0 oder 1 sondern 0 oder 0x20
  • CamDown ist nicht 0 oder 1 sondern 0 oder 0x10

Du vergleichst aber auf "1". Variablen die als boolsche Werte verwendet werden sollte man niemals explizit auf einen Werte prüfen. Statt "(CamUp == 1)" einfach "(CamUp)", wahlweise ohne Klammern.

TaTa, das ist die Lösung :) Ich habe die == 1 entfernt und es geht. Warume es aber beim ButtonStop == 1 klappt verstehe ich nicht. Wird das nach dem Zufallsprinzip beschrieben? Hast du bei CamUp mit 0x20 einen Tippfehler? Wenn nicht verstehe ich es überhaupt nicht.

#7952788
Lesenswert?

Thomas W. schrieb:

Warume es aber beim ButtonStop == 1 klappt verstehe ich nicht. Wird das nach dem Zufallsprinzip beschrieben?

Nein ist kein Zufall

1
ButtonStop =! (PIND &(1<<iButtonStop));

Das "!" ist die boolsche Negation. D.h. der Ausdruck dahinter wird zunächst in einen bool umgewandelt und das Ergebnis davon ist wieder ein bool. Meistens ist es so, das der boolsche Wert "true" dem Zahlenwert "1" entspricht.

Thomas W. schrieb:

Hast du bei CamUp mit 0x20 einen Tippfehler? Wenn nicht verstehe ich es überhaupt nicht.

Wenn ich mich nicht verrechnet habe, dann ist "1<<iCamUp" => "0x01 << 5" => "0x20". Da steht dann also "PIND & 0x20" (Bitweises UND), damit kann da nur 0 oder 0x20 rauskommen.

#7952795
Lesenswert?

Paul B. schrieb:

→ Wenn der Pin geschlossen (LOW) ist, liefert CamUp = 0. → Wenn der Pin offen (HIGH) ist (wegen Pull-Up), liefert CamUp != 0 (meist 0x20 oder 0x10).

Thomas W. schrieb:

Ja, das ist quatsch was da generiert wurde.

Andreas M. schrieb:

  • CamUp ist nicht 0 oder 1 sondern 0 oder 0x20
  • CamDown ist nicht 0 oder 1 sondern 0 oder 0x10

Thomas W. schrieb:

TaTa, das ist die Lösung :) Ich habe die == 1 entfernt und es geht.

Ich lass das mal so stehen, wa ;).

Andreas hat es aber deutlich besser und klarer formuliert, keine Frage :)

OP #7952840
Lesenswert?

@Andreas M. Also, ich verstehe es jetzt erst richtig. Mein Fehler war die Annahme das ich einfach den Zustand des Eingangs in eine Variable schreiben kann. CamUp = (PINC &(1<<iCamUp)); CamDown = (PINC &(1<<iCamDown)); Das in CamUp und CamDown der Binäre Wert von der Pin Position des Ports gesetzt wird habe ich beim erstellen nicht gerafft.

@Paul B. Damit ergibt die Antowrt der KI auch etwas mehr Sinn auch wenn die Lösung irreführend ist.

@ Johann L. Cool, wieder etwas neues gelernt. 1-2 kleine Projekte alle 3 Jahre reicht einfach nicht aus. Eben die <stdbool.h> hinzugefügt die zukünftig verwendet wird.

Vielen Dank an alle für eure tollen Erklärungen. Davon kann ich einiges mitnehmen. Das Programm funktioniert jetzt jedenfalls wie erwartet. Sollte jemand Langeweile haben würde ich mich über Codeverbesserungen freuen :)

#7952942
Lesenswert?

Johann L. schrieb:

Norbert schrieb:

== bindet stärker als && und das stärker als ||.

Stimmt zwar, aber GCC zum Beispiel warnt per default wenn man alle unnötigen Klammern weglässt:bool fun (int a, int b, int c) { return a && b || c; } warning: suggest parentheses around '&&' within '||' [-Wparentheses]

Johann, nur aus Interesse, welcher tiefere Sinn verbirgt sich dahinter? Also für eine sowohl syntaktisch als auch logisch zu 100% korrekt formulierte Programmzeile eine Warnung zu werfen?

#7952945
Lesenswert?

Johann L. schrieb:

GCC zum Beispiel warnt per default wenn man alle unnötigen Klammern weglässt

Norbert schrieb:

welcher tiefere Sinn verbirgt sich dahinter? Also für eine sowohl syntaktisch als auch logisch zu 100% korrekt formulierte Programmzeile eine Warnung zu werfen?

Lass dich nicht verarschen. Der gcc warnt in diesem Fall nicht per default.

Angehängte Dateien:
: Bearbeitet durch User
#7952951
Lesenswert?

Nemopuk schrieb:

Lass dich nicht verarschen. Der gcc warnt in diesem Fall nicht.

Selbstverständlich warnt er. Man muss nur mal etwas ›sensitiver‹ schalten. So wie es (hoffentlich nicht nur) meine Standard-Einstellung ist.

1
#include <stdbool.h>
2

3
bool test(int a, int b,int c) {
4
    return a && b || c;
5
}
6

7
int main(void) {
8
    bool z = test(1,2,3);
9
    (void)z;
10
    return 0;
11
}
12

13
// gcc -Wall -Wextra -pedantic -std=c11 -no-pie -Os -o "unbenannt" "unbenannt.c" 
14
// unbenannt.c: In function ‘test’:
15
// unbenannt.c:6:14: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
16
//     6 |     return a && b || c;
17
//       |            ~~^~~~
18
// Kompilierung erfolgreich beendet.
#7952957
Lesenswert?

Norbert schrieb:

Dann nenne ich es den sinnvollen default.

Was der Compiler ohne besondere Parameter nicht tut, ist kein Default. Defaults sind die Standardvorgaben, die der Compiler ohne Anweisung von sich aus anwendet (so wie ich das vorgeführt habe).

Der andere ist eher der – Achtung: bashing – Arduino default

Arduino deaktiviert mit seinen Vorgaben keine Warnungen des Compilers, sondern unterlässt es lediglich, die optionalen (nicht default) Warnungen zu aktivieren.

Dass -Wall sinnvoll ist, will ich gar nicht in Abrede stellen. Aber du redest dich hier mit falschen Begründungen heraus.

: Bearbeitet durch User
#7952960
Lesenswert?

Das ist schon durchgedrungen.

Aber wer bitteschön schaltet denn noch nicht einmal Warnungen ein? Bei der Software-Entwicklung komplett blind zu fahren, das ist doch nun wirklich Quadratunsinn.

Und selbst ein einfaches

1
gcc -Wall -o "unbenannt" "unbenannt.c"

reicht für die Warnung aus. Aber ich werde mich mal aus dieser kleinteiligen Diskussion subtrahieren und warten ob Johann etwas dazu sagen kann.

: Bearbeitet durch User
#7953141
Lesenswert?

Jetzt habe ich es gefunden:

1
 // Überwachung Nockenschalter
2
  lcd_setcursor( 14, 2 );
3
  if ( CamDown == 0 )
4
  { lcd_string("0"); }
5
  else
6
  { lcd_string("1"); }

Da ist natürlich klar, dass er den Fehler nicht sehen kann, die Variablen mit

1
itoa( CamDown, Buffer, 10 );
2
lcd_string(Buffer);

auszugeben wäre erheblich aussagekräftiger gewesen.

OP #7953332
Lesenswert?

Da ist natürlich klar, dass er den Fehler nicht sehen kann, die Variablen mit

1
> itoa( CamDown, Buffer, 10 );
2
> lcd_string(Buffer);
3
>

auszugeben wäre erheblich aussagekräftiger gewesen.

Ja, das kommt noch vom alten Code wo ich in der If direkt den PortPin abgefragt hatte. Dort hatte ich dann nur die Variable ersetzt was natürlich zur Diagnose nicht so schlau war.

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