PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 3x4 Matrix-Tastarur



andi.studi
06.09.2008, 18:52
Hallo Mikrocontroller Freunde,

ich habe ein kleines Problem bei der abfrage einer 3x4 Matrix Tastatur und hoffe auf eure Hilfe, da ich langsam nicht mehr weiter weiß.

Die abfrage an sich stellt keine Probleme dar, aber ich möchte erkennen ob 2 Tasten gedrückt sind. Und da komme ich heftig ins stolpern.

die Tastatur ist wie folgt an den PORTB angeschlossen

1--2--3-------RB4
| | |
4--5--6-------RB5
| | |
7--8--9------RB6
| | |
*--0--#----- RB7
| | |
| | |
1 2 3
RB RB RB




/** I N C L U D E S ************************************************** ********/
#include <delays.h>
#include <p18f4550.h>
#include "typedef.h"
/************************************************** ************************/


/** D E F I N I T I O N S ************************************************** **/
#define PORTKEY LATB
#define TRIS_KEY TRISB
#define spalte1 PORTBbits.RB1 //Keypad - 1 4 7 *
#define spalte2 PORTBbits.RB2 //Keypad - 2 5 8 0
#define spalte3 PORTBbits.RB3 //Keypad - 3 6 9 #
#define zeile1 PORTBbits.RB4 //Keypad - + I I I
#define zeile2 PORTBbits.RB5 //Keypad - --+ I I
#define zeile3 PORTBbits.RB6 //Keypad - ----+ I
#define zeile4 PORTBbits.RB7 //Keypad - ------+


/************************************************** *********************************************

bit | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00
----|-------------------------------------------|------------------------------------------------
s/z | | | | | 4/3 | 4/2 | 4/1 | 3/3 | 3/2 | 3/1 | 2/3 | 2/2 | 2/1 | 1/3 | 1/2 | 1/1
----|-------------------------------------------|------------------------------------------------
key | | | | | # | 0 | * | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1


************************************************** ************************************************/

signed int KEY_Scancode (void)
{
signed int code=0x0000;

INTCON2bits.RBPU=0; //pull-up's an
TRIS_KEY = 0b11110000; // KEY-PORT bit 0,1,2,3 = Ausgänge (bit 0 für LCD_E=0)
PORTKEY = 0b11111110;



//*******1.Spalte(1,4,7,*)************************** ***********************************************
spalte2 = 1;
spalte3 = 1;
spalte1 = 0;
TRIS_KEY = 0b11111100;
Nop();
if (zeile1==0) code = code | 1; //1
if (zeile2==0) code = code | 8; //4
if (zeile3==0) code = code | 64; //7
if (zeile4==0) code = code |512; //*

//*******2.Spalte(2,5,8,0)************************** ***********************************************
spalte1 = 1;
spalte2 = 0;
TRIS_KEY = 0b11111010;
Nop();
if (zeile1==0) code = code | 2; //2
if (zeile2==0) code = code | 16; //5
if (zeile3==0) code = code |128; //8
if (zeile4==0) code = code |1024; //0


//*******3.Spalte(3,6,9,#)************************** ***********************************************
spalte2 = 1;
spalte3 = 0;
TRIS_KEY = 0b11110110;
Nop();
if (zeile1==0) code = code | 4; //3
if (zeile2==0) code = code | 32; //6
if (zeile3==0) code = code |256; //9
if (zeile4==0) code = code |2048; //#

return code;


void main(void)
{
.
.
.
while (1)
{
PORTD=KEY_Scancode (); //an PortD sind zur silulation led's
}

}


Diese abfrage funktioniert sofern ich 2 Tasten drücke die sich Zeilen oder Spaltenweise nicht überschneiden.

alles andere ist 'müll'

hat jemand von euch Erfahrung mit der abfrage von 2 Tasten und kann mir einen tipp geben?

das eigentliche Ziel wird es später sein, wie bei einer PC-Tastatur bei tasten druck einen makecode (hier 2 byte), und beim loslassen einen breakcode (makecode | 0xf000) zu senden. aber davon bin ich noch einiges entfernt ;)

