[C] While Schleife mit drücken eines Buttons abbrechen

OP #5336556
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 ?
Gast #5336596
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.
OP #5336599
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.
OP #5336625
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..
}
OP #5336645
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.
OP #5336671
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 ?
Gast #5336687
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.
OP #5336691
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?
Gast #5336693
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 von einem Moderator gelöscht.
Gast #5336706
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
OP #5337219
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!
#5337247
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)

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