Hallo liebe Forenteilnehmer,
ich beschäftige mich zum ersten Mal mit GCC zur Programmierung eines µC
und brauche Hilfe, der Quelltext ist angehängt.
Das Programm soll später einmal ein externes Zeitsignal bekommen und
dieses per multigeplexten 7-Segmentanzeigen ausgeben und außerdem zwei
Stoppuhren (eine für kurze Zeiten im 2h-Bereich und eine für Zeiten bis
24h) betreiben.
Das angehängte Programm enthält alles notwendige, außer dem
UART-Empfang, jedoch habe ich wieder vieles auskommentiert um dem Fehler
auf die Schliche zu kommen, es sind also nur noch die konkreten Teile
vorhanden und der Fehler tritt immer noch auf.
Ich teste im Augenblick noch auf einem myAVR-Board, da die Schaltung
noch nicht fertig ist. Daran überprüfe ich die Pegel des Ports C mit den
LEDs, in der Simulation schaue ich sie mir direkt an. Die Taster habe
ich an Port-D 3 und 4 angeschlossen.
In der Simulation zeigt der Code das gewünschte Verhalten, nach der
Initialisierung bleibt Port-C dauerhaft auf 0x04, nach Setzen von PIN 3/
springt er auf 0x01 bzw. 0x02.
Das ganze auf den Atmel geflasht, leuchtet ganz kurz PORTC2 (Also Wert
4) auf, dann springt er auf PORTC0 (Also Wert 1), das Setzen von PIN4
führt zu einem Sprung auf PORTC1 (Also Wert 2), jedoch nur so lange, wie
der Taster gedrückt wird, danach erfolgt wieder der Sprung auf PORTC0
(Also Wert 1). PIN3 hat gar keinen Einfluss, offensichtlich wird also
immer zu Beginn eines Schleifendurchlaufs der Wert geändert und ich weiß
nicht warum.
Was ich mich frage, wieso funktioniert es im Simulator, aber nicht auf
dem Chip und was mache ich falsch? Ich habe die Funktionen auch schon
alle eingegliedert gehabt, ich habe die If-Funktionen umgekrempelt, etc.
aber ich komme auch mit verschiedenen Optimierungsoptionen nicht zum
gewünschten Ergebnis auf der Hardware.
Für eure Hilfe bedanke ich mich im Voraus, ich hoffe es ist ein simpler
Anfängerfehler, dem ihr schnell auf die Sprünge helfen könnt, falls ihr
weitere Infos braucht, lasst es mich wissen, dann versuche ich das nach
bestem Wissen bereitzustellen.
Die Abfrage der Taster ist nicht gerade übersichtlich und wie ich es,
ohne es komlett gelesen zu haben, sehe, auch ohne wirksame Entprellung.
keys = keys & PIND;
keycounter = keycounter + 1;
// CHR RESET
if(keycounter > 7)
{
if(keys & (1<<PIND3))
{
chr_reset();
}
usw...
Warum legst du nicht einfach für jede Taste eine Variable an, die du
runterzählst, wenn die Taste gedrückt ist. Wenn sie weit genug
runtergezählt ist, wertest du die Taste aus und zählst noch einmal
weiter runter, was signalisiert, dass sie nicht nocheinmal ausgewertet
werden soll. Wenn die Taste losgelassen wird, wird die Variable
zurückgesetzt. So mach ich das immer.
Beispielcode von einem MSP430 mit 4 Tasten; P5IN entspricht in deinem
Fall dem PIND, TasterXX sind Variablen mit 8 bit (unsigned char). Man
kann für jede Funktion zwischen edge_detect und level_detect auswählen.
Edge_detect wertet nur einmal aus beim Drücken, level_detect immer
wieder, solange man gedrückt hält.
>Die Abfrage der Taster ist nicht gerade übersichtlich und wie ich es,>ohne es komlett gelesen zu haben, sehe, auch ohne wirksame Entprellung.>>keys = keys & PIND;>keycounter = keycounter + 1;>// CHR RESET>if(keycounter > 7)>{>if(keys & (1<<PIND3))> {> chr_reset();> }>>usw...
Ich bin dabei dem Beispiel von hier gefolgt:
http://www.mikrocontroller.net/articles/Entprellung#Warteschleifenvariante_mit_Maske_und_Pointer_.28nach_Christian_Riggenbach.29
Was findest du daran unübersichtlich?
Die Funktion habe ich ursprünglich auch ausgegliedert gehabt, dann aber
für Testzwecke wieder in den Programmcode aufgenommen, in der Simulation
funktioniert sie auch, die Entprellung geschieht ja darüber, dass keys
in jedem Schleifendurchlauf mit dem Bit-Zustand logisch UND-verknüpft
wird, also bleibt ein Bit in keys nur eins, wenn der Taster gedrückt
war. Dies muss 8 mal hintereinander passieren, ist er in einem dieser
Durchläufe nicht gedrückt, wird keys ja einmal mit 0 verknüpft und
bleibt dann bis zum Reset (bei keycounter>7 wird keys=0xff und
keycounter=0 gesetzt). Durch den geschrumpften Programmcode ist die
Ausführzeit soweit zurückgegegangen, dass ich bei dem im Link
angegebenen Mindestwert von 150us rauskomme, doch auch mit dem gesamten
Code (dann liegt die Zeit bei etwa 1ms) tritt der exakt gleiche Effekt
auf.
Er springt offensichtlich in jedem Durchlauf in die Schleife und setzt
die Werte auf 1, auch wenn der Taster gar nicht angeschlossen ist, d.h.
da kann dann die Entprellung gar nicht Schuld sein.
Jedenfalls habe ich deinen Vorschlag aufgenommen, eingebaut und es
funktioniert jetzt auch, wie es soll, doch mir ist weiterhin
unerklärlich, weshalb der obige Code von mir nicht geht. Danke für die
Hilfe und falls mir jemand noch erklären kann, was da oben schiefläuft,
bin ich ihm auch dankbar.
Dein Code entprellt mich.
Dein Code überprüft lediglich bei jedem 7-ten Schleifendurchlauf, ob
eine Taste gedrückt ist. Das ist aber viel zu wenig, die Schleife läuft
viel zu schnell durch, als das dieses Zählen bis 7 irgendwas bewirken
würde.
Ich nehm immer die PeDa Methode (ebenfalls auf der von dir verlinkten
Seite). Die würde ich dir auch empfehlen. Hauptsächlich deshalb, weil du
ja sowieso zum Multiplexen der Anzeige einen regelmässigen Interrupt
einsetzen wirst. In dieser ISR kannst du dann nebenbei auch noch die
Tasten entprellen und hast dann auch noch den Vorteil, dass du zwischen
langen und kurzen Tastendrücken auch noch unterscheiden kannst.
> Ich bin dabei dem Beispiel von hier gefolgt:> http://www.mikrocontroller.net/articles/Entprellun...
Lies die Seite bitte ganz.
> die Entprellung geschieht ja darüber, dass keys> in jedem Schleifendurchlauf mit dem Bit-Zustand logisch UND->verknüpft wird, also bleibt ein Bit in keys nur eins, wenn der Taster> gedrückt war. Dies muss 8 mal hintereinander passieren,
Was dann nach einer einstelligen Zahl an Mikrosekunden erledigt sein
dürfte - lange bevor das Prellen überhaupt richtig begonnen hat.
>Dein Code entprellt mich.>Dein Code überprüft lediglich bei jedem 7-ten Schleifendurchlauf, ob>eine Taste gedrückt ist. Das ist aber viel zu wenig, die Schleife läuft>viel zu schnell durch, als das dieses Zählen bis 7 irgendwas bewirken>würde.
Die Überprüfung findet doch bei keys = keys & PIND statt, das wird doch
in jedem Durchlauf aufgerufen, nach dem siebten Schleifendurchlauf wird
dann nur überprüft, welche Taster in jedem der vergangenen Durchläufe
gedrückt war, ist das keine Entprellung? Oder habe ich da jetzt
>Lies die Seite bitte ganz.
Das habe ich getan, mit
>Entprellzeit von durchschnittlich 1-3ms (mindestens 8*150us = 1ms)
im Hinterkopf habe ich dann ja diese Auslegung gemacht:
>Was dann nach einer einstelligen Zahl an Mikrosekunden erledigt sein>dürfte - lange bevor das Prellen überhaupt richtig begonnen hat.
Laut der Simulation in AVR Studio nicht, ohne Optimierung brauchte da
der Code etwa 1000us, die kurze Fassung etwa 150us, also genau die im
Artikel erwähnte Zeit.
Deswegen jetzt nochmal der Hinweis, auch ganz ohne Schalter sprang er in
die Funktion die den Wert geändert hat, wenn ich diese rausgeworfen habe
sprang er in die nächste, wie kann es ganz ohne die entsprechenden Pins
überhaupt mit etwas zu belegen zu einem Input kommen, das verstehe ich
einfach nicht.
Tobias wrote:
> Die Überprüfung findet doch bei keys = keys & PIND statt, das wird doch> in jedem Durchlauf aufgerufen, nach dem siebten Schleifendurchlauf wird> dann nur überprüft, welche Taster in jedem der vergangenen Durchläufe> gedrückt war, ist das keine Entprellung? Oder habe ich da jetzt
Stell dir jetzt einfach mal vor, du drückst die Taste genau in dem
Moment, in dem keycdount gleich 6 (oder 7) ist. Bewirkt dein Konstrukt
dann noch irgendwas?
Entprellung bedeutet immer, dass beim ersten Erkennen einer Flanke
irgendein Prozess gestartet werden muss, der nach einer bestimmten Zeit
den endgültigen Tastenzustand feststellt.
Beim Erkennen einer Flanke muss eine Programmlogik starten. In deinem
Code ist nichts davon zu sehen.
> der Code etwa 1000us, die kurze Fassung etwa 150us, also genau die im> Artikel erwähnte Zeit.
Beim Prellen reden wir über Millisekunden, nicht µs!
Das ist ein mechanischer Vorgang! Die Kontaktzungen, die den Kontakt
herstellen, schwingen nach! Millisekunden sind für einen µC eine halbe
Ewigkeit.
> Deswegen jetzt nochmal der Hinweis, auch ganz ohne Schalter sprang> er in die Funktion die den Wert geändert hat> DDRD = 0x00; /* alle Pins von Port D als Eingang */
Ich weiß zwar nicht, wie deine Taster angeschlossen sind. Aber wenn du
keine Pullups aktiviert hast, bzw. extern keine Pullup oder Pulldown
Widerstände angeschlossen jast, darfst du dich nicht wundern, wenn sich
die Eingänge so ziemlich jede elektromagnetische Störung aus der näheren
Umgebung reinziehen und als Signal werten