Hallo! Ich bin ein Anfänger in der Microkontrollerprogrammierung. Ich
habe sämtliche Beiträge angesehen, aber keiner konnte mich weiter
bringen. Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster
zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck
leuchtet nächste Led. Ich habe myAVR mk2 board. Hier ist ein mehr oder
weniger passender
Beitrag(Beitrag "Taster als Schalter"), aber das
bringt mich nicht weiter. Hier ist mein Quellcode mit einem Led. Ich
wäre dankbar, wenn jemand den Quellcode vervollständigen könnte oder
neuer Code mit Timer oder anderem Lösung schreibt.
Alex
1
#include<avr/io.h>
2
3
4
intmain(void)
5
{
6
DDRB|=(1<<PD3)|(1<<PD4)|(1<<PD5);// Pin 3,4,5 im Port B auf Ausgang
7
DDRB&=~(1<<PD0);// Pin 0 im Port B auf Eingang (Taster)
8
PORTB|=(1<<PD0);// Pull-Up aktivieren
9
while(1)
10
{
11
if(!(PINB&(1<<PB0)))// Taster Abfrage high oder low?
12
{
13
PORTB|=(1<<PB3);// Led an
14
}
15
else
16
{
17
PORTB&=~(1<<PB3);// Ansonsten Led aus
18
}
19
20
// Code soll weiter gehen: nach nächsten gleichen Tastendruck soll
21
//Led an PD4 an gehen, und nach nächsten GLEICHEN Tastenbetätigung Led an PD5
Zerlege die Aufgabe in kleinere Teile , die Du leichter
lösen/beherrschen kannst, z.B.:
- zähle mit jedem Tastendruck einen Zähler hoch
- lass die zum jeweiligen Zäherstand passende LED leuchten
Alex schrieb:> // Code soll weiter gehen: nach nächsten gleichen Tastendruck soll> //Led an PD4 an gehen, und nach nächsten GLEICHEN Tastenbetätigung Led> an PD5> //wie soll die Code weiterlaufen?
Was hat PD4 an PortB zu suchen ? Wenn schon PortB, dann PB4.
Code einrücken.
Arithmetische und Logische Operationen mit einem Leerzeichen trennen.
Erst einmal eine Variable deklarieren:
1
uint8tTasterCnt=3;
Der Else Teil deiner if Abfrage ist auch unnötig, also:
1
while(1)
2
{
3
if(!(PINB&(1<<PB0)))// Taster Abfrage high oder low?
4
{
5
PORTB&=~(1<<TasterCnt);// Led aus
6
TasterCnt+=1;
7
if(TasterCnt>5)
8
TasterCnt=3;
9
PORTB|=(1<<TasterCnt);// Led an
10
}
11
}// Ende while Schleife
Normale Taster prellen gern, das muss man auch berücksichtigen.
Hi
Ich kenne nicht dein Board und auch deine Sprache ist nicht mein Ding,
aber prinzipiell solltest du deine Aufgabe in Module packen. Dazu
benötigst du ein paar Variablen. Nur keine Angst, das kostet nix extra,
macht die Arbeit etwas leichter. Beginnen wir mit dem Einlesen der
Eingänge. Auch wenn du hier nur einen Eingang hast, macht es Sinn, eine
Variable zu benutzen und dort die Bits für Eingänge abzulegen. Dazu
schreibst du eine eigene Routine z.B. Read_IO. In einer Variablen New_In
legst du nun das Bit des Tasters an. Hast du später mal mehrere
Eingänge, packst du diese in die Variable. Nun mußt du entprellen. Dazu
schaffst du dir 2 Variablen, eine für ein Zeitzähler und eine für einen
Spiegel der Variablen New_In. Also z.B.Deb_Time als Zählvariable und
In_Debounce für den Spiegel der Variablen New_In. Die Routine zum
Entprellen prüft mit einer Exclusiv-Veroderung, ob zwischen New_In und
In_Debounce ein Unterschied ist. Das erkennst du sehr leicht, da die
unterschiedlichen Bits im Ergebnis "1" sind. Hast du Unterschiede, setzt
du den Zeitzähler auf einen Wert, der ca. 10 - 20 ms bedeuten sollte und
kopierst den Wert von New_In nach In_Debounce. Ist beim nächsten
Durchlauf der Entprellroutine könnte nun der Inhalt von New_In und
In_Debounce gleich sein, dann zählst du den zeitzähler runter. Hat er
bis 0 gezählt, hast du keineunterschiedlichen Informationen in den
beiden Variablen mehr gehabt und das Eingangssignal ( die Eingänge ) ist
(sind) stabil. Nun kopierst du New_In in eine Variable Akt_In für den
aktuellen Portwert.
Um nun eine einmalige Aktion durchzuführen, LED 1x weiterschalten, mußt
du eine Flankenauswertung machen. Auch das ist mit einer
Exclusiv-Veroderung und einer Spiegelvariable machbar. Zusätzlich
brauchst du eine Flankenvariable. In einer Routine zur Flankenbildung
werden Alt_In und Akt_In Exclusiv verodert. Ergebnisbit ist "1", wenn
ein Unterschied erkannt wird. Das Ergebnis verundest du wieder mit dem
Inhalt von Akt_In. Klar, nur "1" und "1" ergibt eine "1". Wenn also das
veränderte Bit in Akt_In eine "1" hat, dann ist ein Signalwechsel auf
"1" erfolgt, also Taste gedrückt. Dieses Bit legst du in eine
Ereignisvariable Event_1 ab.
Nun brauchst du nur noch die Routine, um ein Bit in einer weiteren
Variable zu schieben, um dann diese den Ausgängen mit der LED
zuzuweisen. Auf eines solltest du achten: Taster sind nicht selten auf
GND bezogen, um die internen PullUp-Widerstände zu nutzen. Das bedeutet,
ein betätigter Taster (Kontakt) entspricht einer "0", also ganz
entgegengesetzt dem Verständnis "Taster gedrückt" = "1" ! Daher muss
dann in der Einleseroutine das Bit entsprechend gedreht werden, um im
Programm mit der "1"-Logik zu arbeiten. Hier nochmal grob die
Main-Routine mit den Aufrufen der einzelnen Subroutinen
Main
Aufruf Eingänge lesen. Ergebnis in der Variablen New_In
Aufruf Entprellen. Benutzte Var. New_In, In_Debounce und Deb_Time
Ergebnnis in Akt_In
Aufruf Flankenbilden benutzte Var. Akt_In, Alt_In
Ergebnis in Event_1
Aufruf Eventbearbeitung
Eventbit prüfen, Arbeitsvariable schieben, Eventbit
löschen
Aufruf Ausgabe der Arbeitsvariablen an den Port
Sprung zu MAin (Hauptschleife)
Nun hast du 5 überschaubare Subroutinen zu erstellen. Fällt dir eine
weitere Verwendung ein oder ein weiteres Experiment, ist die Anpassung
durch neue Subroutinen oder Änderung bestehender überhaupt kein Problemm
mehr.
Gruß oldmax
@oldmax
Hallo oldmax!
Danke für deine Mühe, du hast so viel geschrieben, ich bin Anfänger und
etwa in der Mitte von deiner Erklärung stieg ich ab, tut mir leid. Für
mich wäre ein Teil von Quellcode mit Kommentaren hilfreicher. Ansonsten
es ist egal was für ein Board ich habe, Quellcode kann ich zu meinem
Atmega8 auf dem myAVR mk2 Board anpassen.
!!!!!! schrieb im Beitrag #3880070:
> Du Depp !
Jemanden Depp und fauler Hund zu nennen nur weil er um Hilfe bietet
finde ich mega gemein! Ich dachte dieser Forum existiert hier nicht
dafür um jemanden zu beleidigen, sondern um Erfahrungen auszutauschen
und jemanden Helfen, der nicht weiter weist. Ich habe erst vor zwei
Monaten damit angefangen, und davor habe ich nur gehört, dass es Sprache
C überhaupt gibt vor allem habe ich noch nie etwas programmiert. Oder du
denkst, dass ich keine Tutorial von mickrokontroller.net nicht
durchgearbeitet habe, weil ich fauler Hund bin? Wenn du mir zeigst wo
im Tutorial genau mein Problem beschrieben ist, dann nehme ich alles
zurück! Bis jetzt habe ich gefunden, wie man einen Taster abfragt. Wenn
du keine Lust und vor allem nicht weist wie das geht, dann lass es sein
mit dienen Beleidigungen vom Sofa.
Jedenfalls wird hier kein Code eben mal vervollständigt - vor allem wenn
er so weit vom Ziel entfernt ist. Vielmehr wird hier Hilfe zur
Selbsthilfe geleistet.
Was Dir wahrscheinlich fehlt, ist ein Verständnis für die Grundprobleme
Deines Vorhabens.
Siehe dazu: http://www.mikrocontroller.net/articles/Entprellung
und: http://www.mikrocontroller.net/articles/Bitmanipulation
Wäre es anders, würde man nämlich erwarten, dass Du wenigstens in Prosa
den Ablauf, wie er sein soll, erklären könntest. Es fehlt im übrigen
eine Erklärung welches Problem Du konkret hast.
So hat Deine Frage eine gewisse Ähnlichkeit zu solchen, die zwecks
effizienter Erledigung einer Hausarbeit eben mal nach 'nem Code fragen.
Alex schrieb:> Jemanden Depp und fauler Hund zu nennen nur weil er um Hilfe bietet> finde ich mega gemein! Ich dachte dieser Forum existiert hier nicht> dafür um jemanden zu beleidigen, sondern um Erfahrungen auszutauschen> und jemanden Helfen, der nicht weiter weist.
Also, nochmal:
1
volatileuint8tTasterCnt=PB3;// Falls du das mal in der ISR abfragen willst
2
3
while(1)
4
{
5
if(!(PINB&(1<<PB0)))// Taster Abfrage high oder low?
6
{
7
PORTB&=~(1<<TasterCnt);// Led aus
8
TasterCnt+=1;
9
if(TasterCnt>PB5)
10
TasterCnt=PB3;
11
PORTB|=(1<<TasterCnt);// Led an
12
/* Normale Taster prellen gern, das muss man auch berücksichtigen,
13
deshalb hier 50mS warten, ist nicht schlimm, LED ist schon an.
14
Sollte man in der ISR nicht machen, aber hier ist es OK*/
15
_delay_ms(50);
16
}
17
}// Ende while Schleife
Ist dir damit geholfen ?
EDIT:
Taster sind normalerweise auf High, beim drücken gehen die auf Low, so
kann man interne Pullups benutzen.
Marc Vesely schrieb:> Ist dir damit geholfen ?
Kaum.
Der springende Punkt ist die Unterscheidung zwischen der "Erkennung
einer gedrückten Taste" und der "Erkennung eines Tastendrucks".
Er braucht letzteres, da hilft es ihm auch nichts, wenn du ihm ersteres
anbietest.
Das Problem: Das Erkennen eines Tastendrucks ist an und für sich nicht
so schwer (Flankenerkennung), wenn da nicht das Tstenprellen wäre.
@TO
stell diese konkrete AUfgabe noch zurück. Das Erkennen einer gedrückten
Taste ist leicht. Das zuverlässige Erkennen eines Tastendrucks ist
hingegen ungleich schwieriger. Und genau letzteres würdest du aber
brauchen. Solange du noch nicht mehr Erfahrung hast, stell alle Aufgaben
zurück, oder bau die Aufgabenstellung um, die darauf basieren, dass
durch durch einmaliges Drücken einer Taste eine Aktion ein einziges mal
(und NUR ein einziges mal) auslöst.
OK. Ich versuche mal anders rum. Als erste schreibe ich was ich schon
kann. Ich verstehe zu 100% wie man Bitmanipulationen gemacht werden. Ich
verstehe das Problem von Tasten Entprällung, das werde ich dem Code
hinzufügen. Ich bewege mich jetzt auf dem Niveau: Leds an und ausmachen,
Lauflicht, eben mit mehreren Tasten. Ich möchte folgendes lernen: Mit
einem Taster hintereinander bestimmte Aufgaben ausführen. Zum Beispiel
ich möchte folgendes Algorithmus haben: Tastendrück #1 = „Lauflicht 5
Leds“, Tastendrück #2 = „Led 1 und 3 an“, Tastendrück #3 = „alle 5
Leds blinken lassen“, Tastendrück #4 = „alle Leds aus“, mit dem
nächsten Tastendrück wird alles wiederholt. Wenn das nicht geht, dann
schreibt das bitte!
Karl Heinz schrieb:> Der springende Punkt ist die Unterscheidung zwischen der "Erkennung> einer gedrückten Taste" und der "Erkennung eines Tastendrucks".>> Er braucht letzteres, da hilft es ihm auch nichts, wenn du ihm ersteres> anbietest.
Hmmm.
Sehe ich ein bisschen anders.
Er ist Anfänger, wird wohl kaum etwas mit Interrupts und Flanken
anfangen können.
Durch _delay_ms(50) wartet er Tasterprellen ab, beim nächsten Durchgang
wird wieder nur auf Tasterdruck reagiert, also praktisch auf Flanke.
Somit ist seine Aufgabe:
Alex schrieb:> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck> leuchtet nächste Led.
gelöst, oder irre ich mich ?
Alex schrieb:> einem Taster hintereinander bestimmte Aufgaben ausführen. Zum Beispiel> ich möchte folgendes Algorithmus haben: Tastendrück #1 = „Lauflicht 5> Leds“, Tastendrück #2 = „Led 1 und 3 an“, Tastendrück #3 = „alle 5> Leds blinken lassen“, Tastendrück #4 = „alle Leds aus“, mit dem> nächsten Tastendrück wird alles wiederholt. Wenn das nicht geht, dann> schreibt das bitte!
Wenn du das willst, dann schreibt das bitte!
Ich wiederhole mich, aber das war deine Frage am Anfang:
Alex schrieb:
> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck> leuchtet nächste Led.
Was willst du jetzt nun ?
Alex schrieb:> Lauflicht, eben mit mehreren Tasten. Ich möchte folgendes lernen: Mit> einem Taster hintereinander bestimmte Aufgaben ausführen.
Das ist schon der zweite SChritt vor dem ersten.
Der erste Schritt lautet:
Wie kann ich einen Tastendruck erkennen?
Und die Antwort drauf ist an und für sich einfach.
Ein Tastendruck kennzeichnet sich dadurch, dass die Taste vorher noch
nicht gedrückt war, jetzt ist sie aber gedrückt. Es ist genau dieser
UNterschied im 'Status' des Tasters, der deinem Programm sagt: Jetzt hat
der Benutzer die Taste niedergedrückt.
Die Erkennung dieses Wechsels ist an und für sich einfach: In einer
Variablen merkt man sich immer den Zustand von 'vorher'. In der
Hauptschleife wird dann der Zustand 'Jetzt' mit dem Zustand 'VOrher'
verglichen und wenn sich die beiden Unterscheiden, dann muss es einen
Tastendruck gegegeben haben
1
uint8_tvorher;
2
uint8_tjetzt;
3
4
intmain()
5
{
6
....
7
8
if(PINB&(1<<PB0))
9
vorher=1;
10
else
11
vorher=0;
12
13
while(1)
14
{
15
if(PINB&(1<<PB0))
16
jetzt=1;
17
else
18
jetzt=0;
19
20
if(vorher!=jetzt)// Unterschied! Taste wurde gedrückt
21
{
22
vorher=jetzt;// merken, damit im nächsten Durchlauf
23
// beim Vergleich nicht mehr reagiert wird
24
// sondern erst wieder beim nächsten
25
// WEchsel
26
27
if(jetzt==0)// Was war das eigentlich? Niederdrücken
28
// oder Loslassen
29
// Wir wollen nur niederdrücken. Wie die Taste
30
// jetzt steht, verrät uns diese INformation
31
{
32
....machwas
33
}
34
}
35
36
....
37
}
38
}
Im Prinzip also nicht schwer. Eine simple Flankenerkennung.
Wenn da nicht das Tastenprellen wäre.
Marc Vesely schrieb:> Hmmm.> Sehe ich ein bisschen anders.> Er ist Anfänger, wird wohl kaum etwas mit Interrupts und Flanken> anfangen können.> Durch _delay_ms(50) wartet er Tasterprellen ab, beim nächsten Durchgang> wird wieder nur auf Tasterdruck reagiert, also praktisch auf Flanke.
Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in
50 Millisekunden?
Marc Vesely schrieb:> Ich wiederhole mich, aber das war deine Frage am Anfang:>> Alex schrieb:>> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster>> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck>> leuchtet nächste Led.>> Was willst du jetzt nun ?
Danke sehr! Ich habe erste Variante von dir ausprobiert. Es
funktionierte. Nur die zweite Variante mit _delay_ms(50) hat nicht
funktioniert. So sieht es aus: (ich weiß nicht was ich da falsch ist?)
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#define F_CPU 8000000
4
5
intmain(void)
6
{
7
volatileuint8_tTasterCnt=PB3;// Falls du das mal in der ISR abfragen willst
8
9
while(1)
10
{
11
if(!(PINB&(1<<PB0)))// Taster Abfrage high oder low?
12
{
13
PORTB&=~(1<<TasterCnt);// Led aus
14
TasterCnt+=1;
15
if(TasterCnt>PB5)
16
TasterCnt=PB3;
17
PORTB|=(1<<TasterCnt);// Led an
18
/* Normale Taster prellen gern, das muss man auch berücksichtigen,
19
deshalb hier 50mS warten, ist nicht schlimm, LED ist schon an.
20
Sollte man in der ISR nicht machen, aber hier ist es OK*/
Karl Heinz schrieb:> Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in> 50 Millisekunden?
LOL.
Ich schaffe es, aber du hast natürlich Recht.
a) Delay für normale Benutzer verlängern ?
b) Hast du schon gepostet, erübrigt sich.
Und für das, was er jetzt machen will, braucht er sowieso Interrupts
und state machine.
Marc Vesely schrieb:> Karl Heinz schrieb:>> Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in>> 50 Millisekunden?>> LOL.> Ich schaffe es, aber du hast natürlich Recht.> a) Delay für normale Benutzer verlängern ?> b) Hast du schon gepostet, erübrigt sich.>> Und für das, was er jetzt machen will, braucht er sowieso Interrupts> und state machine.
Und Timer.
Spätestens bei 'Blinken' (oder irgendwann mal 'Lauflicht') kommt er mit
delays nicht mehr weit.
Karl Heinz schrieb:> Die Erkennung dieses Wechsels ist an und für sich einfach: In einer> Variablen merkt man sich immer den Zustand von 'vorher'. In der> Hauptschleife wird dann der Zustand 'Jetzt' mit dem Zustand 'VOrher'> verglichen und wenn sich die beiden Unterscheiden, dann muss es einen> Tastendruck gegegeben haben
Danke! Klasse! Ich versuche es mit dem Quellcode auch! Ich bin jetzt auf
jedem Fall weiter als noch vor 5 Tagen.
Marc Vesely schrieb:> Und für das, was er jetzt machen will, braucht er sowieso Interrupts> und state machine.
Wie würde der Code mit Interrupts aussehen? Kompliziert?
Das:
> Insbesondere der Abschnitt> http://www.mikrocontroller.net/articles/Interrupt#...> zeigt Dir ein einfaches Beispiel, mit dem Du erstmal eine LED zum> Blinken bringen kannst
sollte eigentlich heissen:
Insbesondere der Abschnitt
http://www.mikrocontroller.net/articles/Interrupt#...
zeigt Dir ein einfaches Beispiel, mit dem Du erstmal eine LED zum
Blinken bringen kannst, indem Du die Anweisungen für die LED einfügst
und Dir den Zeitabstand der Interrupts anpasst, bzw. eine Zählvariable
verwendest. Fortgeschrittene machen das mit der Flag-Variable.
Alex schrieb:> Wie würde der Code mit Interrupts aussehen? Kompliziert?
Kommt darauf an.
Aber wie der Karl Heinz sagte, du wirst dann auch einen Timer brauchen.
Im Prinzip:
Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,
werden entsprechende Flags gesetzt, unter anderem:
a) Flag für gedrückten Taster.
b) Flag für Timer, damit die Prellzeit abgezählt werden kann. Während
dieser (Prell-) Zeit, wird ISR gleich wieder verlassen. Dieser Flag
wird wiederum in der Timerroutine zurückgesetzt.
c) Wenn du willst, kannst du auch Interrupt umdrehen, d.h. deine ISR
wird nun auf steigende, statt auf fallende Flanke feuern.
Aber nicht gleich übertreiben. Mit einfachem Beispiel anfangen, später
komplizieren, noch später alles wegschmeissen und neu anfangen...
Marc Vesely schrieb:> Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,> werden entsprechende Flags gesetzt, unter anderem:
Jetzt erzähl ihm doch nicht so einen Scheiss.
Alex schrieb:> Wie würde der Code mit Interrupts aussehen? Kompliziert?
Eher einfacher. Aber Interrupts, genauer einen Interrupt, stehen erst an
zweiter Stelle.
Was du brauchst ist ein vernünftiges Timing, um deinem bisher frei
laufenden Controller Manieren beizubringen.
Dazu brauchst du einen Timer. Mit Hilfe dieses Timers führst du in der
Mainloop zyklisch diverse Aufgaben aus. Das kann man ganz einfach mit
einem Interrupt machen. Es geht aber auch ohne.
Eine dieser Aufgaben ist das Einlesen der Taster.
Arbeite nacheinander die Artikel zu Timern und zu Entprellung durch.
Wenn du es schaffst per Tastendruck eine Variable sicher hochzuzählen,
hast du die meisten Probleme, die dein Controller dir jetzt bereitet und
in Zukunft bereiten wird, gelöst.
mfg.
Thomas Eckmann schrieb:>> Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,>> werden entsprechende Flags gesetzt, unter anderem:> Jetzt erzähl ihm doch nicht so einen Scheiss.
Schon wieder schlechte Laune ?
Marc Vesely schrieb:> Interrupt wird auf fallende Flanke eingestellt
Wozu?
Drückst Du die Taste nicht, hast Du erstmal auch keine Interrupts.
Es sei denn, Du kommst mit dem elektrostatisch geladenen Pullover dem
Taster zu nahe. Dann hast Du Interrupts ohne Drücken.
Drückst Du die Taste, kriegst Du zwar Interrupts. Die Anzahl hat
allerdings nur entfernt mit der Anzahl der Drücke zu tun.
Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste
Lösungsversuch.
Hi
Was ist denn so schnell, das man taster mit Interrupts einlesen muss?
Was ist so kompliziert, das ein Delay von 50 ms für ein Entprellen von
Eingängen Probleme macht? Natürlich sind Timer irgendwann einmal
nützlich oder gar wichtig, doch dieses Vorhaben ist doch so banal, das
mit ein wenig nachdenken ein Programm nach meiner Anleitung durchaus
auch von einem blutigen Anfänger erstellt werden kann. K.H.B. hat es
ebenfalls gesagt, wie eine Flanke ermittelt wird. Wenn Bitmannipulation
kein Problem sind, wo ist dann das Problem? Alex, ich hab dir den Ablauf
erklärt. Ein Programm ist eine Endlosschleife und ackert immer wieder
die gleichen Befehle ab. Die Kunst ist nun zu erfassen, was sich ändert
und darauf zu reagieren. Ändern kann sich nur etwas von außen, also
werden erst mal Informationen eingelesen. Nun werden die Änderungen
untersucht und behandelt. Das ist die Verarbeitung und schließlich
wollen wir ja wissen, was nun das Ergebnis dieser Verarbeitung ist,
sowas nennt man dann Ausgabe oder kurz EVA-Prinzip. Nun kannst du
ellenlange ineinander verschachtelte Programme schreiben und dann den
Durchblick verlieren oder du machst eine Schleife in der du immer wieder
Routinen aufrufst, die Einlesen, Verarbeiten und Ausgeben. Da ich dir in
C nicht mit Code dienen kann, hab ich dir die Blöcke genannt, die du dir
zu Herzen nehmen solltest und auch, wie es funktioniert, das man einen
Eingang irgendwann in einem stabilen Status hat. Wie eine
Flankenerkennung aufgebaut ist und wie daraus eine Event- oder
Ereignisbearbeitung abgeleitet wird. Was du in der Ereignisbearbeitung
machst ist dein Job. Schau dir mal die Skizze an. Da wird deutlich, das
es keine Kunst ist, mit kleinen Programmblöcken ein umfangreiches
Programm zu schreiben, nur das du dabei die Übersicht nicht verlierst.
Grad als Anfänger solltest du dich mit diesen kleinen Aufgaben vertraut
machen.
Gruß oldmax
Peter Dannegger schrieb:>> Interrupt wird auf fallende Flanke eingestellt>> Wozu?>> Drückst Du die Taste nicht, hast Du erstmal auch keine Interrupts.
So soll es auch sein, was genau wolltest du andeuten ?
Peter Dannegger schrieb:> Drückst Du die Taste, kriegst Du zwar Interrupts. Die Anzahl hat> allerdings nur entfernt mit der Anzahl der Drücke zu tun.
Deswegen nimmt man Prellzeit und während dieser Zeit wird ISR zwar
angesprungen, aber auch gleich wieder verlassen.
Peter Dannegger schrieb:> Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste> Lösungsversuch.
Natürlich nicht.
Der arme Timer kann (und soll) nicht die ganze Arbeit übernehmen.
Bei mir schuftet der auch am meisten, aber ein einziges Flag, welches
in der Taster-ISR gesetzt wird, sagt ihm, dass er einen ganzen Code-
block überspringen soll.
Marc Vesely schrieb:> Der arme Timer kann (und soll) nicht die ganze Arbeit übernehmen.> Bei mir schuftet der auch am meisten
Ja, mein Timer beschwert sich auch ständig, daß er so wenig zu tun hat.
Wenn man ganz nah mit dem Ohr an den MC geht, ist ein leises Schnarchen
zu hören.
Die Entprellroutine braucht im Timerinterrupt 28 Zyklen für 1..8 Tasten.
Das sind zusätzliche 0,04% CPU-Last bei 10ms Timerrate und F_CPU = 8MHz.
Hat der Timer nichts anderes zu tun, kommen noch die 41 Zyklen
Interruptoverhead hinzu, das ergibt insgesamt stolze 0,09% CPU-Last.
Peter Dannegger schrieb:> Die Entprellroutine braucht im Timerinterrupt 28 Zyklen für 1..8 Tasten.> Das sind zusätzliche 0,04% CPU-Last bei 10ms Timerrate und F_CPU = 8MHz.
Mein Timer muss 10 Mal so viel schuften.
Ich kenne deine Entprellroutine, habe nichts daran auszusetzen, nur ist
diese Routine etwas, dass der TO verwenden, aber z.Zt. wahrschenlich
nicht ganz verstehen kann.
Was ich sagen will:
Wenn der TO etwas braucht das funktioniert, kann er deine Routine
nehmen. Wenn er aber etwas lernen oder selbst versuchen soll, ist die
Aussage:
"Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste
Lösungsversuch." nicht angebracht.
Erstens ist das nicht der Fall und zweitens, wie du selber sagst, dein
Timer feuert alle 10ms.
Flankeninterrupt reagiert aber nach 3-4 Taktzyklen und das kann
manchmal ziemlich wichtig sein.
Was aber wichtiger ist:
Timer arbeitet (bei mir) in Codeblocks, ohne zu wissen wie das alles
hardwaremässig funktioniert. Ein Flag bleibt ein Flag, auch wenn sich
entsprechendes PortPin oder sogar ganzes Port geändert hat. Oder man
einen Taster durch einen Lichtsensor ersetzt hat.
Man kann alles in Timer ISR abfragen, aber das wäre dann der denkbarungeeignetste Lösungsversuch. Deswegen hat ATMEL den neueren uC für
jedes Portpin ein PCI spendiert.
Timer ISR soll koordinieren, nicht die ganze Arbeit verrichten.
Marc Vesely schrieb:> Wenn er aber etwas lernen oder selbst versuchen soll, ist die> Aussage:> "Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste> Lösungsversuch." nicht angebracht.
Ist nur meine persönliche Erfahrung, daß externe Interrupts viel Ärger
machen und besonders für Anfänger deren Probleme schwer zu verstehen und
zu bereinigen sind.
Neben dem Prellen auch die ESD-Empfindlichkeit bei längeren Leitungen
oder zu Bedienelementen.
Und wenn man dazu doch noch den Timerinterrupt braucht, ist das auch von
der Software her deutlich aufwendiger.
Ich benutze externe Interrupts daher nur zum Aufwachen oder für
zeitkritische Sachen (externe Ethernet-, CAN-Controller).
Tasten sind aus MC-Sicht alles mögliche, aber nicht zeitkritisch.