www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik geistertasten


Autor: stefan (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend,
Ich hätte eine Frage bezüglich, der von mir verwendeten Tastermatrix 
(siehe Anhang). Wie ma erkennen kann handelt es sich um eine 8*3 
Active-high Matrix mit externen Pull-downs. Keine Standardmatrix, aber 
für mich einfacher zu verstehen, da ich noch Neuling im Gebiet der µC 
bin.
Meine Frage bezieht sich auf die Entprellung der Matrix, da sich einige 
Tasten immer wieder einfach von alleine drücken.

Hier ein Ausschnitt aus dem Quellcode zur Abfrage und Entrprellung der 
Tasten:

PORTB |= ( ( 1 << PB2 ) );

    for (ui8Count = 0; ui8Count < 5; ui8Count++)
    {
      if ( PINC & (1<<PC3) )
        ui8Prellen[21]++;
      if ( PINC & (1<<PC4) )
        ui8Prellen[22]++;
      if ( PINC & (1<<PC5) )
        ui8Prellen[23]++;

        _delay_ms(5);
    }

PORTB &=~ ( ( 1 << PB2 ) );

Mein Gedankengang:
- Ausgang des Controllers auf high Schalten
- Die Eingänge kontrollieren und damit die Taste eindeutig 
indentifizieren
- Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt 
die Taste als gedrückt und entprellt

Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund.
Wichtig wäre vielleicht noch, dass es nicht möglich sein muss zwei 
Tasten gleichzeitig zu drücken (deshalb habe ich auch auf eine 
Endkopplung mit Dioden verzichtet).

Im voraus danke für eine Antwort
mgf
Stefan

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zum Entprellen eiget sich besser, in einer ISR alle 10ms (z.B.) auf die 
Matrix zu schauen.

In der ISR sete zu die Ports, wartest evtl kurz (also ein paar Ticks() 
und liest dann die aktuelle Zeile/Spalte ein. Durch die Abtastung in den 
Schritten hast du ne Entprellung, und eine nicht-blockierende 
Hauptschleife.

Das kurze Warten dient dem Anpassen der Pegel. Je nach 
Schaltung/Leitungen haben die ne Kapazität von ein paar pF, und wenn der 
AVR schbekk läüft, brauchts u.U ein paar 100ns bis sich die Pegel nach 
Umschaltung angepasst haben.

Pro ISR wird nur eine Zeile abgearbeitet, in der nächsten dann eine 
weitere.

Johann

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sory mein Fehler, ich habe vergessen zu erwähnen, dass die Entprellung 
bereits in einer ISR (also in einem Timer, der alle 10ms Aufgerufen 
wird) erfolgt.
Innerhalb eines durchlaufs wird aber die gesamte Matrix abgefragt...
Ich kann mir nur nicht ganz erklähren warum sich die Tasten teilweise 
von selbst Drücken??

inzwischen danke für die schnelle Antwort

Autor: gast_5 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im moment fällt mir kein Softwarefehler auf.
Kann es sein dass es an der Hardware liegt?
Kurzschluss? Fehlkontakte? Wackelkontakt?

Ich würde auf alle Fälle die Hardware nachkontrollieren.

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S25 ist aber ein übler Kandidat...:-)

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>S25 ist aber ein übler Kandidat...:-)

