Forum: Mikrocontroller und Digitale Elektronik [C] While Schleife mit drücken eines Buttons abbrechen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

erstmal zum Aufbau:
Attiny2313
LEDs
Button

Ziel:
Starten eines Programms durch drücken des Buttons und verlassen der 
Funktion (und der darin befindlichen Schleife) durch erneutes drücken.

Meine Funktion lässt die LEDs in untersch. Reihenfolge aufleuchten und 
das als Schleife. Die Funktion starte ich indem ich den Button drücke. 
Aber wie ist es möglich die Funktion wieder durch drücken des Buttons zu 
verlassen?

Mein Ansatz war:
while (PIND & (1 << START))

Den Pin D2 habe ich Start genannt. Dieser ist über einen Button an Masse 
verbunden und wird vom Attiny als Pullup geschaltet. Das ganze 
funktioniert auch da ich ja meine Funktion durch drücken des Buttons 
starten kann. Also mit: if(!(PIND & (1 << START)))

Hat da jemand einen Tipp ?

: Bearbeitet durch User
von Klaus R. (klara)


Bewertung
0 lesenswert
nicht lesenswert
Mario I. schrieb:
> Ziel:
> Starten eines Programms durch drücken des Buttons und verlassen der
> Funktion (und der darin befindlichen Schleife) durch erneutes drücken.

Wo liegt denn da das Problem?
mfg Klaus

von Mario I. (md94)


Bewertung
-1 lesenswert
nicht lesenswert
Klaus R. schrieb:
> Wo liegt denn da das Problem?

Na es funktioniert nicht ?
Wie oben geschrieben habe ich es über eine while Schleife versucht deren 
Bedingung ist das das der Button nicht gedrückt ist: while (PIND & (1 << 
START))

Das ganze funktioniert aber nicht..
Muss man das anders formulieren oder geht das so "einfach" nicht ?