hoffe es kann mir jemand weiterhelfen.

mfg
andi

PicNick
06.09.2008, 19:55
Ich persönlich würde für alle Tasten eine Bit-Matrix anlegen, die ich beim scannen einzeln vergleiche.
Matrix-Bit = 1 und TastenPin=1 --> nix zu tun
Matrix-Bit = 1 und TastenPin=0 --> taste (neu) gedrückt ->sende ON
Matrix-Bit = 0 und TastenPin=0 --> taste festgehalten, nix zu tun
Matrix-Bit = 0 und TastenPin=1 --> taste ausgeslassen--> sende OFF
und dann den Tastenpin in der Matrix merken

Das kann man nun unterschiedlich geschickt machen, aber das Prinzip bleibt

andi.studi
06.09.2008, 20:31
hm das mit nix tun ..Taste neu...teste festgehalten ... usw.
klingt als wenn es genau das wäre wonach ich suche \:D/

doch leider verstehe ich die zuordnung nicht??
wofür steht das Matrix-Bit? bzw womit vergleiche ich es?
TastenPin leuchtet mir ein.

PICture
07.09.2008, 03:33
Hallo andi.studi!

Es müssen zuerst alle Tasten einzeln durch setzen einzelnen Bits (RB4-RB7) eingelesen werden und danach gesamt ausgewertet werden. Es lässt sich, glaube ich, mit einmaliger Einlesung nicht realisieren.

MfG

andi.studi
07.09.2008, 10:47
guten morgren,


@ PICtrue



Es müssen zuerst alle Tasten einzeln durch setzen einzelnen Bits (RB4-RB7) eingelesen werden

das einlesen einzelner Tasten funktioniert ja problemlos, aber sobald eine 2. Taste dazukommt funktioniert es nicht mehr bei jeder Taste, nur die Tasten die nicht in der gleichen Spalte oder Zeile liegen bringen das von mir erwartete Ergebnis (Ausgabe auf PORTD).

PICture
07.09.2008, 11:43
Ich kenne die Programmiersprache C nicht, deswegen kann ich das in deinem Code nicht prüfen.

Wenn die Bits am RB4-RB7 einzeln nacheinander nur für bestimmte Zeit gesetzt werden, (z.B. zuerst RB4, danach RB5 usw.), könnten zwei Tasten in einer Spalte quasi gleichzeitig (tatsächlich aber nacheinander) eingelesen werden. Die entsprechende Bitmuster für RB4-RB7 sehen dann z.B. so aus: 1000, 0100, 0010, 0001.

Wenn jede Taste einen eigenen Bit setzen würde, sollte auch keine Probleme bei gleichzeitig gedrückten Tasten in einer Zeile geben.

MfG

user529
07.09.2008, 13:53
guten morgren,

das einlesen einzelner Tasten funktioniert ja problemlos, aber sobald eine 2. Taste dazukommt funktioniert es nicht mehr bei jeder Taste, nur die Tasten die nicht in der gleichen Spalte oder Zeile liegen bringen das von mir erwartete Ergebnis (Ausgabe auf PORTD).