Tut mir leid da kann ich leider nicht ganz folgen??

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
War ja auch ne Fehlleistung von mir...
Hatte mit deinem eigentlichen Problem auch nichts zu tun, sah auf den 
ersten Blick so aus, als ob der direkt zwischen Vcc und Masse liegt.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn der Schaltplan stimmt, schließt S25 die Betriebsspannung kurz.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach nee, doch nicht... ;(

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S25 wird durch das Gehäuse und ein bischen mechanischer Bastelei zu 
einem Schalter, ist aber nicht das eigentliche Problem, das liegt wie 
ich hoffe (Platine ist bereist fertig) und vermute an der Software.
Also keiner eine Idee warum der Controller immer wider Tasten als 
gedrückt erkennt, ohne dass diese wirklich gedrückt worden sind??

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stefan schrieb:
> Hier ein Ausschnitt aus dem Quellcode zur Abfrage und Entrprellung der
> Tasten:
>
> PORTB |= ( ( 1 << PB2 ) );
>
>     for (ui8Count = 0; ui8Count < 5; ui8Count++)
>     {
>       if ( PINC & (1<<PC3) )
>         ui8Prellen[21]++;
>       if ( PINC & (1<<PC4) )
>         ui8Prellen[22]++;
>       if ( PINC & (1<<PC5) )
>         ui8Prellen[23]++;
>
>         _delay_ms(5);
>     }
>
> PORTB &=~ ( ( 1 << PB2 ) );
>
> Mein Gedankengang:
> - Ausgang des Controllers auf high Schalten
> - Die Eingänge kontrollieren und damit die Taste eindeutig
> indentifizieren
> - Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt
> die Taste als gedrückt und entprellt

Das steht aber nicht in Deinem Codeschnipselchen.

99% der Fragesteller sind betriebsblind, d.h. posten immer nur 
Schnipselchen, die den Fehler garantiert nicht enthalten oder schlimmer 
noch, dem getesteten Code garnicht entsprechen.
Daher besser einen compilierfähigen, getesteten Code als Anhang posten.


> Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund.

Zur Zeit ist er ja beides nicht.


Hier mal ein funktionierendes Beispiel:

Beitrag "Tasten-Matrix entprellen"


Peter

Autor: stefan (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe Ihren Code bereist genau angeschaut aber nicht wirklich sehr 
viel verstanden. Ich weiß, dass die Matrix Bitweise ausgelesen und dabei 
auch entprellt wird. Außderm hab ich verstanden, dass der Code für eine 
"Active-Low" - Matrix geschrieben wurde. Es werden Registerrichtungen 
(Ausgang-Eingang) gesetzt und auf Low abgefragt und nicht wie ich das 
mache Ports geschalten (high-low) und dann ein high-Signal abfragen.
Das ist leider alles was ich verstanden habe, deshalb habe ich auch 
nicht die geringste Ahnung wie ich Ihren Code an mein Problem anpassen 
könnte.

>99% der Fragesteller sind betriebsblind, d.h. posten immer nur
>Schnipselchen, die den Fehler garantiert nicht enthalten oder schlimmer
>noch, dem getesteten Code garnicht entsprechen.
>Daher besser einen compilierfähigen, getesteten Code als Anhang posten.

Ok könnte stimmen, dann nocheinmal ein neuer Versuch. (compilierfähiger 
Code im Anhnag).

> Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund.
>Zur Zeit ist er ja beides nicht.

Nein eigentlich nicht wirklich, der Tastendruck wird zwar immer erkannt, 
aber wie schon gesagt drücken sich die Tasten immer wider von selbst, 
was vermutlich daran liegt, dass die Tasten nicht ausreichend entprellt 
werden.

Thoretisch müsste, die Entprellung und das Einlesen der Matrix aber so 
funktionieren? Glaube ich zu mindest?
Wie schon gesag es muss nicht effektiv sein aber funktionieren, außerdem 
ist meine Variante so einfach, dass sie sogar ich verstehe, was mir auch 
sehr wichtig ist.

Autor: phil58 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tut mir leid meiner Meinung nach müsste der Quellcode stimmen, 
theoretisch als auch in der Ausführung.
Sicher keine Fehler in der Hardeware?

Autor: Markus ---- (mrmccrash)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welche Art Tasten verwendest du? sind das Folientaser oder "richtige" 
Mechanische? Wie ist der Spass verkabelt? An AVCC/AGND auch noch einen 
Abblockkondensator angeschlossen? Lässt du zwischen den High-Schalten 
einer Zeile und dem Auslesen eine Pause?

Ich vermute, dass durch die kurzen Impulse beim Einschalten die 
Zuleitungen bzw. die Taster wie Kondensatoren verhalten und daher 
"falsche" Werte liefern.

_.-=: MFG :=-._

Autor: skua (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kann Übersprechen sein.
In der ISR immer nur 1 spalte abfragen und am ende der ISR auf die 
nächste umschalten.
Dadurch bekommen die Signale zeit sich einzuschwingen.
Als ausgleich kann man die ISR ja öfter starten.
mfg.

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Welche Art Tasten verwendest du? sind das Folientaser oder "richtige"
>Mechanische? Wie ist der Spass verkabelt? An AVCC/AGND auch noch einen
>Abblockkondensator angeschlossen? Lässt du zwischen den High-Schalten
>einer Zeile und dem Auslesen eine Pause?

-Es sind mechanische Taster
-Die Schaltung ist bereits auf einer Platine
-an AVCC/AGND ist ein 100nF Kondensator zwischengeschaltet (müsste 
reichen?)
-eine Pause wird auch gemacht

>Das kann Übersprechen sein.
>In der ISR immer nur 1 spalte abfragen und am ende der ISR auf die
>nächste umschalten.
>Dadurch bekommen die Signale zeit sich einzuschwingen.
>Als ausgleich kann man die ISR ja öfter starten.

Wie schon gesagt bin ich noch Anfänger und habe mit Mühe und Not einen 
ISR zum Starten gebracht.
Wenn ich es richtig Verstanden habe müsste ich dann 8 verschiedene ISRs 
haben um jeweils 3 Tasten auszulesen. Am Ende von der Einen müsste die
Nächste gestartet werden Zum Ausgleich müsste die gesamte Prozdur 
mehrmals gestartet werden??
Giibt es überhaupt 8 verschieden ISRs?
Kann ich irgendwie testen ob es sichh um das benannte Problem handelt?

Kann mein Problem wirklich nicht an der Entprellung liegen?

Danke  inzwischen
Stefan

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du deine Entprellung sicher testen willst, dann les mal nur eine 
Zeile deiner Matrix ein und lass die anderen mal aussen vor. Wenn's dann 
einwandfrei geht weißt du, dass deine Entprellung läuft und der Fehler 
wahrscheinlich durch überpsrechen kommt. Wenn's nicht läuft hat auf 
jeden Fall deine Entprellung auch noch nen Fehler.

Nein, du brauchst weiterhin nur eine ISR. Du brauchst eine globale 
Variable, die du bei jedem ISR-Aufruf um eins verringerst. Je nach Wert 
der Variable wird dann eine Zeile ausgelesen. In Pseudocode könnte das 
so ungefähr aussehn:


verringer global_cnt
wenn global_cnt == 0, dann global cnt = Anzahl Zeilen
lese Tastenwerte ein
deaktiviere Zeile mit der Nummer von global_cnt
aktiviere Zeile mit der Nummer von global_cnt+1

Hier dann die Entprellroutine

Return

Auf die weise hat die Matrix eine Interrupt-periode (z.B.10ms) Zeit 
bevor die neue Zeile eingelesen wird. Auf die weise sollten dann alle 
Kapazitäten umgeladen sein.
In der initialisierung aktivierst du dann schonmal die erste Zeile und 
lädst die anzahl zeilen in dein globales register bevor du den Timer 
startest.

Hatte übrigens vor einigen Tagen das gleiche Problem und hab es genau so 
gelöst. Aber in Assambler, mein Code wird dir also nicht viel helfen.

Sebastian

Autor: stefan (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Der Fehler wird sich wohl doch bei der Entprellung eingeschlichen haben.
Im Anhang nocheinmal der Testcode, der nur nor eine Zeile ausliest.
Trotz das nur eine Zeile ausgelesen wird drücken sich die Tasten b,h,j 
immer wider von selbst, obwohl nur die Tasten a,b,c abgefragt werden.
Die Tasten werden zwar nicht mehr so oft als gedrückt erkannt aber 
leider immer noch?
Also muss der Fehler beim Entprellen liegen oder kann Trotzdem ein 
überspringen darfür verantwortlich sein?

Noch eine kurze Frage zum getrennten behandeln der ISRs. Müsste es vom 
Prinzip nicht das selbe sein wie:

Pseudocode:
verringer global_cnt
wenn global_cnt == 0, dann global_cnt = Anzahl_Zeilen
wenn zeile_nr == global_cnt, dann lies entsprechende Zeile aus

So wird in jedem ISR Durchgangn nur jeweils eine Zeile (also drei 
Tasten) abgefragt

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es macht definitiv keinen Spaß, sich diesen Code anzusehen. Es werden 
Unmengen an Flash und SRAM verschwendet ohne den geringsten Effekt.

Auch wenn es für den Anfänger scheint, Copy&Paste sei einfach, das 
Gegenteil ist der Fall. Der Code wird nur unübersichtlich und 
fehlerträchtig.
Gleiche Sachen immer zusammenfassen, entweder als Loop oder Funktion 
oder notfalls erstmal als Macro.


Schmeiß alles weg und versuche mal einen komplett neuen Ansatz:
Trenn Erkennung, Entprellen, Anzeigen und Warten voneinander und 
schreibe eins nach dem anderen.

Du willst ja nur eine Taste erkennen, also sind 24 Variablen genau 23 
zuviel.
Die Erkennungsroutine gibt Dir einfach ne Zahl 0..24 zurück, die der 
ersten erkannten Taste entspricht.
Die Entprellroutine  ruft diese im Timerinterrupt alle 10ms auf.
Dann zählst Du nur noch, ob 4-mal hintereinander der gleiche Wert 
gelesen wird und voila, die Taste ist entprellt.
Dann zeigst Du sie an, aber nicht im Timerinterrupt.

Bezüglich Timerinterrupt: irgendwelche Delays haben darin absolut nichts 
verloren. Das ist ja gerade der Witz am Timerinterrupt, daß er selbst 
das Delay darstellt und die Rechenzeit ans Main zurück gibt statt sie zu 
vergeuden.

Wenn man also schon Delays benutzt, dann ausschließlich im Main!


Als Anfänger sollte man auch nicht alle Portpins lustig 
durcheinanderwürfeln, damit machst Du Dir nur selber das Leben schwer.
Der AVR ist ein 8-Bitter und Du hast 8 Zeilen, da sollte man schon 
möglichst alle Zeilen auf den gleichen Port legen. Das vereinfacht die 
Auswertung erheblich.
Das Verwürfeln von Portpins ist dann schon höhere Programmierschule (ist 
aber mit Bitvariablen auch gut lesbar).


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stefan schrieb:
> Es werden Registerrichtungen
> (Ausgang-Eingang) gesetzt und auf Low abgefragt und nicht wie ich das
> mache Ports geschalten (high-low) und dann ein high-Signal abfragen.


Nun, dann überlege mal, wenn jemand 2 Tasten drückt und dadurch ein 
0-Ausgang mit einem 1-Ausgang kurzgeschlossen wird.
Der MC überlebt es in der Regel, aber die Stromaufnahme steigt 
erheblich.

Daher ist Ausgänge umschalten falsch!
Alle Ausgänge müssen den gleichen Wert haben und nur die Richtung wird 
umgeschaltet.


Man spart Rechenzeit und Code, wenn man die kleinere Anzahl umschaltet 
und dann die größere einliest. Also die 3 Spalten als Ausgang und die 8 
Zeilen als Eingang.


Peter

Autor: stefan (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß nicht ob ich wirklich verstanden habe was Sie meinen aber hier 
nocheinmal ein Versuch

Vielen Vielen dank für die Gedult
Stefan

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es wäre wohl sinvoll, wenn du deinen Schaltplan nochmal änderst. Wenn du 
die 8 Zeilen zusammen auf einen Port gibst und dann zwischen den 3 
Spalten auswählst wird die Software deutlich einfacher. Schneller und 
kürzer sowieso.

Seh ich das richtig, dass du versuchst, bei jedem ISR-Aufruf eine ganze 
Entprellung durchzuführen, also 5 Samples zu nehmen? Dann kommst du um 
ein Delay tatsächlich nicht rum. Aber das Konzept ist Mist.

Du musst bei jedem ISR-Aufruf nur ein Sample nehmen. Der letzte Zustand 
wird gespeichert und es wird jedesmal ein Zähler verringert, der zählt, 
wie lange sich der Zustand schon nicht geändert hat. Erreicht der Zähler 
0, dann liegt ein sauberer Pegel an. Dieser Pegel wird für Main 
übernommen und es wird nichtmehr weitergezählt. Sind aktueller und 
letzter Zustand unterschiedlich wird der Zähler (z.B. auf 4) 
zurückgesetzt.

Für den Anfang solltest du mal nur eine der 3 Spalten deiner Matrix 
verwenden. Die muss dann aber auch immer aktiv bleiben, also auch 
außerhalb der ISR (für den ersten test jetzt). Wenn dann deine 
Entprellung funktioniert, kannst du anfangen, dich mit der Matrix 
rumzuärgern.

Schau doch auch mal in die Codesammlung, wie andere soetwas lösen.

Sebastian

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Schau doch auch mal in die Codesammlung, wie andere soetwas lösen.

Ich habe jetzt seit über 2 Wochen Beiträge studiert, aber die einzig 
Gute Entprellroutine (die von Peter) verstehe ich nicht, der Rest war 
nicht besonders hilfreich.

>Es wäre wohl sinvoll, wenn du deinen Schaltplan nochmal änderst. Wenn du
>die 8 Zeilen zusammen auf einen Port gibst und dann zwischen den 3
>Spalten auswählst wird die Software deutlich einfacher. Schneller und
>kürzer sowieso.

Den Schaltplan nocheinmal zu ändern ist leider nicht mehr möglich.


Dass das was ich produziert habe reiner Mist ist habe ich jetzt auch 
verstanden.

Ich muss:
- in der ISR nur jeweils eine Zeile überprüfen
- und damit in der ISR keine delays verwenden
- die Zeilen und Spalten aufgrund der Effektivität vertauschen
- die Auswertung (Ausgabe auf dem Display) in der Main realisieren

Ok das habe ich verstanden hab aber leider keine Ahnung wie ich das 
machen soll??
Ein Pseudocode von Peters Routine oder eine Erklährung wäre sehr 
hilfreich? Ich bin mir nicht sicher ob ich das Konzept mit den oben 
genannten Punkten wirklich verstanden habe. Ich hoffe miar kenn jemad 
weiterhelfen

Danke im voraus Stefan

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ich muss:
>- in der ISR nur jeweils eine Zeile überprüfen

Persönlich trenne ich bei Martixtastaturen die Erkennung einer 
gedrückten Taste und die Ermittlung der gedrückten Taste. Zur 
Tastenerkennung reicht es alle Ausgänge in den aktiven Zustand zu 
versetzen und die Eingänge abzufragen. Erst wenn dadurch (irgend-)eine 
Taste erkannt wurde erfolgt die Decodierung der Taste. Dadurch ist die 
Tastenerkennung relativ schnell und kompakt und die zeitliche Trennung 
von Erkennung und Dekodierung reicht u.U. schon für die Entprellung.

MfG Spess

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Den Schaltplan nocheinmal zu ändern ist leider nicht mehr möglich.

Warum? Platine schon geätzt? Vor allem als Anfänger sollte man sowas 
vielleicht erstmal auf Lochraster probieren, bevor man ne Platine ätzt.

Leiterbahnen auftrennen und mit Draht neu verlöten kann durchaus auch ne 
Alternative sein. Ich kenne dein layout nicht.

Es gibt noch tausend andere und teils sicher bessere möglichkeiten, aber 
hier mal ein Weg, der zum erfolg führen sollte und vielleicht für dich 
nachvollziebar ist. Dabei werden (erstmal) nur 2 Samples genommen bis 
der Zustand als gültig erkannt wird. Mehrere Samples darfst du selbst 
einbauen, wenn's nötig ist.

Für den ersten Test beachtest du nur die Spalte an PC3.
In der Init:
-PC3 wird auf ausgang und High gestellt und dann nicht mehr verändert.
-Die ISR wird initialisiert
-globale Variable sw_old=0 anlegen (hier wird der letze Zustand deiner 
Tasten gespeichert)
-globale Variable sw_state anlegen (hier wird der entprellte Zustand 
deiner Tasten gespeichert)
-ab nach main

in der ISR:
-Zeilen einlesen und in ein Byte vereinen. Jede Taste bekommt ein Bit, 
das den Zusatnd der Taste anzeigt.(Genau der Punkt wäre mit anderem 
Layout einfacher, kürzer und schneller)
-neuer Zustand==sw_old?  wenn ja: sw_state= neuer Zustand
-sw_old=neuer Zustand    //neuen zustand als "neuen alten Zustand" 
übernehmen
-ende

in der main kannst du dann mit sw_state lesend machen was du willst, 
blos schreiben darfst du hier dann nicht.


Wenn du an dem Konzept was nicht verstehst frag nach. Ansonsten antworte 
ich erst wieder, wenn das bei dir läuft und du verstanden hast, warum.

Sebastian

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stefan schrieb:
> Ich weiß nicht ob ich wirklich verstanden habe was Sie meinen aber hier
> nocheinmal ein Versuch

Nein.

Ich meinte, die Aufgaben zu trennen (teile und herrsche).
Und Spaghetticode vermeiden (Schleifen statt Copy&Paste).

#include <io.h>


#define COL0    PC3
#define COL1    PC4
#define COL2    PC5

#define ROW0    PC0
#define ROW1    PC1
#define ROW2    PC2
#define ROW3    PB0
#define ROW4    PB1
#define ROW5    PB2
#define ROW6    PD6
#define ROW7    PD7


uint8_t get_key_row( void )
{
  uint8_t key = 0;
  uint8_t row;

  row = (PINB & (1<<ROW3 | 1<<ROW4 | 1<<ROW5)) << 3;
  row |= PINC & (1<<ROW0 | 1<<ROW1 | 1<<ROW2);
  row |= PIND & (1<<ROW6 | 1<<ROW7);

  if( row )
    for(;;){
      key++;                            // count bit number
      if( row & 1)                      // until bit found
        break;
      row >>= 1;
    }
  return key;                           // 0 = no key, 1..8 = key
}


uint8_t key_scan( void )
{
  uint8_t key = 0;
  uint8_t col = 1<<COL0;                // 1th column

  do{
    if( !key )
      key = get_key_row();
    else
      key += 8;

    PORTC = col;
    DDRC = col;                         // open drain to avoid short circuit !!!
    col <<= 1;                          // next column
  }while( col & (1<<COL2 | 1<<COL1));

  return key;                           // 0 = no key, 1..24 = key pressed
}


uint8_t key_debounce( void )            // call every 10ms
{
  static uint8_t old_key = 0xFF;
  static uint8_t debounce_cnt = 0;
  uint8_t key;

  key = key_scan();

  if( old_key == key ){
    if( debounce_cnt == 4 )             // four times equal (40ms)
      return key;
    debounce_cnt++;
  }else{
    old_key = key;
    debounce_cnt = 0;
  }
  return 0;
}


Peter

P.S.: In Foren ist "Sie" ungebräuchlich.

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja habe die Platine leider schon geätzt und gelötet da miar einwenig die 
Zeit davon rennt...

Ok danke für die schnelle Antwort, einige Kleinigkeiten hätte ich aber 
noch die ich dabei noch nicht ganz verstanden habe:

>in der main kannst du dann mit sw_state lesend machen was du willst,
>blos schreiben darfst du hier dann nicht.


-Wenn ich die Ausgabe nicht in der ISR und in der Main auch nicht machen 
soll, wo soll ich das ganze dann ausgeben
-für die Ausgabe muss ich dann aber immer noch abfragen welches Bit 
gesetzt wurde um die Taste zu erkennen
z.B.
if (sw_state == 0b10000000)
   Taste1->gedrückt
else if (sw_state == 0b01000000)
   Taste2->gedrückt
das ganze dann 3 mal für jede Zeile
liege ich damit richtig?
-Für eine Zeile glaube ich das Prinzip verstanden zu haben, aber wie 
soll ich das ganze anschließend für drei Zeilen realisiern

Nochmal herzlichen Dank ohne Euch wäre ich verloren
mgf
Stefan

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit "Ausgabe" meinst du das Anzeigen auf dem Display welche Taste 
gedrückt ist? Bzw. halt die jeweilige Aktion, die ausgeführt werden 
soll?
Das muss in der main passieren. Deine ISR liest die Tasten ein und 
entprellt sie. Der entprellte Zustand kommt in den Ram (hier ist das 
sw_state). In deinem eigentlichen Programm (main) interessiert dich die 
Matrix dann garnicht mehr, weil du einfach aus sw_state den Zustand der 
Tasten einliest.

In main könnte dann durchaus ein Konstrukt stehen, wie du es angedeutet 
hast:

if (sw_state == 0b00000001)
   Aktion von Taste1
else if (sw_state == 0b00000010)
   Aktion von Taste2


Zeig mal deinen Sourcecode für eine Spalte. Dann weiß man, wie du das 
umgesetzt hast und kann konkret dort weiterhelfen.

Als grober Anriss:
Man liest bei jedem Aufruf der ISR nur eine Spalte ein, deaktiviert sie 
danach und aktiviert die nächste Spalte. Auf die Weise können sich die 
Kapazitäten der Matrix umladen, ohne dass man delays braucht.
Nicht unbedingt das beste, aber wohl einfachste ist es jetzt, die ersten 
2 Spalten erstmal zwischenzuspeichern. Einfach der Wert, der gerade 
eingelesen wurde.
Wenn die dritte Zeile eingelesen wird führt man alle Zustände zusammen 
in ein longint (? irgendwas mit mindestens 24 bit halt) und führt darauf 
wieder die debug-routine aus.


Schau dir auch mal den Code an, den Peter vorhin gepostet hat. Er hat 
alles schön aufgeteilt, sodass der Code leicht lesbar wird. Er hat dann 
ein "modul" zum einlesen der Zustände und vereinen in ein Byte, eines um 
die Spalten umzuschalten und eines um das ganze dann zu entprellen. Er 
hat sogar eine 4-fache Statusabfrage drin.


@Peter
Wenn ich das richtig sehe liest du alle 3 Spalten direkt hintereinander 
ein. Das kann funktionieren, muss aber nicht. Bei mir ist die 
Tastenmatrix vielleicht einen halben Meter abgesetzt und es hat nicht 
funktioniert. Atmel macht in seinen Appnotes deswegen Warteschleifen 
rein. Dass das Mist ist wissen wir beide. Deshalb würde ich bei jedem 
ISR-Aufruf nur eine Zeile einlesen. Macht die Software aufwändiger, aber 
sonst kommts eben zu genau den "Geistertasten" des Threadopeners.

Gruß, Sebastian

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian schrieb:
> @Peter
> Wenn ich das richtig sehe liest du alle 3 Spalten direkt hintereinander
> ein. Das kann funktionieren, muss aber nicht.

Ich wollts erstmal nicht zu unübersichtlich machen.
Ich setze sie auch erst am Ende der Schleife, d.h. da sind noch einige 
Instruktionen dazwischen bis zur Abfrage.


> Bei mir ist die
> Tastenmatrix vielleicht einen halben Meter abgesetzt und es hat nicht
> funktioniert.

Das dürfte dann aber eher Probleme mit dem CE-Zeichen geben.
Falls die CPU von der Tastatur abgesetzt werden muß, gönne ich der 
Tastatur nen eigenen MC, spart dann auch Leitungen.


Peter

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich wollts erstmal nicht zu unübersichtlich machen.

Ja, hatte ich mir schon gedacht. Hab dann aber die andere Version 
beschrieben, da der OP ja genau mit komischen Tastenereignissen Probleme 
hatte. Ob die jetzt daher kamen kann ich nicht sagen. Der alte 
Sourcecode war mir zu unübersichtlich.

> Das dürfte dann aber eher Probleme mit dem CE-Zeichen geben.
Da ich für meine Privatbasteleien kein CE-Zeichen brauch hab ich da 
nochmal glück gehabt :-)
Hat sich auch nur im Testaufbau so ergeben. Soll später noch näher 
zusammenrücken. Und so ist die Software wohl störsicherer.

Gruß, Sebastian

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian schrieb:
> Hab dann aber die andere Version
> beschrieben, da der OP ja genau mit komischen Tastenereignissen Probleme
> hatte.

Ich vermute ja, daß er mal 2 Tasten drückt und es dann zum Kurzschluß 
kommt, weil er ja nicht auf mich hören will und alle Ausgänge 
gleichzeitig an läßt.

Ob sein Code funktionieren kann, weiß ich nicht.


Peter

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>P.S.: In Foren ist "Sie" ungebräuchlich.

Bei miar in der Gegend ist das 56k - Modem Zeitalter erst seit 10 Tagen 
Vergangenheit also ist meine Forumerfahrung nicht besonders groß;-)

Ich höhre gerne auf jeden der mir weiterhilft. Studiere gerade den Code 
von Peter (danke erstmals) und werde mich dann selbst versuchen, endlich 
was sinnvolles auf die Reihe zu bringen...

gruß
Stefan

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan,

du sagst, daß deine Funktion in einer ISR alle 10ms aufgerufen wird, 
aber selbst ein _delay_ms(5) enthält welches 5 mal ausgeführt wird, also 
in der Summe 25ms dauert.
Wie soll das funktionieren, wenn die ISR noch nicht fertig ist, wenn sie 
schon wieder aufgerufen wird ?

Warum ist das bisher noch niemandem aufgefallen ?

Zweitens sagst du, dass du nur alle 10ms die Tastatur abfragen willst. 
Damit ist eine Taste endweder gedrückt, oder nicht gedrückt. Wenn sie 
(weniger als 10ms) prellt, mekrt das die Tastaturabfrageroutine nicht, 
sie sieht die Taste bereits ohne Prellen.
Daher ist es überflüssig und eher schädlich, nun noch:
"Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt
die Taste als gedrückt und entprellt."
zu versuchen. Sollte die Taste länger als 10ms, sondern 40ms prellen, 
dann mach deine ISR so, dass sie die Tastatur nur noch alle 50ms 
abfragt.

Du musst nicht entprellen.

Warum ist das bisher noch niemandem aufgefallen ?

Du musst nur die Tastatur in längeren Intervallen abfragen, als die 
Tasten maximal prellen, und ebkommst automatisch einen entprellten 
Tastenzustand.

Wenn nun noch die Ausgänge richtig auf Ausgang geschaltet sind und nur 
der von einer Reihe auf HI liegen, und die Eingaenge mit den 10k 
PullDown nicht gegen einen eingeschalteten internen PullUp des AVR 
anarbeiten müssen, dann ist es sogar egal, ob die Ausgänge noch den 
überflüssigen 10k Widerstand R12..R14 gegen Masse enthalten. Ja, die 
sind überflüssig. Klüger wäre es natpürlich, PC und PD aus Ausgang zu 
definieren, dann braucht amn nur die 3 Widerstaende an den dann als 
Eingang geschalteten PA, und noch klüger wäre es, die eingebauten 
PullUps des AVR zu verwenden,dann spart man sich alle externen 
Widerstaende.

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>du sagst, daß deine Funktion in einer ISR alle 10ms aufgerufen wird,
>aber selbst ein _delay_ms(5) enthält welches 5 mal ausgeführt wird, also
>in der Summe 25ms dauert.
>Wie soll das funktionieren, wenn die ISR noch nicht fertig ist, wenn sie
>schon wieder aufgerufen wird

Die ISR kann nicht nocheinmal aufgerufen werden, da zu beginn von dieser 
die Interrupts global ausgeschlaten und erst nachdem diese abgearbeitet 
worden ist wider eingeschalten werden.

Ok mit den Widerständen känntest Du recht haben ist jetzt aber auch 
nicht mehr weiter schlimm da sie schon verbuat sind.
Ich verstehe nur nicht warum alle von entprellen sprechen, wenn die 
Sache wirklich so einfach wäre (Timer zur abfrage nur alle 50ms 
aufrufen)????



@peter
Ich hätte noch ein paar Fragen zu Deinem Code, da ich in wirklich geren 
verstehen möchte:
-key_debounce() ist klar damit werden die Tasten entprellt
-get_key_row() findet heraus ob überhaupt eine Taste gedrückt wurde, ich 
verstehe nur nicht wenn das if (row & 1) erfüllt wird und die Schleife 
abgebrochen?
-bei key_scan() habe ich dann ein totales Balckout col = 1<<COL0; 
verstehe ich überhaupt nicht. Und bedeutet dass key += 8, alle acht bits 
auf null setzt, was logisch wäre oder bekommt key den Binäerwert von der 
Dezimalzahl 8?

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> wenn die Sache wirklich so einfach wäre

Sie ist es. Wenn Tasten weniger als 50ms prellen, sieht man in Abfragen 
die 50ms auseinanderliegen keine prellenden Tasten. Es geht auch mit 
10ms, denn kaum eine Taste prellt 10ms.

Wenn du nun noch die richtigen Ports ansprichst, denn dein Schaltplan 
passt nicht zum Code.

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der code von Peter funktioniert einwandfrei, auch wenn dabei innerhalb 
einer ISR alle Zeilen abgefragt werden.

Recht herzlichen dank nocheinmal an Peter
Wäre Nett wen Du oder jemad mir die weiter oben gestellten Fragen zu 
deinem Code noch kurz erläutern könnte?

Danke nocheinmal Ihr wart echt meine Rettung

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stefan schrieb:
> -get_key_row() findet heraus ob überhaupt eine Taste gedrückt wurde, ich
> verstehe nur nicht wenn das if (row & 1) erfüllt wird und die Schleife
> abgebrochen?

Ich will die Nummer der ersten gedrückten Taste, d.h. nachdem das Bit 1 
war, darf ich nicht mehr weiter zählen.
Alle Bits werden nach rechts geschoben, d.h. irgendwann habe ich die 1.
Und der Zähler (key) sagt mir dann die Bitnummer.

> -bei key_scan() habe ich dann ein totales Balckout col = 1<<COL0;

Ich setzte COL0 auf 1.
Dann wird nach links geschoben (col <<= 1;) und im nächsten Durchlauf 
wird damit COL1 = 1 usw.

> Und bedeutet dass key += 8

Die Reihenerkennung liefert immer nur 1..8, dazu muß ich je nach Spalte 
dann 0, 8 oder 16 addieren.

Welche Taste nun welchen Wert hat, ist nebensächlich, daß macht man dann 
später mit ner Lookuptable wie man es wünscht.


Peter

Autor: stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erleuchtung;-) Super danke jetzt hab sogar ich verstanden
Nochmals vielen dank an alle

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.