|
Display+tangentbord+CPU lämpliga för utveckling av billiga pryttlar.
Display:
DOGM163 (lcd-module.de) ELfa 75-407-63
Seriell (enkelriktad) och parallell interface (dubbelriktad)
Chip= ST7036.
Art.nr. 75-407-63. Kostar120kr+moms=150kr hos Elfa.se
CPU:
Microchip 16C690 (kjell.com)
39kr hos kjell.com
Tangentbord:
Deltaco TB-72 (www.deltaco.eu)
150kr hos Teknikmagasinet.se
Här är C-program ni behöver för att göra en pryl som kan ta emot tecken från en keypad
och visa dessa tecken på PC'n (t.ex. via PICkit2 UART Tool):
MAIN_keyPad.c - Läser tangentbordet och visar tecken på PC'n.
getTkn.c - Hämtar tecken från den numeriska keypad'en.
baudChar.c - Skickar tecken till PC med 1200 .. 19200 baud
Allt ovan zip'at i en katalog PicKbd inkl. hexkoden
Om du genast testar hexkoden på ett PICkit2 demoboard måste du kapa jp4,
annars kortsluts datan från tangentbordet.
Gratis versionen av kompilatorn Cc5x kan kompilera programmet ovan.
Här är C-program ni behöver för att göra en pryl som kan ta emot tecken från tangentbordet
och visa dessa tecken på PC'n och på displayen:
MAIN_PicKbdDisplay.c - Läser tangentbordet och visar tecken på display och PC
getKey.c - Hämtar tecken från tangentbordet.
baudChar.c - Skickar tecken till PC med 1200 .. 19200 baud
keyToTkn.c - Gör om keyboardkod till ASCII kod.
displayInstr.c - Skickar ett commando till displayen
displayTkn.c - Skickar ett tecken till displayen
delayx10ms.c - Väntar n*10ms
Allt ovan zip'at i en katalog PicKbdDisplay inkl. hexkoden
Om du genast testar hexkoden på ett PICkit2 demoboard måste du kapa jp4,
annars kortsluts datan från tangentbordet.
Gratis versionen av kompilatorn Cc5x kan kompilera programmet ovan.
Anpassad för (och testad med) "PICkit2 UART Tool" som terminal.
___________ ___________
| \/ |
+5V---|Vdd 16F690 Vss|---GND
|RA5 RA0/AN0/(PGD)|---bbTx ->- PK2Rx
|RA4 RA1/(PGC)|---bbRx -<- PK2Tx
Pk2 VPP---|RA3/!MCLR/(Vpp) RA2/INT|
|RC5/CCP RC0|--+LED--gnd
Disp C/D--|RC4 RC1|--Disp Data
KBD Rx--|RC3 RC2|--Disp Clock
KBD Ck--|RC6 RB4|
|RC7 RB5/Rx|
|RB7/Tx RB6|
|________________________|
Display anslutningar:
pin 1-20 inte anslutna
pin:
21 inte ansluten
22 inte ansluten
23 gnd
24 5V
25 5V
26 5V
27 gnd
28 in PIC PORTC.1 Seriell Data
29 in PIC PORTC.2 Klocka
30 5V
31 5V
32 5V
33 5V
34 5V
35 5V
36 5V (E)
37 5V (R/W)
38 gnd (CS)
39 in PIC PORTC.4 Controll=1, Data=0
40 5V (RESET)
Tangentbordet har en USB-kontakt som inte är sann USB utan bara en seriell utgång, som kan kopplas in direkt till CPU'n.
Jag har sedan bilden togs klippt av tangentbord-sladden (som var onödigt lång) och anslutit en DIN-kontakt istället.
Tangentbordet drar ca 1.5mA i vila.
Jag rekomenderar att du skaffar en passande USB-kontakt "hona" som du kan ansluta direkt till tangenbordets USB-kontakt.
Det är dock vilseledande eftersom det inte blir en sann USB ingång.
Men det ger fördelen att du kan "hotswap'a" tangentbordet utan att det riskerar att gå sönder.
Min version av getKey ovan stödjer inte hotswap.
USB-pin 2 kan anslutas direkt till RX (portB.5) och USB-pin3 direkt till CK (portB.7) på 16C690 CPU'n.
1 5V
2 RX (Data- på en sann USB pryl)
3 CK (Data+ på sann USB pryl)
4 GND
Jag har istället lött dit denna DIN-kontakt:
 Numrering framifrån hylskontakten.