spalten werden durchgeschaltet und zeilen ausgelesen. wenn du jetzt zwei taster in der zeile drückst bekommst du ohne dioden einen kurzen. (port 0 auf high port 1 auf low und diese beiden sind durch die zwei taster und ein zeilenstück verbunden.

definiere mist: drücke 1 und 4 was passiert??

mfg clemens

theborg
07.09.2008, 14:05
Als vor schlag du köntest auf rb1-3 vdd geben und über dioden rb4-7 auf rb0 legen rb0 kanste dan als interupt für die abfrage nutzen wen du nicht permanent die tasten abfragen möchtest

andi.studi
07.09.2008, 15:58
definiere mist: drücke 1 und 4 was passiert??

taste 1 --> bit0 (portd) wird gesetzt = funktion gegeben.
taste 4 --> bit3 (portd) wird gesetzt = funktion gegeben.

wird aber nach der Taste 1 die Taste 4 gedrückt, springt die anzeige von bit 0 auf bit 3. = falsch bit 0 und 3 sollten high sein.

2. beispiel.

taste 2 --> bit1 (portd) wird gesetzt = funktion gegeben.
taste 5 --> bit4 (portd) wird gesetzt = funktion gegeben.

wird aber nach der Taste 2 die Taste 5 gedrückt, geht die anzeige aus (alles low). = falsch bit 1 und 4 sollten high sein.



spalten werden durchgeschaltet und Zeilen ausgelesen. wenn du jetzt zwei taster in der zeile drückst bekommst du ohne dioden einen kurzen. (port 0 auf high port 1 auf low und diese beiden sind durch die zwei taster und ein zeilenstück verbunden.

wieso bekomme ich einen Kurzschlüß?
ich definiere doch nur die gerade abgefragte Spalte als Ausgang mit logisch 0, alle anderen spalten werde als Eingang definiert und haben dank der integrierten und aktivierten pull up wiederstände des PORTB logisch 1 signal. dies sollte doch einen Kurzschluß verhindern bei mehr als 2 Tasten in einer Zeile.

beispiel zeile 3 (funktioniert)
taste 7 und taste 8 werden auch bei demeinsamen drücken richtig dargestellt. (bit 6 und 7 von portD sind high.

zeile 1 (mist)
anzeige geht aus beim drücken einer weiteren taste.




Wenn jede Taste einen eigenen Bit setzen würde, sollte auch keine Probleme bei gleichzeitig gedrückten Tasten in einer Zeile geben.


jede Taste setzt ja ein bit in der Variablen scan jede neue taste wird mit scan verodert. klappt leider nicht bei allen tasten.


2 Tasten abzufragen, das muss doch auch ohne Dioden oder Interrupts gehen. habe das auch mehrmals schon gelesen, leider hapert es an meiner Umsetzung.

hilfe

andi.studi
07.09.2008, 17:45
ich hab das jetzt mal ans display angeschloßen,
die unteren beiden zeilen funktionieren einwandfrei.

was ist an diesen denn anders??



//*******1.Spalte(1,4,7,*)************************** ***********************************************
TRIS_KEY = 0b11110000;
spalte2 = 1;
spalte3 = 1;
spalte1 = 0;
TRIS_KEY = 0b11111100;
Nop();
if (zeile1==0) code = code | 1; //1
if (zeile2==0) code = code | 8; //4
if (zeile3==0) code = code | 64; //7
if (zeile4==0) code = code |512; //*

//*******2.Spalte(2,5,8,0)************************** ***********************************************
TRIS_KEY = 0b11110000;
spalte1 = 1;
spalte2 = 0;
TRIS_KEY = 0b11111010;
Nop();
if (zeile1==0) code = code | 2; //2
if (zeile2==0) code = code | 16; //5
if (zeile3==0) code = code |128; //8
if (zeile4==0) code = code |1024; //0


//*******3.Spalte(3,6,9,#)************************** ***********************************************
TRIS_KEY = 0b11110000;
spalte2 = 1;
spalte3 = 0;
TRIS_KEY = 0b11110110;
Nop();
if (zeile1==0) code = code | 4; //3
if (zeile2==0) code = code | 32; //6
if (zeile3==0) code = code |256; //9
if (zeile4==0) code = code |2048; //#

return code;
}

andi.studi
07.09.2008, 19:27
\:D/ \:D/ \:D/ \:D/ \:D/ \:D/
so 2 Tasten werden nun gleichzeitig erkannt.
verodert und per led anzeige auf portD und auf dem display in dezimal dargestellt.

es lag an einem timing problem.
in jeder spalten abfrage funktionierten ja nur die letzten beiden if abfragen richtig sobalt 2 Tasten gedrückt waren.
mit 100µs wartezeit nachdem die zu scanende spalte aktiviert wurde funktionierte auch die 2. zeile richtig.
und nu mit 200µs klappt alles.



signed int KEY_Scancode (void)
{
signed int code=0x0000;

INTCON2bits.RBPU=0; //pull-up's an
TRIS_KEY = 0b11110000; // KEY-PORT bit 0,1,2,3 = Ausgänge (bit 0 für LCD_E=0)
PORTKEY = 0b11111110;

//*******1.Spalte(1,4,7,*)************************** ***********************************************

TRIS_KEY = 0b11111100;
spalte1 = 0;
delay100us(2);
if (zeile1==0) code = code | 1; //1
if (zeile2==0) code = code | 8; //4
if (zeile3==0) code = code | 64; //7
if (zeile4==0) code = code |512; //*

//*******2.Spalte(2,5,8,0)************************** ***********************************************

TRIS_KEY = 0b11111010;
spalte2 = 0;
delay100us(2);
if (zeile1==0) code = code | 2; //2
if (zeile2==0) code = code | 16; //5
if (zeile3==0) code = code |128; //8
if (zeile4==0) code = code |1024; //0


//*******3.Spalte(3,6,9,#)************************** ***********************************************

TRIS_KEY = 0b11110110;
spalte3 = 0;
delay100us(2);
if (zeile1==0) code = code | 4; //3
if (zeile2==0) code = code | 32; //6
if (zeile3==0) code = code |256; //9
if (zeile4==0) code = code |2048; //#

return code;
}



erste stufffe ist erklommen \:D/

jetzt gehts weiter mit der erkennung ob eine taste gedrückt ist, ob sie noch festgechalten wird, oder schon losgelassen wurde.


PicNick schrieb:

Ich persönlich würde für alle Tasten eine Bit-Matrix anlegen, die ich beim scannen einzeln vergleiche.
Matrix-Bit = 1 und TastenPin=1 --> nix zu tun
Matrix-Bit = 1 und TastenPin=0 --> taste (neu) gedrückt ->sende ON
Matrix-Bit = 0 und TastenPin=0 --> taste festgehalten, nix zu tun
Matrix-Bit = 0 und TastenPin=1 --> taste ausgeslassen--> sende OFF
und dann den Tastenpin in der Matrix merken

Das kann man nun unterschiedlich geschickt machen, aber das Prinzip bleibt

Was ist mit Marix-Bit gemeint, und womit wird er verglichen.

bin gespannt auf eire anregungen.

PICture
08.09.2008, 02:44
Hallo!

@ andi.studi

Gratulation! :)

Eine Pause zwischen zwei nachfolgenden Einlesungen habe ich als selbstverständlich betrachtet und leider nicht als mögliche Fehlerquelle berücksichtigt.

Viel Erfolg beim Lösen allen nächsten Problemen! O:)