von Quadrat (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
>drücken des Buttons und verlassen der
>Funktion (und der darin befindlichen Schleife) durch erneutes drücken.

Erst ne WHILE, um zu warten, bis der Knopf gerückt wurde, dann ne WHILE 
um zu warten, bis er los gelassen wurde und dann ne WHILE um zu warten, 
bis er zum zweiten Mal gedrückt wurde.

Da Taster prellen, sollte man nach jedem WHILE etwa 50ms warten.

Das wäre der einfachste Weg.

Etwas komplizierter aber viel viel eleganter und besser wenn das 
Programm komplexer wird:

In einer Task (1ms, 10ms) den Taster abfragen. Zählen zum Entprellen. 
Flag setzen beim "Drücken" und "Loslassen erkannt". Und dann noch ein 
Flag für beide Flanken.

Ein gutes Programm hat kein WHILE (bzw. nur ein einziges zentrales) und 
kein DELAY.

von Mario I. (md94)


Bewertung
-3 lesenswert
nicht lesenswert
Danke aber kannst du das mal als Code schreiben?
Kann damit nicht so viel anfangen bin recht neu in dem Thema..
Wär super wenn du das mal als Beispielcode zeigen könntest!

Also aktuell hab ich ne While Schleife mit einer if Anweisung. Wenn der 
Button gedrückt wird ist diese erfüllt und startet meine LED-Funktion 
die in einer While läuft die beendet werden soll wenn der Button nochmal 
gedrückt wird.

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mario I. schrieb:
> Hat da jemand einen Tipp ?

Zeige eine vollständige, auf das Grundproblem reduzierte Version deines 
Programms

von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> Mario I. schrieb:
>> Hat da jemand einen Tipp ?
>
> Zeige eine vollständige, auf das Grundproblem reduzierte Version deines
> Programms

hier int main:

  while(1)
  {
    if(!(PIND & (1 << START)))
    {
      if(PINB & (1 << PB1)) {Modus1();} //wenn Schieberegler auf Modus1 
steht, später kommen noch 4-5 Programme dazu und er führt dann immer das 
aus auf dem der Schieberegler steht.

    else{PORTD |= (1 << LEDR);}
  }

drücke ich den button springt es in die Funktion Modus1:

  while (PIND & (1 << START) || s==5) {

    PORTA |= (1 << LEDG);
    PORTD |= (1 << LEDR);
    _delay_ms(5000);
    PORTA &= ~(1 << LEDG);
    PORTD &= ~(1 << LEDR); //der Vorläufer zum Programm das 5 mal 
wiederholt wird

    for(s=0; s<5; s++) {
//Programmablauf von den LEDs..
}

: Bearbeitet durch User
von Jim M. (turboj)


Bewertung
0 lesenswert
nicht lesenswert
Mario I. schrieb:
> _delay_ms(5000);


Mal probiert den Taster 5 Sekunden lang gedrückt zu halten?

von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Jim M. schrieb:
> Mario I. schrieb:
>> _delay_ms(5000);
>
>
> Mal probiert den Taster 5 Sekunden lang gedrückt zu halten?

Was soll das bringen?
Die Passage die du zitierst soll genau das machen..die LEDs für 5 
Sekunden anschalten und dann ausschalten. Darauf folgt dann eine Abfolge 
die sich 5 mal wiederholt. Die 5sek. dienen als eine Art Ankündigung das 
der Modus gestartet wird.

von Teo D. (teoderix)


Bewertung
-2 lesenswert
nicht lesenswert
Von AVR hab ich keinen Plan.

Mario I. schrieb:
> PIND

Was is'n dat, was steht da drin?
Sicher das ein Bitweiser Vergleich Not tut? Probier mal einen Logischen 
Vergleich (&&).

von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Teo D. schrieb:
> Von AVR hab ich keinen Plan.
>
> Mario I. schrieb:
>> PIND
>
> Was is'n dat, was steht da drin?
> Sicher das ein Bitweiser Vergleich Not tut? Probier mal einen Logischen
> Vergleich (&&).

PinD ist die Pingruppe D und den Pin PD2 hab ich als "Start" definiert.

Ich verstehe nicht ganz was du mit dem logischen Vergleich meinst. 
Worauf beziehst du das auf welchen Teil ? Und was meinst du damit ?

von Michal (Gast)


Bewertung
0 lesenswert
nicht lesenswert
_delay_ms(5000) blockiert 5 lang. In dieser Zeit wird der PIN mit dem 
Taster nicht abgefragt. Wenn du innerhalb dieser 5s den Taster kurz 
drückst, bemerkt die Abbruchbedingung der Schleife dies nicht.

von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Michal schrieb:
> _delay_ms(5000) blockiert 5 lang. In dieser Zeit wird der PIN mit dem
> Taster nicht abgefragt. Wenn du innerhalb dieser 5s den Taster kurz
> drückst, bemerkt die Abbruchbedingung der Schleife dies nicht.

Ja das hab ich mir auch schon gedacht, aber wie löst man das ? Also wie 
lass ich die Bedingung Prüfen während die LED für 5 sek aus bleibt?

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Teo D. schrieb:
> Was is'n dat, was steht da drin?
> Sicher das ein Bitweiser Vergleich Not tut? Probier mal einen Logischen
> Vergleich (&&).

PIND wird ein Register mit 8 Bit sein, dass den Zustand von den 8 
IO-Pins am Port D wiederspiegelt. Da ist es schon gut, das Bit/den Pin, 
an dem der Taster hängt, rauszumaskieren.

Beitrag #5336694 wurde vom Autor gelöscht.
von Teo D. (teoderix)


Bewertung
-1 lesenswert
nicht lesenswert
Wolfgang schrieb:
> PIND wird ein Register mit 8 Bit sein, dass den Zustand von den 8
> IO-Pins am Port D wiederspiegelt. Da ist es schon gut, das Bit/den Pin,
> an dem der Taster hängt, rauszumaskieren.

Ojemine, ich sollts lieber gleich ganz lassen. Das dauert aber auch 
immer länger, bis der Kalk rieselt. :)

von Hunsbuckel (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Warum nutzt man bei so einer aufgsbe  keinen Interrupt?
ZB Pin Change Interrupt?

von Michal (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Mario I. schrieb:
> Ja das hab ich mir auch schon gedacht, aber wie löst man das ? Also wie
> lass ich die Bedingung Prüfen während die LED für 5 sek aus bleibt?

Am besten so, wie Quadrat das beschrieben hat:

Quadrat schrieb:
> In einer Task (1ms, 10ms) den Taster abfragen. Zählen zum Entprellen.
> Flag setzen beim "Drücken" und "Loslassen erkannt". Und dann noch ein
> Flag für beide Flanken

Einen task könnte man mit einem Timerinterrupt erzeugen, der alle 10ms 
ein Interruptroutine aufruft. Falls dir das nichts sagt, könntest du 
zunächst probieren, eine LED gesteuert von einem interrupt blinken zu 
lassen. Beispiele dafür gibt es im Netz oder vielleicht auch im Kurs auf 
mikrocontroller.net

von duck&wech (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Michal schrieb:
> Einen task könnte man mit einem Timerinterrupt erzeugen, der alle 10ms
> ein Interruptroutine aufruft.

Läuft dann das delay() trotzdem noch sauber weiter?

von Teo D. (teoderix)


Bewertung
0 lesenswert
nicht lesenswert
duck&wech schrieb:
> Läuft dann das delay() trotzdem noch sauber weiter?

Klar, ist aber Ressourcen Verschwendung, wenn man eh schon einen 
Timer-Tick (Flag) hat.
While(pause - TimmerTick) TimmerTick=0;
Geschickt programmiert, sind damit aber Pausen, die das Programm 
anhalten, dann nicht mehr nötig.

von Mario I. (md94)


Bewertung
0 lesenswert
nicht lesenswert
Soooo..damit Leute die das selbe suchen wie ich nicht dumm sterben:

Das ganze wurde von mir jetzt mit einem Interrupt gelöst.
Da ich nicht wusste was das ist konnte ich ja schlecht danach 
suchen..nach dem Hinweis hier hab ichs dann mal gesucht und bin auf ein 
lehrreiches YT Video gestoßen:

https://youtu.be/vl5H_Q1slYY

Für den Attiny2313 muss das aber so aussehen ->
In der Main den Taster (der am Pin PD2 (INT0) hängt) so definieren:

  DDRD &= ~(1 << PD2);
  PORTD |= (1 << PD2);

In der Funktion die unterbrochen werden soll muss folgendes stehen:

GIMSK = (1<<INT0); //Eingang INT0 als Interrupt definieren
sei(); // das muss auch darunter..

Dann muss eine Funktion erstellt werden in die das Programm beim 
Interrupt durch den Taster springt:

ISR(INT0_vect)
{
// Hier kann man dann zb die Hauptfunktion aufrufen das er wieder auf 
Anfang springt..oder was man da eben ausführen will..
}

ACHTUNG: Schreibt man das jetzt einfach so hin wie ich dann ist das 
Programm schneller als man den Taster wieder loslassen kann und das 
Programm "spinnt". Hier hab ich dann mit dem delay Befehl gearbeitet um 
den Taster zu entprellen. Also einfach in der interrupt Funktion ein 
kurzes Delay von 300ms einbauen und es sollte genügen.

Das man das ganze profesioneller lösen kann kann ich mir denken. Für 
mich funktioniert die Lösung aber sehr sehr gut da mein Programm alles 
andere als komplex ist.

Vielen Dank an die die mir hier geholfen haben und mich darauf gestoßen 
haben!

: Bearbeitet durch User
von Teo D. (teoderix)


Bewertung
0 lesenswert
nicht lesenswert
Mario I. schrieb:
> Hier hab ich dann mit dem delay Befehl gearbeitet um
> den Taster zu entprellen. Also einfach in der interrupt Funktion ein
> kurzes Delay von 300ms einbauen und es sollte genügen.

Wenn du dich jetzt noch mit Timer beschäftigst, kannst du das/die Delays 
auch rausschmeißen.
zB: Den durch den Taster ausgelösten Interrupt 300ms sperren, anstatt 
das Programm zu stoppen.
Oder statt eines Pin-Interrupt regelmäßig (zB.300ms wie du gerade 
wartest) pollen, einlesen -> Nennt sich Polling. :)
https://de.wikipedia.org/wiki/Polling_(Informatik)

von Dieter F. (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Schau dir mal das Standard-Werk an - die "Peter Dannegger-Methode" ist 
(nahezu :-)) unbestritten.

https://www.mikrocontroller.net/articles/Entprellung

von Teo D. (teoderix)


Bewertung
0 lesenswert
nicht lesenswert
Dieter F. schrieb:
> Schau dir mal das Standard-Werk an - die "Peter Dannegger-Methode" ist
> (nahezu :-)) unbestritten.

Wer bestreitet da was? Was gibts da zu bekritteln?
(Außer ein paar nicht zu beseitigende Missverständnissen, bei der 
Kommunikation:)
"Der hats drauf" würde man da nur sagen.

von Dieter F. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Teo D. schrieb:
> Wer bestreitet da was?

Schau dir mal die Threads dazu an - dann weisst Du es :)

von Teo D. (teoderix)


Bewertung
0 lesenswert
nicht lesenswert
Dieter F. schrieb:
> Schau dir mal die Threads dazu an - dann weisst Du es :)

Muss ich glaube nicht, hab mir schon gedacht, das da seine 
Empfindlichkeit herrührt. :(

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.