Hallo zusammen,
ich versuche eine 3*4 Tastenmatrix über einen Spannungsteiler mittels
AD-Wandlung einzulesen.
Funktioniert soweit auch schon ganz gut, nur habe ich ein riesen Problem
mit dem Prellen der Tasten.
Wie kann ich dafür sorgen das die Tasten entprellt werden sobald sie den
Wert 0xff unterschreiten, bzw. den gelesenen Wert wieder verlassen?
Hier der Quellcode:
1
#include<avr/io.h>
2
#define F_CPU 3686400UL
3
#include<util/delay.h>
4
5
uint8_tmessen(uint8_tport)
6
{
7
ADMUX=0x00;//MUX0 bis MUX3 zurücksetzen
8
ADMUX|=port;//MUX0 bis MUX3 auf gewünschten Port setzen
Ich gebe die gedrückte Taste an eine 7-Segmentanzeige aus. Solange ich
die Taste drücke wird ja auch das richtige angezeigt, aber sobald ich
die Taste loslasse oder nur andrücke wird mir alles angezeigt nur nicht
der Tastenwert.Deshalb müsste ich die Tastenerkennung entprellen, nur
weiß ich leider nicht wie ich das bewerkstelligen muss.
Danke schonmal für eure Hilfe im voraus.
Danke für den Hinweis.
Hatte ich auch schon gelesen, doch ehrlich gesagt nicht ganz verstanden,
deshalb ja nochmal meine Anfrage im Forum.
Ist es auch möglich die Tasten ohne Interrupt zu entprellen?
Das Prinzip ist im Grunde immer das gleiche.
Eine festgestellte Veränderung deiner Messung wird erst dann akzeptiert,
wenn sich ein paar mal hintereinander (in einem zeitlichen Abstand von
jeweils ein paar Millisekunden) derselbe Wert ergibt.
Timer mit Interrupt ist einfach nur eine einfache Möglichkeit, wie man
diese zeitliche Abtastung machen kann, so dass das nicht mit dem
restlichen Programm beisst.
Auf Dauer wirst du um Timer sowieso nicht rumkommen. Jedes ernsthafte
Programm, welches ein bischen komplexer ist als irgendwelche banalen
Programmierübungen ist, kommt ohne Timer nicht aus. Also warum nicht
jetzt lernen, wie man einen Timer einsetzt?
Karl Heinz Buchegger schrieb:> Also warum nicht> jetzt lernen, wie man einen Timer einsetzt?
Warum 'nen Timer verschwenden, wenn man über 'ne langsame Samplerate und
Freerun den ADC als zeitgebendes Element verwenden kann ?
In der AD-Complete ISR den aktuellen gemessenen mit dem vorherigen Wert
innerhalb eines Fensters vergleichen. Wenn innerhalb Toleranz, 'ne
Zählvariable erhöhen und den Mittelwert bilden. Wenn die Zählvariable
eine bestimmte Höhe erreicht hat, sagen wir 20, dann ein Flag setzen und
analog zu obigem Code den gemittelten Wert auswerten. Im Falle dass der
aktuelle gemessene ADC-Wert außerhalb der Toleranz zum letzten Wert
liegt, Zählvariable löschen und aktuelle Messung als neue Referenz
setzen.
MWS schrieb:> Warum 'nen Timer verschwenden
Naja, irgendwas wie einen "heartbeat"-Timer braucht man ohnehin in
so ziemlich jeder Applikation. Den lässt man aller 5 oder 10 ms
ticken, und das bisschen Tastaturabfrage macht der nebenbei.
ADC free-running mode als Timer geht natürlich auch, hilft dem TE
aber nichts, denn auch da muss man sich ja mit Interrupts befassen. ;-)
MWS schrieb:> Warum 'nen Timer verschwenden, wenn man über 'ne langsame Samplerate und> Freerun den ADC als zeitgebendes Element verwenden kann ?
Laut Datenblatt nicht unter 50kHz / 13.
Das ist zum Entprellen noch viel zu schnell, d.h. unnötig hohe CPU-Last.
Peter
Jörg Wunsch schrieb:> ADC free-running mode als Timer geht natürlich auch, hilft dem TE> aber nichts, denn auch da muss man sich ja mit Interrupts befassen. ;-)
"Nichts helfen" würd' ich jetzt nicht sagen, denn wenn er's lernen will
oder muss, dann ist der Ansatz durchaus interessant. Der
Schwierigkeitsgrad einen AD-complete oder Timer-overflow Interrupt
aufzusetzen, sollte ähnlich sein.
Peter Dannegger schrieb:> Laut Datenblatt nicht unter 50kHz / 13.
Du hast F_CPU wahrgenommen ?
> between 50kHz and 200kHz to get maximum resolution.
Maximum resolution braucht er nicht.
> Das ist zum Entprellen noch viel zu schnell, d.h. unnötig hohe CPU-Last.
Auch wenn's im momentanen Stadium nicht viel ausmachen wird, da dafür
ca. 3-5% CPU verbraten würden. Aber Dein Argument ist gültig.
Dann soll der TE sich meinen Vorschlag merken, wenn ihm mal die Timer
ausgehen, oder er soll's testweise implementieren, wenn er lernen will.
MWS schrieb:> Karl Heinz Buchegger schrieb:>> Also warum nicht>> jetzt lernen, wie man einen Timer einsetzt?>> Warum 'nen Timer verschwenden
Weil du von Atmel für einen nicht benutzten Timer kein Geld
zurückbekommst.
Im übrigen gehts ja nicht um den Timer an sich, sondern um das Prinzip
wie Entprellung funktioniert. Ob er da jetzt einen Timer benutzt oder
sonst irgendwie eine regelmässige Abtastung erreicht, ist Jacke wie
Hose. Du musst nur aufpassen, dass du nicht zu schnell (!) sampelst. Das
bringt dann nämlich auch wieder nichts.
MWS schrieb:> Peter Dannegger schrieb:>> Laut Datenblatt nicht unter 50kHz / 13.>> Du hast F_CPU wahrgenommen ?
Dir ist klar, dass man den ADC nicht beliebig langsam betreiben kann?
> Dann soll der TE sich meinen Vorschlag merken, wenn ihm mal die Timer> ausgehen, oder er soll's testweise implementieren, wenn er lernen will.
Auch wenn es viele nicht wahrhaben wollen:
Ja, man kann einen Timer durchaus dazu einsetzen, MEHRERE Dinge zu
machen. Es ist nicht in Stein gemeisselt, dass eine Timer ISR nur eine
einzige Aufgabe erfüllen darf.
Karl Heinz Buchegger schrieb:> Dir ist klar, dass man den ADC nicht beliebig langsam betreiben kann?
Beliebig langsam nicht, aber wenn man ihn mit weniger als 50 kHz
taktet, leidet erstmal nur die Genauigkeit, weil die S&H-Stufe dann
bereits während der Wandlung Ladung verliert. Da es hier aber ohnehin
kaum auf 10 bit Wandlergenauigkeit ankommen wird (sondern eher nur
4 bit), und ein SA-ADC zuerst die MSBs wandelt, passen diese auch mit
geringer Taktrate immer noch gut genug.
Karl Heinz Buchegger schrieb:> Dir ist klar, dass man den ADC nicht beliebig langsam betreiben kann?
Ja. Aber 28,8kHz sollten schon noch mit ausreichender Genauigkeit
klappen.
Jörg Wunsch schrieb:> Karl Heinz Buchegger schrieb:>> Dir ist klar, dass man den ADC nicht beliebig langsam betreiben kann?>> Beliebig langsam nicht, aber wenn man ihn mit weniger als 50 kHz> taktet, leidet erstmal nur die Genauigkeit, weil die S&H-Stufe dann> bereits während der Wandlung Ladung verliert. Da es hier aber ohnehin> kaum auf 10 bit Wandlergenauigkeit ankommen wird (sondern eher nur> 4 bit), und ein SA-ADC zuerst die MSBs wandelt, passen diese auch mit> geringer Taktrate immer noch gut genug.
OK. Das kann ich akzeptieren.
Trotzdem finde ich, dass er mit dem Konzept "Heartbeat - Timer" doch
einen wesentlich wichtigeren Schritt in seiner Programmierer-Entwicklung
macht.
Karl Heinz Buchegger schrieb:> Trotzdem finde ich, dass er mit dem Konzept "Heartbeat - Timer" doch> einen wesentlich wichtigeren Schritt in seiner Programmierer-Entwicklung> macht.Das sehe ich natürlich genauso. Ich kann mich (jenseits einfacher
Testprogramme) nur an wenige Applikationen erinnern, die sowas nicht
brauchen würden in der einen oder anderen Form.
Karl Heinz Buchegger schrieb:> Trotzdem finde ich, dass er mit dem Konzept "Heartbeat - Timer" doch> einen wesentlich wichtigeren Schritt in seiner Programmierer-Entwicklung> macht.
Den wird er schon machen. Dennoch ist's immer gut neben der
eingefahrenen Spur denken zu können.
Soll er halt für sich entscheiden, meinst nicht auch ? Das Wissen darum,
das man sowas mit der AD-complete ISR machen kann, oder ggf. den ADC als
Timer missbrauchen kann, wird ihm jetzt nicht seine Seele kosten.
Ja, man kann schon die lustigsten Sachen als Timer nehmen.
Man kann ja im ADC-Interrupt ne Variable runterzählen und nur jede 100.
Messung auswerten.
Oder wenn ein Pin frei ist, UART-senden.
Oder den Watchdoginterrupt.
Echte Männer nehmen ja den EEPROM-Interrupt als Timer (~8ms) und lassen
die ersten 16Byte ungenutzt, weil die irgendwann vergeßlich werden.
Und schon hat man auf den ATmega48 7 Timer mit 14 Interrupts.
Peter
Ersteinmal vielen Dank für die vielen Antworten.
Jedoch kann ich eurer Diskussion nicht ganz folgen.
Jetzt mal ganz dumm gefragt.
Wie würde denn eine festgestellte Veränderung meiner Messung akzeptiert,
wenn sich ein paar mal hintereinander (in einem zeitlichen Abstand von
jeweils ein paar Millisekunden) derselbe Wert ergibt.
Wie könnte ich das realisieren?
Habe im moment nur ??? im Kopf.
Peter Dannegger schrieb:> Echte Männer nehmen ja den EEPROM-Interrupt als Timer (~8ms) und lassen> die ersten 16Byte ungenutzt, weil die irgendwann vergeßlich werden.
Chuck Norris kann Timer1 gleichzeitig mit 3 verschiedenen Prescalern
laufen lassen. :D
Sascha S. schrieb:> Wie könnte ich das realisieren?
Eine Lösung hab' ich hier gegeben:
Beitrag "AD-Wandlung Tastenentprellen"
Ob Du das per Timer oder wie von mir propagiert per ADC-complete
Interrupt löst, bleibt sich gleich - am Prinzip ändert sich nix.
Aber zuerst brauchst eine Zeitquelle, dazu arbeite Dich mal in Timer und
Timerinterrupt ein, so wie es Karl Heinz vorschlug.
MWS schrieb:> Chuck Norris kann Timer1 gleichzeitig mit 3 verschiedenen Prescalern> laufen lassen. :D
Wenn man die Zeiten nicht gleichzeitig benötigt, mag das gehen.
Was ich aber schonmal gebraucht habe, mit T1 3 verschiedene Intervalle
zu erzeugen.
Der Overflow macht 65536 Takte. Und Compare-A bzw. -B machen irgendwas
zwischen 2 .. 65536, indem sie ihr Compareregister entsprechend
nachladen.
Das ist ziemlich flexibel und auf den Takt genau.
Peter