MfG

PicNick
08.09.2008, 11:11
Nicht, dass die folgenden Programmzeilen besonders elegant oder effizient wären, aber zum Verständnis, was ich meine:

(beschränkt auf das Wesentliche)


static char Matrix[12];
//--------------------------------------------------------------
void KEY_Check (int index, int maske)
{
if ( Matrix[index] ^= ( PORTB & maske ) ) // änderung alt/neu
{
if ( PORTB & maske) // alt=0,neu =1
SendKeyOFF( index)
else
SendKeyON( index )
Matrix[index] = PORTB & maske; // merken
}
}
signed int KEY_Scancode (void)
{
spalte1 = 0; spalte2 = 1; spalte3 = 1;
KEY_Check (0 , 1);
KEY_Check (1 , 2);
KEY_Check (2 , 4);
KEY_Check (3 , 8);
spalte1 = 1; spalte2 = 0; spalte3 = 1;
KEY_Check (4 , 1);
KEY_Check (5 , 2);
KEY_Check (6 , 4);
KEY_Check (7 , 8);
spalte1 = 1; spalte2 = 1; spalte3 = 0;
KEY_Check (8 , 1);
KEY_Check (9 , 2);
KEY_Check (10 , 4);
KEY_Check (11 , 8);
}


Nebeneffekt "at first", weil ja alle Matrixbits auf 0 stehen: ALLE Tasten on, und dann gleich ALLE Tásten OFF.

