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.
1 | #include "binary_numbers.h" |
2 | #define edge_detect 1
|
3 | #define level_detect 0
|
4 | |
5 | for (;;) |
6 | {
|
7 | if (((P5IN & b00000010) == 0) & (TasterRU != 0)) TasterRU--; |
8 | if (((P5IN & b00000100) == 0) & (TasterRO != 0)) TasterRO--; |
9 | if (((P5IN & b00001000) == 0) & (TasterLO != 0)) TasterLO--; |
10 | if (((P5IN & b00010000) == 0) & (TasterLU != 0)) TasterLU--; |
11 | if ((P5IN & b00000010) == b00000010) TasterRU = 0xFF; |
12 | if ((P5IN & b00000100) == b00000100) TasterRO = 0xFF; |
13 | if ((P5IN & b00001000) == b00001000) TasterLO = 0xFF; |
14 | if ((P5IN & b00010000) == b00010000) TasterLU = 0xFF; |
15 | |
16 | if (TasterRO == edge_detect) //1 = Flankenauswertung |
17 | {
|
18 | display_frame(1); |
19 | }
|
Ich hoffe, das hilft etwas, den Code zu strukturieren. Grüße, Peter
>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
> Dein Code entprellt mich.
Cool =) Kannst du mal beschrieben wie sich das anfühlt? Ich bin da mal
neugierig :D
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.