Ich suche eine gute Portierung der Entprellung von Peter Dannegger für
ARM µC, da die ASF debouncing filter von Atmel nicht ausreichend sind.
Leider funktioniert der Link für die Portierung für den AT91SAM7 nicht
mehr.
Hat jmd eine bereits gut funktionierende Lösung zum "parallelen"
debouncing von Tasten ala Peter Dannegger für ARM programmiert?
Da ich bislang nicht wirklich eine zufriedene Lösung gefunden habe,
bastel ich gerade selbst eins mittels Button Handler und TC Handler.
Die Idee war, dass bei Tastendruck ButtonHandler ausgelöst wird und
dabei direkt erkannt wird welcher Button gedrückt wurde. Erst beim
Auslösen des Buttonhandlers wird der Interrupt für den Overflow des TC0
wieder erlaubt. So wird darüber die Taste entprellt. Sofern keine
erneute Signale ankommen wird der TC0 Interrupt wieder deaktiviert.
Allerdings erscheint mir das alles bisl umständlich, vll hat jmd bessere
Ideen :).
Wo ist das Problem?
Das ist doch plain C, also direkt portierbar.
Und der Interrupthandler kommt in den SysTick mit rein.
Der einzige Unterschied ist, daß ein Port wohl nicht 8bit, sondern 16
oder 32Bit breit sein wird, also die Typen entsprechend anpassen.
Nicht wenn ich die ASF von Atmel im allgemeinen nutze, bzw. habe das
Problem, dass die Tasten nicht alle an einem Port liegen, sondern an
unterschiedlichen. Ich kann nicht direkt mit Registern arbeiten sondern
muss Arrays von den Tasten erstellen, die wiederrum müsste ich in eine
binäre Zahl mit 8 Bit umwandeln.
Ich dachte, dass ich durch die Priorisierung der Interrupts das
Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi
nichts.
Nur eine LEDkette, die der Reihe nach an und aus geht, um zu gehen ob
nicht irgendwo eine Endlosschleife ist.
Habe einen Buttonhandler der sofort anspringt wenn ein Pegel anliegt.
Der wiederrum erlaubt TC0 Interrupts. Im TC0 Handler wollte ich die
Tasten entprellen und sobald kein Bedarf mehr ist, den TC0 Interrupt
wieder deaktivieren. Funktioniert nicht, da beim gedrückten Tastendruck
Systik nicht mehr ausgeführt werden kann. (So bei mir zumindest)
Daher muss TC Handler mit in Systick rein oder TC Handler entfernen und
über Systick entprellen?
Klingt ja wahnsinnig kompliziert gedacht.
Warum?
Ports lesen, alle xmsec, vergleichen alter und neuer Zustand der Ports,
auch öfters, ist der Zustand stabil dann die Änderung am Port als
Tastendruck interpretieren.
Elektrotiger schrieb:> habe das> Problem, dass die Tasten nicht alle an einem Port liegen, sondern an> unterschiedlichen.
Das ist kein Problem.
Du bastelst dann eben durch Schieben und Verunden einen 16Bit Wert aus
mehreren Portbits zusammen.
Bzw. wenn es mehr als 16 Tasten sind, einen 32 oder 64Bit Wert.
Elektrotiger schrieb:> Ich dachte, dass ich durch die Priorisierung der Interrupts das> Entprellen von Tasten seperieren kann.
Der Mensch ist schnarchlahm aus CPU-Sicht. Tasten kriegen, wenn
überhaupt, nur die ganz unterste Priorität.
Im einfachsten Fall garkeine, sondern der Systick macht alle 100ms die
super eiliegen Tastendrücke.
Ansonsten macht Tastenereignisse auswerten die Mainloop.
Peter D. schrieb:> Der Mensch ist schnarchlahm aus CPU-Sicht. Tasten kriegen, wenn> überhaupt, nur die ganz unterste Priorität.
Daher wollte ich das Entprellen auch mit einem TC Handler mit
niedrigster Priorität trennen.
Systick hat stets die höchste Priorität?
Habe aktuell das Problem, dass beim gedrückt halten der Taste gerade
permanent in Button Handler reinspringt, sodass ich meine LEDKette nicht
mehr bewegen sehe, obwohl Button Handler Priorität 5 hat :/.
Allerdings TC0 Handler mit Priorität 4 verarbeitet wird.
Systick wird bei mir jede ms angesprungen, da ich dieses später zur
Simulierung eines MRT Signals so genau brauche. Nun möchte ich ungern im
Systick anfangen eine Variable hoch zu zählen bzw runter um dann über
systick das Entprellen der Tasten zu steuern. Da später ggf mehr im
Systick stehen wird, würde ich es gerne seperieren.
Peter D. schrieb:> Schieben und Verunden
Und ich wollte schon mit 2^n rechnen :D... an shiften habe ich nicht
mehr gedacht. Werde morgen mein Code auf deinen anzupassen.
Dennoch würde ich mich freuen zu verstehen wieso ich meine Interrupts
nicht so getimet bekomme ich wie ich es mir vorstelle.
Danke :)
Elektrotiger schrieb:> Ich dachte, dass ich durch die Priorisierung der Interrupts das> Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi> nichts.
Oh mann, das schmerzt ja beim Lesen. Von wegen "Elektrotiger" ...
Eigentlich ist es ja so unsäglich einfach:
1. man tastet die betreffenden Portpins zyklisch ab, sowas macht man am
sinnvollsten im Systick, der nebenbei auch noch die System-Uhrzeit
führt, so daß man davon zeitabhängige Funktionalitäten ableiten kann.
2. beim allerersten Erscheinen eines Tastendruckes kann und soll man
dies als Tastendruck-Ereignis an den Rest der Firmware weiterleiten.
3. ab einem erkannten Tastendruck muß man anschließend so lange keine
neuen Tastendrücke aus dem Tastenzustand herleiten, bis die betreffende
Taste für eine bestimmte Zeit AM STÜCK als ungedrückt erkannt wurde.
Zumeist reicht hier 50..80 ms dicke aus. Fakultativ kann man bei länger
als eine bestimmte Zeit gedrückt gehaltener Taste ein Repetieren
veranstalten. Als erste Repetierzeit ist ne Sekunde ganz gut, folgende
repetierzeiten dann deutlich kürzer.
Wo ist das Problem, sowas in aller Kürze als Quelltext hinzuschreiben?
Ich geb dir mal ein Beispiel:
#define LangeRepZeit 80
#define KurzeRepZeit 10
#define EntprellZeit 6
byte Old, Rep;
bool tastenrepetieren;
... alle 10 ms:
L = PORT; // Port lesen
if (!(L & (1<<Tastennummer))) // Taste gedrückt ?
{ if (!Old) // war vorher ungedrückt
{ Rep = LangeRepZeit;
Add_Event(idDieseTaste);
}
else
if (tastenrepetieren)
{ --Rep;
if (!Rep)
{ Rep = KurzeRepZeit;
Add_Event(idDieseTast);
}
}
Old = EntprellZeit;
}
else
{ if (Old) --Old; } // entprellen
.. so etwa und fertig. Wie man das per Schleife auf N Tasten erwitert,
sei dir überlassen.
W.S.
Elektrotiger schrieb:> Habe aktuell das Problem, dass beim gedrückt halten der Taste gerade> permanent in Button Handler reinspringt
Der Trick an meiner Entprellung ist natürlich, daß sie nur die Flanke
als Event ausgibt.
Egal wie lange Du drückst, es gibt nur genau ein Event (ohne
Repeatfunktion).
Erst nach Loslassen kann ein erneutes Drücken ein weiteres Event
generieren.
Durch die Eventsteuerung ergibt sich auch eine Entkopplung zwischen
Drücken und Auswertung. D.h. auch wenn die Mainloop mal etwas busy ist,
geht ein kurzes Drücken nicht verloren.
Bei vielen kommerziellen Geräten nervt es total, daß ständig Drücke
verloren gehen, solange es noch mit der vorherigen Aktion beschäftigt
ist.
Ich verstehe nicht wie ich die Pins unterschiedlicher Ports in ein
Register bzw integer Variable speichern kann?
Die Pins zeigen doch nur ihren Pegel High:1 und Low:0 an.
Ich müsste die Zeiger auf die Pins in ein Array packen? Wenn ich dies
wieder in ein integer Variable wie ein 8 Bit Register arbeitet,
speichern würde, dann verliere ich doch den Bezug zu den Pins und habe
nur noch die Pegel :/? Hier dürft ihr mir auf die Finger hauen^^
W.S. schrieb:> Oh mann, das schmerzt ja beim Lesen. Von wegen "Elektrotiger" ...
Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine
Ohrfeige geben! Dieser Bereich gehört erstens eher zur Informatik bzw.
zur technischen Informatik. 2. verurteile nicht einfach solche User, ich
selbst studiere an der RWTH Aachen im 6. Semester. Kann dir
Elektromagnetische Wellen im freien Raum, Materie und Leitern
berechnen....
W.S. schrieb:> 1. man tastet die betreffenden Portpins zyklisch ab, sowas macht man am> sinnvollsten im Systick, der nebenbei auch noch die System-Uhrzeit> führt, so daß man davon zeitabhängige Funktionalitäten ableiten kann.
Die Idee hinter dem Algorithmus habe ich verstanden, hier mein Code.
Allerdings habe ich durch ASF gerade das Problem die Pins/Ports sinnvoll
in einem "Register" bzw. 8Bit integer Variable sinnvoll zu verpacken.
Dabei habe ich Tasten an bis zu drei unterschiedlichen Ports. Daher
hatte ich überlegt meine Pins in Arrays zupacken und mit einander zu
vergleichen. Das wird wirklich eine "schmerzliche, dumme" Lösung sein,
daher frage ich hier nach...
tc interrupt wird wieder erlaubt, sobald im Button_Handler ein
Tastendruck registriert wird und direkt im Array gespeichert.
Peter D. schrieb:> Bei vielen kommerziellen Geräten nervt es total, daß ständig Drücke> verloren gehen, solange es noch mit der vorherigen Aktion beschäftigt> ist.
Daher ist deine Idee und vorallem Codeumsetzung sehr gut :). Danke
Peter D. schrieb:> Der Mensch ist schnarchlahm aus CPU-Sicht.
Aber 100 ms ist auch für einen Menschen schon recht lang. Mit einer
gutgehenden Morsetaste könnte man in 100 ms gut und gern wenigstens
zwei komplette Tastendrücke unterbringen. ;-) Klar, Morsetasten
dienen üblicherweise nicht als Eingabegeräte an Controllern, aber ein
wenig schneller als 100 ms darf man schon reagieren, sonst kommt es
dem Bediener „zuckelig“ vor.
Elektrotiger schrieb:> Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine> Ohrfeige geben!
W.S. war schon immer ein ungehobelter Klotz. Dabei schafft er's
nicht einmal, ein paar simple Code-Tags in seinen Beitrag zu
tippen, sodass sein Code völlig unleserlich ist (zumindest für
diejenigen, die die Fließschrift-Version des Forums nutzen). Ignorier'
ihn einfach, wenn er dich stört, dann kann er vor sich hin blubbern, wie
er will. Mit Peter hast du allemal nicht nur einen kompetenten
Diskutanten, sondern auch einen, der ein vernünftiges Benehmen an den
Tag legen kann.
Elektrotiger schrieb:> Ich verstehe nicht wie ich die Pins unterschiedlicher Ports in ein> Register bzw integer Variable speichern kann?
Z.B. 8 Tasten an P0.0, P0.1, P0.2, P0.3, P1.3, P2.3, P2.4, P2.6, dann:
Jörg W. schrieb:> aber ein> wenig schneller als 100 ms darf man schon reagieren, sonst kommt es> dem Bediener „zuckelig“ vor.
Dann kennst Du Heimelektronik nicht.
Wenn ich bei meinem HDD-Rekorder im Menü die ">" Taste drücke, dann
dauert es ewig, eh mit viel Getöse (Animation) der Kursor auf den
nächsten Menüpunkt schleicht.
Und erst dann darf man wieder auf ">" drücken.
Bei nur 100ms könnte ich mein Glück kaum fassen. Dann könnte man ja
blind bedienen, wenn man die Tastenfolge schon kennt.
Peter D. schrieb:> Dann kennst Du Heimelektronik nicht.
Du musst ja nun nicht die schlechten Beispiele als Vorbild nehmen,
wenn du auch weißt, dass man es besser machen kann. ;-)
Konrad S. schrieb:>> ... P1.3 ...>> ... ((P1 & 0x10)<<3) ...>> ?
Genau darin dürfte die Fratzenfalle liegen, wenn man das einfach
„zu Fuß“ codiert.
Etwas sauberer könnte man es mit einer Union schreiben, die zum einen
einen 32-bit-Integer enthält (den du in den Algorithmus reinwerfen
kannst), zum anderen eine Bitfield-Struktur, mit der man sich die
einzelnen Bits aus den gelesenen Ports zusammenfummelt. Das ist
zwar nicht 100% portabel gemäß Standard, sollte aber für den
Hausgebrauch
allemal genügen, und man überlässt es dem Compiler, die Bits an die
richtige Stelle ohne Überlappungen zu sortieren.
Peter D. schrieb:> Z.B. 8 Tasten an P0.0, P0.1, P0.2, P0.3, P1.3, P2.3, P2.4, P2.6, dann:> uint8_t val = (P0 & 0xF) | ((P1 & 0x10)<<3) | ((P2 & 0x58)<<1);
Klasse danke :). Glaube du meintest P1 & 0x03 in Hexa 10 wäre es in
Binär?
Bzw weil der erste Eintrag der Px.0 ist müsste man hier 0x04 nehmen?
0x04 = 4*16^0 = 4 = 2^2 = (00100000) in binär
0x58 = 88 = 2^6 + 2^4 + 2^3 = (000110100) in binär
Hier passt es :).
Ist das so richtig? z.B. zweiter Eintrag: PA11 ist der 12. Pin, also
somit das 12. Bit am PortA. 12 = 0x0C . Diesen möchte ich im selbst
gebastelten button_register am zweiten Bit setzen. Muss ich jetzt um 10
Schritte shiften oder 11?
PIOA auf dem ARM ist ein Zeiger auf eine Struktur.
Du musst stattdessen das Eingaberegister der jeweiligen PIO benutzen.
Was für einen SAM benutzt du? Auf den älteren (SAM3/4) wäre das
das Register PIOA->PIO_PDSR (pin data status register).
Auf den neueren (SAMD und Verwandte) gibt es PIOA eigentlich gar
nicht direkt, sondern dort müsste man PORT->Group[0].IN.bit.IN
einlesen. (Zuweilen habe ich aber auch schon #defines gesehen, die
PORT->Group[0] als PIOA abkürzen.)
Edit: in deinem Beispiel liegt jetzt doch alles an PIOA, oder fehlt
da noch was?
Jörg W. schrieb:> in deinem Beispiel liegt jetzt doch alles an PIOA, oder fehlt> da noch was?
ne eins liegt an PIOD: PD25,
Benutze das evoltionboard, da sind die extensions vorgegeben und meine
Beschaltung an den Extensions war nicht zu ende gedacht^^.
Aber grundsätzlich hatte ich das Problem schon öffter, von
unterschiedlichen PIOs Pins sinnvoll in ein Register ala AVR
zsmzufassen.
Da die Bits auf den beiden Ports, die du benötigst, sich nicht
überlappen, kannst du die für deinen internen Status einfach
verODERn (PD25 ist disjunkt von allen Bits auf PIOA). Im Ergebnis
hast du dann einen „schwach besetzten“ 32-bit-Integer, mit dem du
in Peters Algorithmus reingehst. Das auf 8 Bit herunter zu
„komprimieren“, hat auf dem 32-bit-Prozessor sowieso keinen Sinn,
also rechnest du einfach den kompletten Entprellalgorithmus mit
32 Bits durch.
Beim ARM muß man nicht mit RAM geizen, sondern kann alle Variablen und
Funktionen uint32_t machen.
Und die Tasten müssen auch nicht lückenlos sein, man wählt sie ja eh
über Bitmasken aus.
Z.B.:
Elektrotiger schrieb:> Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine> Ohrfeige geben! Dieser Bereich gehört erstens eher zur Informatik bzw.> zur technischen Informatik. 2. verurteile nicht einfach solche User, ich> selbst studiere an der RWTH Aachen im 6. Semester. Kann dir> Elektromagnetische Wellen im freien Raum, Materie und Leitern> berechnen....
Ach Ohrfeigen willst du verteilen - wieso eigentlich? Was meinst du, was
unsereiner sich dabei denkt, wenn er sowas lesen muß:
Elektrotiger schrieb:> Ich dachte, dass ich durch die Priorisierung der Interrupts das> Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi> nichts.
Ich sag dir, was ich mir dabei denke: Der Junge hat sein Problem nicht
im Mindesten durchdacht und kommt erwiesenermaßen mit Peters
Entprellroutinen nicht zu Potte, weswegen er hier hilflos auftaucht -
aber er spuckt große Töne, unangemessen große Töne. Ein Elektrotiger,
der zum großen Sprung angesetzt hat und als Elektro-Bettvorleger
gelandet ist. Geht es nicht ein wenig bescheidener, wenn man nix weiß
und fragen muß? Also ein Danke für eine funktionable (allerdings aus dem
Handgelenk geschüttelte) Entprellroutine anstelle angedrohter Ohrfeigen?
p.s.: "SEPARIEREN"
Wäre ich dein Professor, dann würde ich dir zu etwas mehr Systematik
beim Systemkonzept raten.
So, das sollte genug sein. Wenn du mal sehen willst, wie man eine ganze
Tastenmatrix entprellt, dann guck in die mittlerweile steinalte
Lernbetty.
Und zu Peter und seiner Erfahrung mit Heimelektronik: Ja, die deutliche
Lahmheit vieler Geräte kenne ich auch, ich kann dir das nachfühlen.
Insbesondere DVD-Player. Wir hatten das Thema doch neulich schon mal:
Die Hälfte meiner Anwender drischt auf die Tasten, was eine Schließzeit
in der Nähe von 10..30 ms ausmacht - nicht mehr. Abhilfe: 100 nF oder
etwas mehr über die Tastenkontakte, die Ungleichheit zwischen
niederohmiger Entladung und Wiederaufladung per 22k Hochzieher sorgt
dafür, daß man trotzdem zu auswertbaren Signalen kommt.
W.S.
W.S. schrieb:> Die Hälfte meiner Anwender drischt auf die Tasten, was eine Schließzeit> in der Nähe von 10..30 ms ausmacht
Dann einfach das Timerintervall auf 25ms hochsetzen, d.h. alles <100ms
wird unterdrückt.
Sollst mal sehen, wie schnell die Leute manierlich mit den Tasten
umgehen, was sich positiv auf die Haltbarkeit der Tasten auswirkt.
Nicht immer muß man teure vandalensichere Tasten verwenden.
Elektrotiger schrieb:> Hat jmd eine bereits gut funktionierende Lösung zum "parallelen"> debouncing von Tasten ala Peter Dannegger für ARM programmiert?
Das Prinzip des Entprellen ist weder schwer noch kompliziert. Wer auf
einem 32'Bitter rumbastelt sollte das eigentlich selber können. Vor
allem wenn er offensichtlich schon einen funktionierenden Algorithmus
vorliegen hat den er nur noch etwas anpassen muss.
Thomas H. schrieb:> Wer auf einem 32'Bitter rumbastelt sollte das eigentlich selber können.
Nachdem es hier schon deutlich konkreter geworden war, was meinst du,
welche großartige „Hilfe“ dieser dein Beitrag für den TE wohl ist?
Eine derartige Antwort hätte ich ja vielleicht noch als erste Antwort
im Thread verstanden, aber zwei Tage und 25 Beiträge später ist sie
einfach nur Gelaber.
Jörg W. schrieb:> Eine derartige Antwort hätte ich ja vielleicht noch als erste Antwort> im Thread verstanden, aber zwei Tage und 25 Beiträge später ist sie> einfach nur Gelaber.
Selbstverständlich ist und war die "Antwort" provokativ gemeint, ob am
Anfang, oder zum aktuellen Zeitpunkt. Und auch nach der ganzen
Diskussion sehe ich immer noch kein Problem in dem Entprellen. Das
Prinzip ist und bleibt simpel. AFS und verteilte Pin's hin und her. Die
Provokation geht in die Richtung, dessen was ich hier ständig beobachte.
Die Leute verlernen heutzutage das eigenständige Denken und Problem
lösen. Selbst beim lösen schulischer oder universitärer Aufgabenstellung
wird das verwenden bereits vorhandener Lösungen oder der Gehirnschmalz
anderer bevorzugt anstatt sich selbst mal mit einem Blatt Papier einem
Bleistift und vielen Stunden Ruhe hinzusetzen und das Problem selber
aufzurollen. Das mag auch der Grund sein, warum es eine Menge
kommerzieller Geräte am Markt gibt in denen das mit dem Entprellen nicht
richtig funktioniert.
Thomas H. schrieb:> Das Prinzip ist und bleibt simpel.
Trotzdem steckt der Teufel eben manchmal im Detail, und es ist
durchaus sinnvoll, eine vorhandene und gut erprobte Lösung zu
verstehen und dann zu verwenden, statt das Fahrrad jedesmal neu
zu erfinden und dabei die Fehler, die andere in der Vergangenheit
gemacht haben, alle nochmal zu durchlaufen.
Eine Taylor-Reihe ist auch simpel, trotzdem implementierst du dir
deine Winkelfunktionen sicherlich nicht jedesmal neu, oder?
Klar hat der TE anfangs eine gewisse Faulheit an den Tag gelegt, aber
seine späteren Beiträge zeigen, dass er zumindest versucht hat, da
mitzudenken. Ich hoffe, dass er nun die Denkpause seit gestern nutzt,
um vielleicht endlich auch noch bitweise Logik zu verstehen. ;-)
Ich weiß nicht warum hier so viele auf den Algorithmus eingehen.
Vielleicht habe ich mich auch falsch ausgedrückt.
Meine Problematik war und ist es immmer noch die saubere Implementierung
in ein 32Bit µC. Das erscheint mir noch peinlicher als den Algorithmus
nicht zu verstehen.
Leider weiß ich jetzt nicht mals genau wo ich was falsch denke :/.
Hier meine Implementierung, die leider nicht funktioniert, es wird
einfach kein Tastendruck wahrgenommen.
Habe hoffentlich alles wichtige hier aus meinem Programm
rausgeschnitten.
button_register entspricht KEY_PIN, button_repeatmask dem REPEAT_MASK
aus Peters Implementierung. Ich hätte gerne button_register vor der ISR
zugewiesen, was allerdings zu Fehler führte, daher definiere ich es
direkt am Anfang des Mainprogrammes.
W.S. schrieb:> Ich sag dir, was ich mir dabei denke: Der Junge hat sein Problem nicht> im Mindesten durchdacht und kommt erwiesenermaßen mit Peters> Entprellroutinen nicht zu Potte
Die Problematik habe ich mir schon früher in AVR durchdacht gehabt. Hier
bekomme ich die Anpassung einfach nicht hin. Wo möglich zu wenige C
Kenntnisse.
W.S. schrieb:> Geht es nicht ein wenig bescheidener, wenn man nix weiß> und fragen muß?
? Beziehst Du Dich vll allgemein auf alle Nutzer hier und weniger auf
mich? Ich sehe hier von meiner Seite aus keiner Provokation, bis auf
meiner Reaktion auf Deinen mehr als unangenehmen Post und geprahlt habe
ich erst recht nicht... wie auch wenn ich nicht mals einen Algorithmus
richtig implementieren kann bzw einbinden kann :D......
Sorry für die späte Antwort, eine Hochzeit 800km ferne, ließ dies
weniger zu...
Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal
außen vor und schreibst dir zum entprellen einfach fürs erste selbst
eine Routine und im zweien Schritt gehst Du hin und versuchst dich damit
einen nicht selbst erdachten und verstandenen komplexen Code auf eine
andere Architektur anzupassen.
Thomas H. schrieb:> Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal> außen vor und schreibst dir zum entprellen einfach fürs erste selbst> eine Routine
habe ich, die auch nicht funktioniert -.-... siehe oben zwischen Post:
Elektrotiger schrieb:> int main (void)> {> button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 |> PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR &> PIO_PD25);
Im AVR-Code steht das Einlesen doch in der ISR.
Warum wohl?
Elektrotiger schrieb:> if( get_key_press(1 << ((PIOA->PIO_PDSR) & PIO_PA16))
PIOA->PIO_PDSR ist aber keine Bitmaske.
Wozu definierst Du dann BUTTON_xx_MASK, wenn Du sie nicht benutzt?
Elektrotiger schrieb:> button_register entspricht KEY_PIN
Klar. Zu dem Zeitpunkt, da main() startet. Danach werden die Pins
nie wieder eingelesen …
Ein bisschen solltest du schon verstehen, was bei deinem Controller
der physische Zugriff auf die Peripherie ist und was nur eine dumme
Variable, in der man sich was merken kann.
Elektrotiger schrieb:> Thomas H. schrieb:> Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal> außen vor und schreibst dir zum entprellen einfach fürs erste selbst> eine Routine>> habe ich, die auch nicht funktioniert -.
Das ist genau was ich vermutet habe. Du hast deinen Controller noch
nicht richtig im Griff. Das solltest Du aber zuerst einmal hinbekommen.
Dann komplexe Dinge, dann fremden Code portieren.
Elektrotiger schrieb:> #define LED0 IOPORT_CREATE_PIN(PIOA, 25)> ...> static uint8_t outputs[] = {LED0,
Ich kenne das Macro nicht, geht das im Array überhaupt und was willst Du
damit bezwecken?
Ich denke nicht, daß das Entprellen Dein vorrangiges Problem ist,
sondern eher das Verständnis von C.
Schreib erstmal ein Programm, was einfach nur die Tasten auf die LEDs
ausgibt.
Habe button_repeatmask noch nicht zugewiesen -.-'.
Diese müsste einfach einmal ganz am Anfang zu button_register zu
gewiesen werden?
In AVR waren es die PINs, die wiederholt betrachtet werden sollen. Da
wurde es per #define definiert.
Hier reicht es wenn ich es einmal vor bzw nach Systick definiere?
Elektrotiger schrieb:> 1 << BUTTON_RIGHT_MASK
Mannomann! Was steht da rechts drin?
"MASK"
Warum zum Geier™ schiebst du die (Bit-)Maske denn dann nochmal durch
die Botanik?
Elektrotiger schrieb:> Diese müsste einfach einmal ganz am Anfang zu button_register zu> gewiesen werden?
Das button_register brauchst du nicht global. Das ist eine
Zwischenvariable, die in die ISR gehört.
> In AVR waren es die PINs, die wiederholt betrachtet werden sollen. Da> wurde es per #define definiert.
Warum willst du sie hier nicht einfach auch per #define festlegen?
Aber Thomas Holmes hat schon recht: du solltest erstmal mit deutlich
kleineren Brötchen anfangen. Spiegele den Zustand einer der Tasten
in einer Endlosschleife auf eine der LEDs. Vielleicht verstehst du
ja damit besser, wie die PIO des SAM4 so „tickt“, als durch trial &
error.
Eigentlich solltest du den ASF-Krempel gleich noch mit entsorgen, denn
der scheint dem Verständnis des Controllers alles andere als förderlich
zu sein. Am Ende ist es sowieso nur eine umständliche Variante, um
über viele viele Schichten ein paar Bits in Steuerregistern zu
modifizieren.
Peter D. schrieb:> Elektrotiger schrieb:>> #define LED0 IOPORT_CREATE_PIN(PIOA, 25)>> ...>> static uint8_t outputs[] = {LED0,>> Ich kenne das Macro nicht, geht das im Array überhaupt und was willst Du> damit bezwecken?
Dies ist aus der ASF von Atmel. Das Array war nur dazu da um alle
Eingangs- bzw Ausgangspins über eine Schleife zu definieren:
Elektrotiger schrieb:> Das ist mit der ASF relativ einfach.
Genau. Nur, dass du anschließend nach wie vor immer noch nicht
weißt, was du tust.
Das ist wie, wenn du auf den Hinweis, erstmal geradeaus fliegen zu
lernen antortest: „Das ist mit dem Autopiloten ganz einfach.“
Ja, beim SAM3/4 ist es halt ein wenig umständlicher. Dessen PIO
hat zwar allen möglichen Furz und Feuerstein eingebaut (bis eben hin
zu einer Entprellung in Hardware, die dir am Ende doch bloß nicht
ausreicht), aber sie fühlt sich ansonsten deutlich wie aus dem
vorigen Jahrtausend an: ein Register zum Setzen von Pins, eins zum
Löschen von Pins, den aktuellen Status liest man aus einem dritten
Register aus …
Kommt hinzu, dass du dich an dieses blöde „Ich muss mir meine Bitmaske
selbst erstellen“-Konzept des AVR (1<<KEY_unten) so sehr gewöhnt hast,
dass du das nun krampfhaft auf alles andere anwenden willst. PIO_PA11
auf dem SAM4 ist aber bereits eine Bitmaske. (Hätte man auch auf dem
AVR besser so definieren sollen, und dann den Assembler die Maske in
eine Bitnummer rückrechnen lassen für das bisschen SBI/CBI, aber das
haben sie halt beim AVR seinerzeit versaubeutelt, und stattdessen
Generationen von Programmierern mit diesem 1<< sich herumärgern lassen.)
Du musst dir einfach mal aus den zugehörigen Headerfiles die
lowlevel-Details ansehen, wenn du lowlevel-Funktionalität implementieren
willst, wie es die Tastenentprellung nun einmal ist.
Und ich würde fürs erste auch empfehlen nicht gleich in die vollen zu
gehen, sondern
1 Taste, 1 LED
in deinem ganzen Code-gewusel sieht man ja vor lauter 'gleichzeitig alle
Pins bedienen'-Wollen gar nicht mehr, was du da alles eigentlich tust.
> Die Verknüpfung hier mit dem fertigen ASF mit AVR... die ist mein> Problem.
Das glaub ich nicht, Tim.
Dein Problem ist, dass du nicht eine Zuordnung von gedrückter Taste zu
LED-Leuchten machen willst, sondern die Zurodnung "1 Tastendruck ->
Umschalten des Zustandes der LED".
Denn dazu, und nur dazu brauchst du eine Entprellung. Solange die LED
leuchten soll, solange der Benutzer auf der Taste eingeschlafen ist,
solange brauchst du auch keine Entprellung. Und dann reicht auch die ASF
Lösung.
Also stell dich nicht dümmer als du bist und vertrau auf das, was dir
erfahrene Programmierer raten.
Jörg W. schrieb:> Kommt hinzu, dass du dich an dieses blöde „Ich muss mir meine Bitmaske> selbst erstellen“-Konzept des AVR (1<<KEY_unten) so sehr gewöhnt hast,> dass du das nun krampfhaft auf alles andere anwenden willst. PIO_PA11> auf dem SAM4 ist aber bereits eine Bitmaske.
Goldrichtig. Ich hatte gehofft mit den lowlevel-details aus AVR direkt
auf ARM anwenden zu können oder sogar mit Hilfe der ASF die
lowlevel-details komplett umgehen zukönnen indem ich nur die Pins
zuweise...
Aber dem ist wohl leider nicht so.
Eine gründliche Entprellung ist zwingend notwendig um wie bei meinem AVR
µC später via Tasten Signale mittels Display zu steuern und ein zu
stellen.
Mittels Tasten wird ein Menü gesteuert. Zähler beim gedrückthalten
hochgezählt usw...
Dazu ist die Entprellung über ASF einfach zu schlecht.
Danke für die Ratschläge und Mühen. Ich werde mich erst mal auf die
Lowprogrammierung des ARMs einlassen und mich später wohl nochmal
melden.
Elektrotiger schrieb:> uint32_t button_repeatmask, button_register;> button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 |> PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR &> PIO_PD25);
Jetzt hast du aber das Kind mit dem Bade ausgeschüttet.
Bekommst du keine Warnung vom Compiler dafür, dass du eine
button_repeatmask benutzt, obwohl du ihr nichts zugewiesen hast
und sie eine auto-Variable ist?
Versuch doch erstmal alles (wie Karl Heinz schon schrieb) mit einer
Taste, ohne Auto-Repeat, und einerLED.
Jörg W. schrieb:> Versuch doch erstmal alles (wie Karl Heinz schon schrieb) mit /einer/> Taste, ohne Auto-Repeat, und einerLED.
Das Konzept, Problemstellung erst einmal so zu vereinfachen (ohne
Beschränkung der Allgemeinheit, wie die Mathematiker sagen würden), dass
man es auch stemmen kann und sich mit dem Prinzip vertraut macht,
scheint immer mehr aus der Mode zu kommen.
Karl H. schrieb:> Das Konzept, […]> scheint immer mehr aus der Mode zu kommen.
Nö, auch dahin, dass dieses Konzept eine sinnvolle Vorgehensweise ist,
muss man halt per Erkenntnisprozess hinkommen. :)
Jörg W. schrieb:> Bekommst du keine Warnung vom Compiler dafür, dass du eine> button_repeatmask benutzt, obwohl du ihr nichts zugewiesen hast> und sie eine auto-Variable ist?
Das ist das Problem wenn ich zu viele Funktionen in einem Prgramm habe
und gerade nicht nutze... da werden die Warnungen wegen unbenutzte
Funktionen ignoriert...
Da ich zu nächst alle Button als Repeatbutton nutzen möchte habe ich nun
in der isr dies hinzugefügt:
Elektrotiger schrieb:> Das ist das Problem wenn ich zu viele Funktionen in einem Prgramm habe> und gerade nicht nutze... da werden die Warnungen wegen unbenutzte> Funktionen ignoriert...
Dann schmeiss sie raus!
Es ist sowieso ein Unsinn zu denken, man könne gerade als Anfänger
Funktion an Funktion heften und das würde auf Anhieb funktionieren.
Programme werden schrittweise entwickelt.
Man beginnt mit einer leeren main() und arbeitet sich einen Schritt nach
dem anderen vor.
Nur Anfänger kopieren ihren Code aus dem vorhergehenden Projekt und
denken, dass sie mit ein paar geringfügigen Änderungen ein vollkommen
neues Programm schreiben könnten. Aber alles was jetzt zur Zeit im Code
steht ist unantastbar und bleibt dort stehen - ob es wer braucht oder
nicht.
> button_repeatmask = button_register;
nein.
In der Variablen button_repeatmask steht genaus wie in der AVR Version
eine Bitmaske, die angibt, für welche Buttons überhaupt ein Repeat
durchgeführt werden soll. Für eine Taste 'Links' kann ein Autorepeat
sinnvoll sein, für eine Taste 'Enter' aber mglw. nicht. Genau das will
man einstellen können.
Das ist aber eine Vorgabe und hat nichts damit zu tun, welche Buttons
aktuell zur Zeit jetzt gerade hedrückt oder nicht gedrückt sind.
Wenn du nichts anderes hast, dann setz die Variable einfach auf 0. Dann
ist erst mal für keine einzige Taste ein möglicher Repeat aktiviert.
PIO haben diverse Attribute hier die wohl vorerst wichtigen:
PIO_ELSR : Edge/LvL Status Register
PIO_LSR : Level Select Register
PIO_PDSR : Pin Data Status Register
PIO_PSR: PIO Status Register
PIO_OER: Output Enable Register
PIO_ODR: Output Disable Register
PIO_OWER: Output Write Enable
Nun will/soll ich eine LED ohne ASF ansteuern, als Kommentar wäre
jeweils der Code von der ASF:
Habe Problem bei der Überlegung wie ich den Pegel der Rechten Taste
abfrage. mit PIOA->PIO_LSR habe ich das Level Register von PIOA, davon
will ich nur den Pin von Butten_Right, daher habe ich das Logische und
Verknüpft... Ist wohl so falsch, da es nicht klappt^^.
wohl falsch.
Mich beschleicht schön langsam das Gefühl, wir sind hier an einem Punkt
angelangt, an dem du nur noch im Forum nachfragst und nicht mehr
eigenständig erst mal deinen Code kritisch unter die Lupe nimmst.
Sorry, das muss natürlich die Mask sein, so wie es dadrüber auch
stand......
Karl H. schrieb:> Mich beschleicht schön langsam das Gefühl, wir sind hier an einem Punkt> angelangt, an dem du nur noch im Forum nachfragst und nicht mehr> eigenständig erst mal deinen Code kritisch unter die Lupe nimmst.
Ja und nein, ich hatte gehofft dass sich jetzt alle Knoten lösen...
Tuts aber nicht.
nicht funktionieren.
Dir scheint nicht klar zu sein, dass diese Tastenerkennung und
Entprellung deine Tasten insofern überwacht, dass sie einen Tasten-DRUCK
erkennt. Also das einmalige Ereignis des Niederdrückens einer Taste.
Genau das macht der Teil in der ISR. Er wertet den aktuellen Zustand der
Portpins aus und hinterlässt sich in der Variablen key_press die
Information, dass eine Taste niedergedrückt wurde.
Die Funktion get_keypress macht nichts anderes als in dieser Variablen
nachzusehen, ob ein derartiges Niederdrück-Ereignis registriert wurde
oder nicht. Wenn ja, dann meldet sie das und löscht gleichzeitig dieses
Ereignis.
Das heisst: im Endeffekt läuft es darauf hinaus, dass nach dem der
Benutzer eine Taste gedrückt hat, get_keypress genau 1 mal TRUE zurück
liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem
Tastendruck eine Aktion einmalig auslösen will.
In deinem Fall schaltest du eine LED ein. Aber ein paar Hunderstel-µs
später ist dieser Tastendruck dann eben auch schon wieder Geschichte,
get_keypress wird FALSE liefern und die LED wird in deinem Code gleich
wieder ausgeschaltet. Fazit: die LED wird ein paar Hunderstel oder
Zehntel µs lang brennen, d.h. eigentlich mehr kurz aufflackern. Viel zu
kurz, als das du das sehen kannst. Ok, wenn es sehr dunkel ist, du
konzentriert direkt in die LED siehst, dann kannst du möglicherweise
erahnen, dass da ein kurzes Aufleuchten war, aber so richtig bewusst
wirst du das eher nicht sehen können.
Karl H. schrieb im Beitrag #4291597:
> get_keypress genau 1 mal TRUE zurück> liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem> Tastendruck eine Aktion einmalig auslösen will.
Stimmt, daher wird diese auch mit dem get_key_rpt mit oder Verknüpft. So
müsste zumindest die LED so lange leuchten bis ich die Taste wieder
loslasse.... theoretisch... wenns fehlerfrei wäre -.-
Elektrotiger schrieb:> Karl H. schrieb im Beitrag #4291597:>> get_keypress genau 1 mal TRUE zurück>> liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem>> Tastendruck eine Aktion einmalig auslösen will.>> Stimmt, daher wird diese auch mit dem get_key_rpt mit oder Verknüpft. So> müsste zumindest die LED so lange leuchten bis ich die Taste wieder> loslasse.... theoretisch... wenns fehlerfrei wäre -.-
Nein.
Dann leuchtet deine LED im Abstand von ein paar Zehntel Sekunden immer
noch nicht länger als ein paar Hundertsel-µs auf. Immer noch zu kurz.
Das ist noch nicht mal ein Glimmen der LED.
Denn: einen Autorepeat stellt man sinnvollerweise ja so ein, dass er
einem einigermassen flott tippendem Menschen entspricht. Wenn du auf
deiner Tastatur auf einer Taste drauf bleibst, dann generiert deine
Tastatur ja auch nicht in 1 Sekunde 2 Millionen Tastendrücke sondern
höchstens 'ein paar'.
Warum schaltest du nicht einfach die LED jedesmal in den andern Zustand,
wenn get_key_press TRUE liefert? Oder du benutzt 2 Tasten. Mit der einen
wird eingeschaltet, mit der anderen ausgeschaltet.
Dann brauchen wir hier diese Diskussion überhaupt nicht führen.
Fazit: Auch das Generieren von Testcode um eine Funktionaität zu testen,
will gelernt und überlegt sein.
Karl H. schrieb:> Denn: einen Autorepeat stellt man sinnvollerweise ja so ein, dass er> einem einigermassen flott tippendem Menschen entspricht. Wenn du auf> deiner Tastatur auf einer Taste drauf bleibst, dann generiert deine> Tastatur ja auch nicht in 1 Sekunde 2 Millionen Tastendrücke sondern> höchstens 'ein paar'.
Stimmt, hatte damals meine Ampel bei jedem Repeattimerreset getoggelt...
oder hier counter hochgezählt:
1
elseif(get_key_rpt(1<<KEY_links))
2
{
3
*pcountdown=500;// 5 Sekunden
4
flag_countdown=1;
5
flag_firstcount=1;// Erstmaliges Drücken
6
7
if(pulsdauer<0)pulsdauer=0;
8
elseif(pulsdauer%1000==0)
9
{
10
pulsdauer-=1000;
11
}
12
elseif(pulsdauer%100==0)
13
{
14
pulsdauer-=100;
15
}
16
elseif(pulsdauer%10==0)
17
{
18
pulsdauer-=10;
19
}
20
else
21
{
22
pulsdauer--;
23
}
24
.......
Fazit von meiner Seite aus:
Erst mal vielen, VIELEN Dank für alle Poster. Habt mein Verständnis zu
ARM schon mal einen Boden gegeben um dort nun aufzubauen.
Es ist mir sehr peinlich..., aber ich musste es mal verstehen :/. Es
gibt leider zu ARM µC kaum Tutorials, die ASF Atmel sind dafür richtig
mies. Haben mich nicht sehr verwirrt.
Ich habe jedenfalls viel gelernt und bedanke mich noch für Eure Geduld.
Entprellung funktioniert. Topic somit abgeschlossen.
Da ARM noch "relativ" neu sind gegenüber AVR wären eventuell mehr
Tutorial dazu sehr hilfreich. Zu AVR gab es genügend hier auf
mikrocontroller.net und auch um Netz, vll kann man da was erweitern?