Man müsste daher ganz am Anfang alle tasten auf "aus" stellen

for (int ix=0; ix < 12; ix++)
Matrix[ix] = 0xFF;

andi.studi
08.09.2008, 20:16
hallo PicNick,
danke für die erleuterung,

doch wie es aussieht stehe ich auf dem bit :-k
mir will einfach nicht klar werden was


if ( Matrix[index] ^= ( PORTB & maske ) )

macht.

was bringt mir z.b. den die bitweise verundung zwischen PORTB und maske " ( PORTB & maske )"?

bsp.
Taste PortB________ maske______resultat?
1:__ 1110 1100__0000 0001___0000 0000
4:__ 1101 1100__0000 0010___0000 0000
7:__ 1011 1100__0000 0100___0000 0100

2:__ 1110 1010__0000 0001___0000 0000
5:__ 1101 1010__0000 0010___0000 0010


für "Matrix[index] ^= ( PORTB & maske )" kann ich auch
"Matrix[index] = Matrix[index] ^( PORTB & maske )" schreiben, ist das richtig?

PicNick
09.09.2008, 08:52
Ich bin ein Koffer :oops:

"maske" muss natürlich den Postb-Bits der Tasten entsprechen, also
KEY_Check (0 , 0x10);
KEY_Check (1 , 0x20);
KEY_Check (2 , 0x40);
KEY_Check (3 , 0x80);



(PortB & maske ) ergibt ein Byte, das nur aus dem fraglichen Bit aus PortB besteht.

if ( matrix[index] ^= (PortB & maske ) ) ist ja EXCLUSIV ODER.
Das ergebnis ist also nur != 0, wenn das gefragte bit in Matrix und PortB verschieden ist



*schäm*

andi.studi
15.09.2008, 20:09
hi @ all ;)

vielen dank für alles, und vorallem danke ich PicNick,

super idee!!!

nun läuft es auch endlich stabiel

hier nen ausschnitt:


#define MAXB 12 // bestimmt die grösse von keybuffer (keybuffer[MAXB])//0..255


static int keybuffer[MAXB]={0,0,0,0,0,0,0,0,0,0,0,0}; //funktion bufferlöschne schreiben und in die init packen
static uint8 keycount=0;

void KEY_Check (uint8 index, uint8 maske)
{
static uint8 Matrix[12]= {0x10,0x10,0x10,0x20,0x20,0x20,0x40,0x40,0x40,0x80 ,0x80,0x80};
unsigned int code;
static uint8 i=1;

if ( Matrix[index] ^ ( PORTB & maske ) ) // änderung (alt=0/neu=1)
{
/*******************************************sende breakcode, taste losgelassen********************/
if ( PORTB&maske)
{ switch(index+100)
{
case 100: code=0x2001; break;
case 101: code=0x2002; break;
case 102: code=0x2004; break;
case 103: code=0x2008; break;
case 104: code=0x2010; break;
case 105: code=0x2020; break;
case 106: code=0x2040; break;
case 107: code=0x2080; break;
case 108: code=0x2100; break;
case 109: code=0x2200; break;
case 110: code=0x2400; break;
case 111: code=0x2800; break;
}
}
/*******************************************sende makecode, taste gedrückt**********************/
else
{ switch(index)
{
case 0: code=0x0001; break;
case 1: code=0x0002; break;
case 2: code=0x0004; break;
case 3: code=0x0008; break;
case 4: code=0x0010; break;
case 5: code=0x0020; break;
case 6: code=0x0040; break;
case 7: code=0x0080; break;
case 8: code=0x0100; break;
case 9: code=0x0200; break;
case 10: code=0x0400; break;
case 11: code=0x0800; break;
}
}
Matrix[index] = PORTB & maske; // merken Matrix[index] ist null bei gedrükter Taste

// füllt puffer mit make und break code ////////////////////////////////////////////////////////
// keybuffer[keycount++]=code; // code in aktuelles feld speichern und feld um 1 erhöhen
// if (keycount>MAXB-1) keycount=0 ; // wenn feld ende erreicht gehe zu feld anfang

if(code<=0x0800)
{
keybuffer[keycount] |= code; i=0;
}
if (code>=0x2000 && i==0)
{
keycount++; i=1;
}

if (keycount>MAXB-1) keycount=0;
}
}



