Hallöchen alle miteinander :)
Ich möchte gerne eine LED "steuern", indem ich drei mal auf den Taster
drücke und diese an geht. Nach erneutem dreimaligen Drücken soll sie
wieder ausgehen und immer so weiter.
Das Einschalten funktioniert soweit ganz gut, jedoch weiß ich nicht, wie
ich in dieser Art die LED wieder ausschalten soll. Ich hab es damit
probiert, die Variable var wieder zu dekrementieren, jedoch kommt dabei
nicht wirklich etwas gescheites raus.
Hier mein Code um die LED einzuschalten:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
intmain(void)
4
{
5
PORTD=(1<<PD2);
6
DDRB|=(1<<PB0);
7
uint8_tvar=0;
8
uint8_ttaster_vorher=0;
9
uint8_ttaster_jetzt=0;
10
11
while(1)
12
{
13
if((PIND&(1<<PD2)))
14
{
15
taster_jetzt=1;
16
}
17
else
18
{
19
taster_jetzt=0;
20
}
21
if(taster_vorher==0&&taster_jetzt==1)
22
{
23
var++;
24
}
25
if(var==3)
26
{
27
PORTB|=(1<<PB0);
28
}
29
taster_vorher=taster_jetzt;
30
}
31
}
Entprellt habe ich mittels Kondensatoren.
Liebe Grüße,
Lavy!
Du hast keinen Befehl die LED auszuschalten:
PORTB &= ~(1<<PB0);
Führe eine Variable ein, die den Status der LED widerspiegelt, ändere
die abfrage auf 3 durch eine Modulo-Divisions-Abfrage auf 0 und toggle
dann die LED anhand deren Status.
Nebenbei: Willst du einen Triple-Klick erkennen, oder nur die Anzahl der
Klicks zählen und dann reagieren? Weil für ersteres müsstest du die
Klicks
nach einer gewissen Zeit resetten...
Svenja S. schrieb:> if(var == 3)> {> PORTB |= (1<<PB0);> }
hier schaltest Du immer ein, wenn 3 Mal drücken erreicht wurde. Wie wäre
es, wenn Du den Zustand der Led umkehrst, wenn 3 Mal drücken erreicht
wurde ?
Ok, da lauert noch ein kleiner Fallstrick : die Led fängt an zu glimmen
nach 3 Mal drücken. Wenn man erst mal weiss warum, ist es klar. Der
Zähler steht noch auf 3 Mal gedrückt, und die Led wird in jedem
Durchlauf an oder aus geschaltet. Bisher hast Du sie immer wieder
eingeschaltet, was bei einer bereits eingeschalteten Led nichts macht,
also nicht auffällt.
Die Idee von Udo ist deshalb nicht so prickelnd, weil jede Variable
einen maximalen Wert hat. Bei C geht das Zählen danach ohne weitere
Warnungen wieder von vorne los. Wenn also jemand es schafft 256 mal zu
drücken, bevor Dein Programm neu gestartet wird, passiert was
Unerwartetes weil 256 nunmal nicht ohne Rest durch 3 teilbar ist.
Überhaupt will ja niemand wissen, wie oft der Taster seit Programmstart
gedrückt wurde. Das macht die Sache nur unnötig kompliziert so mit
Modulo und so. Einfach jedesmal bis 3 zählen und gut. Klappt schon im
Kindergarten...
Achtung Spoiler :
.
.
.
.
Hey super, vielen Dank!
Manchmal ist die Lösung zu einfach um darauf zu kommen ^^'
Mal aus Interesse: Ich verwende einen ATMega8. Gibt es dort vielleicht
eine interne Funktion, die man dafür ausnutzen könnte?
Also um dann aus dem Code quasi einen Dreizeiler zu machen?
Liebe Grüße
Lavy :)
Du kannst dafür den Timer/Counter 2 im CTC Modus mit externem
Takteingang nutzen. Die Initialisierung passt eventuell nicht in 3
Zeilen, wenn es dann mal läuft, läuft es ohne eine einzige Codezeile.
>Also um dann aus dem Code quasi einen Dreizeiler zu machen?
Dahin kommst Du, wenn Du in Deinem Programm die Zeilen 21 bis
(einschließlich) 28 änderst in...
1
if ( taster_vorher == 0 && taster_jetzt == 1 )
2
{
3
KeyPress
4
}
...und in die Funktion "KeyPress" den entsprechenden Code auslagerst:
1
var++;
2
if(var == 3)
3
{
4
LEDState = !LEDState;
5
var = 0;
6
}
Plus noch an geeigneter Stelle eine Zeile, die sich darum kümmert, dass
die boolesche Variable LEDState mit Pin PB0 auf dem Port PORTB verknüpft
wird. Bekommst Du sicher selber hin.
Den Inhalt von "KeyPress" könnte man nun als "Anwendung" interpretieren
und alles andere als "Betriebssystem" (beide Begriffe in einem sehr
weiten Sinn). Wie Du siehst, ist die "Anwendung" dann tatsächlich nur
ein ganz einfacher Vierzeiler.
Svenja S. schrieb:> Ich verwende einen ATMega8EAF schrieb:> Für die meisten/modernen AVR reicht hier PINB = (1<<PB0); statt PORTB> ^= (1<<PB0);
Meiner Erinnerung nach ist der ATMega8 zu alt dafür. Ein ATMega88
hingegen könnte das.
Frank M. schrieb:> Meiner Erinnerung nach ist der ATMega8 zu alt dafür.
Durchaus!
Allerdings, kam diese Salamischeibe quasi gleichzeitig mit meinem
Posting.
Ansonsten, würde ich mich mit solchen Antiquitäten nur unter Zwang
beschäftigen
Nochmal vielen Dank an alle :)
Hab es jetzt auch mit Interupts probiert und funktioniert alles wie es
soll!
Ich wünsche euch noch eine schöne Woche :)
LG
Lavy
So was programmiert sich komfortabler als State-Machine (finiter
Automat).
Also kein linearer Algorithmus, der hin und her hüpft, sondern eine
Funktion, die periodisch aufgerufen wird und dann abhängig vom Status
die Eingangswerte auswertet und ggf. den Status wechselt.
Wenn man nur ein/aus hätte, dann würde der "aus" Status, also State 0,
prüfen, ob die Taste gedrückt wurde. Wenn das so ist, schaltet er die
Lampe ein und wechselt zum nächsten Status (1), der dann jedes mal beim
Aufruf prüft, ob die Taste wieder losgelassen wurde, dann wechselt er
zum Status 2, der guckt, ob die Taste wieder gedrückt wurde, dann die
Lampe ausschaltet, zum Status 3 wechselt, der auf das Loslassen wartet
und zum Status 0 zurück kehrt.
Solche State-Machines kann man beliebig komplex machen. Am Besten ruft
man die in einem Interrupt auf, wenn etwas passiert ist, oder periodisch
über einen Timer. Die einzelnen States sind in einem switch/case was die
Funktionen klein, handlich und übersichtlich macht.
ggf. mal was über finite Automaten lesen. Das ist ein sehr praktisches
Werkzeug.
Peter D. schrieb:> Ich würde zum Einschalten fünfmal drücken, dann reicht zum Ausschalten> einmal drücken.
+1 ;-)
Du musst Dir aber dann merken (oder aufschreiben), dass Du schon 5mal
gedrückt hast ;-)
Hallo Svenja,
hat dieses 3 malige betätigen einen Hintergrund?
Es macht nach nur dann Sinn wenn Du die Taste 3x innerhalb eines
Zeitraumes mit Timeout betätigst.
Alternativ wäre die Länge eines Tastendrucks eine Lösung.