Med DIN-kontakt kan man ansluta gamla AT-tangentbord (och PS2 och USB tangentbord med anpassningsplugar).
1 CK
4 GND
2 RX
5 5V
3
Så här ser tx och ck ut när man trycker ner keypaddens enterknapp.
Jag tolkar oscilloskopets datapulser som:
0.0000.0111.01 - 0.0101.1010.11 vid +klockflanker
Då stämmer det bra med EN startbit! ( Hexdata blir 0.E-A.5, dvs 0xE0 följt av 0x5A)
Jag testade att läsa in alla databitar från tangentbordet
med det enkla och därför snabba (kräver ca10us/datapuls) programmet nedan.
När programmet nedan läser in oscilloskop-pulserna ovan får jag
dessa databitar.
Vid lästrigg på -klockflanker:
0.0000.0111.01 = 0E (syns på oscilloskopet) LSB först
0.0101.1010.11 = A5 (syns på oscilloskopet)
0.0000.0111.01 = 0E
0.0000.1111.11 = 0F
0.0101.1010.11 = A5
Data stämmer då med 1 startpuls.
Nedan ett enkelt struktur-diagram för programmet getTkn.c.
Nedan ett mer detaljerat struktur-diagram för det färdiga programmet getTkn.c.
När man trycker på enter så skickar keypad'en:
E0 (3ms) 5A (0.1s) E0 (3ms) F0 (3ms) 5A
När man trycker ned knappen skickas E0 5A.
När man släpper knappen skickas E0 F0 5A.
Håller man den intryckt skickas E0 5A 10ggr/s.
Nedan getTkn.c
/* Hämtar tecken från en keyPad
Använder kod från www.elektronikutveckling.com,
radera inte denna info om du modifierar eller kopierar delar
från denna fil. Använd på egen risk, rätta felaktigheter.
Använder dessa PIC 16F690 portar:
Kopiera till huvudprogrammet.
ANSEL.7 = 0; // PORTC.3 ej analog
TRISC.3 = 1; // KeyPad Rx in
ANSELH.0= 0; // PORTC.6 ej analog
TRISC.6 = 1; // KeyPad Clk in
*/
char getTkn(void)
{ // getTkn() returnerar keypad'ens tecken för NEDtryckt tangent, annars 0x7.
// Made by elektronikutveckling.com
// In:
// Om data1 != EO || F0 så är det ett tecken.
// Om data1 == E0 så är nästa tal ett tecken eller F0.
// Om data1 eller data2 == F0 så är nästa tal samma tecken (knapp uppe igen).
// Ut: endast teckenkoden vid nedtryckt tangent.
char bitCount, key, tkn, i;
char data1;
char data2;
char data3;
char data4;
char data5;
// läs in 3st eller 5st 11bit byte:
// tecken ska ha buffrats i keypaden genom att hålla clock låg tills nu
PORTC.6=1; // "clock"
TRISC.6=1; // nu kan keypaden skicka sparat tecken
PSA=0; // TMR0 används som timer.
T0CS=0; // Intern Fosc/4 används som klocka för TMR0
/* PS<2:0> prescaling
000 1:2
001 1:4
010 1:8
011 1:16
100 1:32
101 1:64
110 1:128
111 1:256 */
TMR0=0; // Reset'ar TMR0 register och prescaler.
PS2=1; // Sätter prescalern= 1:256 på detta sätt
PS1=1; // TMR0==20 borde ge ca 20 * 256*1us = 5 ms
PS0=1;
while (PORTC.6) {if(TMR0>20) {key=0x7; goto END;} } // hitta flank eller AVBRYT
while (!PORTC.6) {if(TMR0>20) {key=0x7; goto END;} } // hitta flank eller AVBRYT
// klockan har nu gått från hög till låg till hög
Carry = PORTC.3; // läser data vid klock +flank
data1 = rr( data1); // Carry blir LSB , ? blir Carry
bitCount = 8;
do {
while (PORTC.6);
while (!PORTC.6);
Carry = PORTC.3;
data1 = rr( data1);
} while ( -- bitCount > 0); // (startbiten hamnar till slut i Carry)
bitCount = 2;
do {
while (PORTC.6);
while (!PORTC.6);
} while ( -- bitCount > 0);
key=data1; // Klart om data1 inte är E0 eller F0.
// key ändras nedan om så inte var fallet.
/* -------------- (S2) i strukturdiagramet ------------- */
if(data1==0xE0) // Om 0xE0 läses alltid en byte till
{ // Antingen "enter" eller "/"
bitCount = 9;
do {
while (PORTC.6);
while (!PORTC.6);
Carry = PORTC.3;
data2 = rr( data2);
} while ( -- bitCount > 0);
bitCount = 2;
do {
while (PORTC.6);
while (!PORTC.6);
} while ( -- bitCount > 0);
key=data2; // Klart om data2 är "/" eller "enter".
// Alt. ignorera "enter knapp nere"
// och välj "enter knapp uppe" istället.
/* -------------- (S3) i strukturdiagramet ------------- */
if( data2==0xF0 ) // data3 = "/" , "enter". (knapp uppe)
{
bitCount = 9;
do {
while (PORTC.6);
while (!PORTC.6);
Carry = PORTC.3;
data3 = rr( data3);
} while ( -- bitCount > 0);
bitCount = 2;
do {
while (PORTC.6);
while (!PORTC.6);
} while ( -- bitCount > 0);
key=0x7; // Jag ignorera key knapp uppe.
// (Alt. "enter knapp uppe" istället för
// "enter knappr nere" kan vara vettigt.)
}
}
/* -------------- (S4) i strukturdiagramet ------------- */
if(data1==0xF0) // Tangenkoden upprepas efter 0xF0 när knapp uppe igen.
{
bitCount = 9; // (Alt. lösn: klocka 11 bitar och strunta i data.)
do {
while (PORTC.6);
while (!PORTC.6);
Carry = PORTC.3;
data2 = rr( data2);
} while ( -- bitCount > 0);
bitCount = 2;
do {
while (PORTC.6);
while (!PORTC.6);
} while ( -- bitCount > 0);
key=0x7; // Jag struntar i när knapp uppe. (Alt. returnera annars data2)
}
// Inläsningen klar av 1,2 eller 3st byte.
END:
TRISC.6=0;
PORTC.6=0; // nu kan keypaden inte skicka tecken (tecken sparas i keyPad'en)
switch(key)
{
case 0x4A: tkn = '/'; break;
case 0x7C: tkn = '*'; break;
case 0x7B: tkn = '-'; break;
case 0x79: tkn = '+'; break;
case 0x5A: tkn = '='; break; // Min översättning av 'enter'
case 0x71: tkn = '.'; break;
case 0x70: tkn = '0'; break;
case 0x69: tkn = '1'; break;
case 0x72: tkn = '2'; break;
case 0x7A: tkn = '3'; break;
case 0x6B: tkn = '4'; break;
case 0x73: tkn = '5'; break;
case 0x74: tkn = '6'; break;
case 0x6C: tkn = '7'; break;
case 0x75: tkn = '8'; break;
case 0x7D: tkn = '9'; break;
case 0x77: tkn = 'N'; break; // Min översättning av 'Num Lock'
case 0x07: tkn = key ;
}
return tkn;
}
Jag har nedan även försökt använda den inbyggda UART'en för att ta emot keypad tecken,
men tyvärr måste den reset'as efter varje läst tecken.
Varför måste PIC'en reset'a sitt register mellan varje läst byte?
PIC'ens UART måste anpassas till TVÅ startbitar för att läsa in rätt data.
UART'en bryr sig inte om satt klockflank verkar det som. En bugg i PIC?
Det verkar som PIC'en alltid triggar på +flank klocka vid synkron slave mottagning
även om jag ställer in den (med SCKP=0) till -flank triggning.
Eller har jag missat hur man ställer in klockflank vid synkron slave rx UART?
Enligt PIC manualen:
SCKP=1=Data ändras vid -flank vid TX (data läses vid +flank).
SCKP=1=Clock idle high och +flank trigg för läsning
SCKP=0=Clock idle low och -flank trigg för läsning
Data blir samma oavsett om jag sätter SCKP hög eller låg.
Jag har testat att invertera klockan från keypad'en. (Fysiskt med en yttre grind.)
Det blev lite sämre, så det tyder på att SCKP inte
har någon funktion vid synkron slave rx. Databladet är troligen missvisande.
På grund av PIC'ens UART bugg (?) har jag skrivit getTkn till
att inte använda UART'en utan istället själv läsa in varje databit.
Det går bra tackvare att keypaden har en egen teckenbuffer
som man kan använda genom att dra klockan låg när PIC'en är upptagen med annat.
Nedan är programmet för den hopplösa UART'en som jag kastat bort många dagar på.
"Bit bang" a la ovan fungerar stålande jfm programmet nedan.
char getKey(void) // borde fungera men PIC'en hinner inte alltid med.
{
// OBS, PS2-tangentbord och Keypad har 2 startbitar enligt UARTE'n. (Knasigt)
// MSB hamnar som paritetsbit,
bit paritet;
char key, skrot, i;
if(OERR==1) // UART overrun (för mycket indata)
{
CREN = 0; // radera UART
SPEN = 0; // reset UART
SPEN = 1;
CREN = 1;
skrot = RCREG; // borde sätta RCIF =0
skrot = RCREG;
key= 0x7; // ignorera key
return key;
}
paritet=RX9D; // paritetsbiten motsvarar MSB biten pga 2 startbitar.
Carry=paritet; //
key = RCREG; // RCIF blir =0 efter läsning av RCREG.
key = rr(key); // Skiftar in MSB, skiftar bort starbit från LSB
CREN = 0; // radera UART
SPEN = 0; // reset UART
seganer(6);
SPEN = 1;
CREN = 1;
if( (key!=0xE0)&&(key!=0xF0) ) key=0x7; // Om inte E0, F0, ignorera key
if(key==0xE0)
{
while(RCIF==0);
paritet=RX9D; // paritetsbiten mostvarar MSB biten pga 2 startbitar.
Carry=paritet; //
key = RCREG; // RCIF blir =0 efter läsning av RCREG.
key = rr(key); // Skiftar in MSB, skiftar bort starbit från LSB
CREN = 0; // radera UART
SPEN = 0; // reset UART
seganer(6);
SPEN = 1;
CREN = 1;
if( key!=0xF0 ) key=0x7; // Om inte F0, ignorera key
}
if(key==0xF0)
{
while(RCIF==0);
paritet=RX9D; // paritetsbiten mostvarar MSB biten pga 2 startbitar.
Carry=paritet; //
key = RCREG; // RCIF blir =0 efter läsning av RCREG.
key = rr(key); // Skiftar in MSB, skiftar bort starbit från LSB
CREN = 0; // radera UART
SPEN = 0; // reset UART
seganer(6);
SPEN = 1;
CREN = 1;
}
return key;
}
Fotot nedan duger väl som kopplingsschema? Nej, jag har flyttat sladdar sedan fotot togs.
Se istället det enkla "+5V---|Vdd " schemat längst upp på sidan.
Displayen ovan visar det tecken som binärkoden motsvarar för displayen,
det är inte samma tecken som tryckt på tangentbordet.
-0-0-0 motsvarar -Paritetsbiten-FrameError-OverrunError
Ett PS2 tangentbord ger rätt koder enligt kbd koder
Ett tryck på "1" på keypaden ska enligt tabellen ge 69H och det stämmer, det motsvarar tecknet "i" på displayen.
Dator-nostalgi: Min Nascom Z80 dator från 1981. Den motsvarar ungerfär en PIC idag.
Sänd mig ett email om du har gjort en användbar programsnutt.
spam@elektronikutveckling.com ersätt "spam" med "notspam"
PGP public key.
|
|
Ledig reklamplats? |