uint8 KEY_scancheck (void)
{
INTCON2bits.RBPU=0; //pull-up's an
TRIS_KEY = 0b11110000; // KEY-PORT bit 0,1,2,3 = Ausgänge (bit 0 für LCD_E=0)
PORTKEY = 0b11111110;

TRIS_KEY = 0b11111100;
spalte1 = 0;
KEY_Check (0 , 0x10); //1
KEY_Check (3 , 0x20); //4
KEY_Check (6 , 0x40); //7
KEY_Check (9 , 0x80); //*
spalte1 = 1;

TRIS_KEY = 0b11111010;
spalte2 = 0;
KEY_Check (1 , 0x10); //2
KEY_Check (4 , 0x20); //5
KEY_Check (7 , 0x40); //8
KEY_Check (10, 0x80); //0
spalte2 = 1;

TRIS_KEY = 0b11110110;
spalte3 = 0;
KEY_Check (2 , 0x10); //3
KEY_Check (5 , 0x20); //6
KEY_Check (8 , 0x40); //9
KEY_Check (11 ,0x80); //#
spalte3 = 1;
}


musste aber: if ( Matrix[index] ^ ( PORTB & maske ) ) // änderung (alt=0/neu=1)
heisen und nicht ^= ;) // brauchte etwas länger um das zu finden ;)

nun versuch ich die funktion uint8 KEY_scancheck (void) über einen timer interrupt in regelmässigen abständen auszuführen.

wünscht mir glück ;)

und nochmals danke :)


mfg andi

PicNick
16.09.2008, 08:18
uiiii :oops:

naja, irgendwann lern' ich's

andi.studi
17.09.2008, 22:48
hej so langsamm wird was draus, nun funktioniert auch das einlesen per timer0 interrupt. \:D/

musste diesen aber ausschalten bei den funktionen die daten and LCD senden, welches sich auf dem gleichen port befindet, da sonst das LCD gesponne hat.

weiß jemand womit das zu tun hat?

beapbeap
19.09.2008, 21:53
sry habe keinen plan davon

8-[ 8-[

beapbeap
19.09.2008, 21:53
sry habe keinen plan davon

8-[ 8-[

andi.studi
14.10.2008, 22:28
HILFE

Hallo Microcontroller Freunde,

ich hab ein kleines großes Problemchen, irgendwas stimmt nicht mehr mit meiner abfrage. hoffe ihr könnt mir wieder etwas unter die arme greifen.

Problem äußert sich folgendermaßen:

sobald mehr als eine Taste in der selben Spalte oder Zeile betätigt werden sind alle Eingänge von PORTB high.

1--2--3-------RB4
| | |
4--5--6-------RB5
| | |
7--8--9------RB6
| | |
*--0--#----- RB7
| | |
| | |
1 2 3
RB RB RB

RB4..RB7 -> Eingang (interne Pull Up Aktiviert)

weiß jemand einen rat?

mfg andi