
In applicazioni in cui l’interfaccia utente è piuttosto elaborata, può essere utile utilizzare una tastiera standard PS/2 (le classiche tastiere per PC) anziché il classico keypad 4x4. Ecco dunque come gestire una tastiera PS/2 utilizzando un microcontrollore PIC.
Le tastiere PS/2 per PC sono oramai un prodotto consumer: si trovano a pochi euro ed hanno le forme più svariate ed i colori più strani tant’è che spesso sono veri e propri oggetti d’arredamento. A parte l’aspetto estetico, sfruttare una tastiera di questo tipo consente di risparmiare linee di I/O sul micro e, allo stesso tempo, di disporre di 101 tasti ai quali è possibile associare qualsiasi funzione. Per riuscire in questo intento è dunque necessario conoscere il protocollo PS/2 quindi disporre delle routine che siano in grado di gestirlo. È proprio questo l’intento di questo articolo.
La connessione PS/2
Codici dei tasti
Nel suo normale funzionamento, una tastiera PS/2 invia all’host (generalmente un PC, in questo caso il micro) una sequenza di bit (scan codes) che informa l’host su quale tasto è stato premuto. Qualora il tasto venga mantenuto premuto a lungo, il relativo codice viene inviato più volte, mentre al rilascio viene inviato il codice 0xF0 seguito dal codice relativo al tasto rilasciato. A ciascun tasto è associato uno ed un solo scan code come mostrato in figura 1 e la tastiera non è in grado di gestire autonomamente i tasti Lock (NumLock, CapsLock e ScrollLock). Ad esempio alla pressione di NumLock la tastiera invia il codice opportuno all’host il quale memorizza questa informazione e risponde con il codice che consente di accendere il LED NumLock.
Tra i vari tasti disponibili su una tastiera standard, ve ne sono alcuni noti come extended keys. Questi sono codificati con uno scan code composto da più byte come indicato nella figura 1. Ad esempio nel caso del tasto AltGr il codice associato è 0xE011 dove 0xE0 indica che si tratta di un extended key. In questo caso, al rilascio, verrà inviato prima 0xE0 seguito dal codice di rilascio 0xF0 quindi l’identificativo del tasto (0x11 nel caso di AltGr).
Codici dei comandi
Tra le informazioni che una tastiera può scambiare con un host (sia esso un PC che un microcontrollore) vi sono, oltre ai dati relativi ai singoli tasti, anche una serie di comandi. Di seguito sono riportati quelli principali.
Comandi da host a tastiera:
0xED (Impostazione LED) – è il comando utilizzato per la gestione dei LED NumLock, CapsLock e ScrollLock. Alla ricezione di questo comando la tastiera risponde con un ACK e si mette in attesa di un successivo byte che determina il nuovo stato dei LED con la seguente convenzione: bit2 CapsLock, bit1 NumLock, bit0 ScrollLock.
0xEE (Echo) – inviando questo comando alla tastiera, questa risponde con un ulteriore comando Echo.
0xF0 (Set Scan Code Set) – è possibile scegliere il set di scan code da utilizzare inviando alla tastiera il codice 0xF0 attendere l’ACK dalla tastiera, quindi inviare un byte (0x01, 0x02 o 0x03) per selezionare il set di codici da utilizzare. Inviando il byte 0x00 la tastiera risponde con un byte che identifica il set in uso.
0xF3 (Set Typematic Repeat Rate) – Inviando alla tastiera questo comando è possibile impostare il Typematic Repeat Rate ovvero il ritardo di ripetizione nell’invio dello scan code quando un tasto viene mantenuto premuto. Alla ricezione di 0xF3 la tastiera risponde con un ACK quindi si aspetta un byte che specifica il valore del Typematic Repeat Rate.
0xF4 (Keyboard Enable) – Svuota il buffer della tastiera, abilita la scansione e restituisce un ACK.
0xF5 (Keyboard disable) – Resetta la tastiera, disabilita la scansione e ritorna un ACK.
0xFE (Resend) – Alla ricezione di questo comando la tastiera invia nuovamente l’ultimo byte inviato.
0xFF (Reset) – Resetta la tastiera. Comandi da tastiera ad host:
0xFA (ACK) – notifica la corretta ricezione di un comando.
0xAA (Power On Self Test Passed) – notifica il corretto superamento del test automatico eseguito all’accensione.
0xEE (Echo) – è la risposta al comando echo inviato dall’host.
0xFE (Resend) – Alla ricezione di questo comando l’host invia nuovamente l’ultimo byte inviato.
0x00 o 0xFF (Error) – notifica una condizione di errore (tipicamente la saturazione del buffer).
Connessione con l’host
La connessione tra una tastiera PS/2 e l’host avviene per mezzo di un connettore Mini DIN maschio a 6 poli riportato in figura 2. Come mostra la stessa figura, dei 6 poli del connettore, solo quattro sono effettivamente utilizzati. I due fili di comunicazione (KBDclk e KBDdata) sono linee bidirezionali open-collector. Lo standard prevede che una tastiera non assorba una corrente superiore a 300mA e questo dato è importante nel dimensionamento delle linee di alimentazione nell’ipotesi di utilizzare la tastiera con un proprio hardware.
Il protocollo: da tastiera verso host
Come già detto, la comunicazione tra tastiera ed host è bidirezionale e l’host ha la priorità sulla comunicazione e può quindi inviare comandi alla tastiera in qualsiasi momento. La tastiera può invece inviare dati all’host solo se i segnali KBDdata e KBDclock sono entrambi a livello alto. In questo senso il segnale KBDclock può essere considerato come un “Clear-To-Send”: se l’host mantiene questo segnale a livello basso, allora la tastiera riempie il proprio buffer con i dati che via via arrivano sul canale KBDdata. La trasmissione dati da tastiera verso l’host, avviene in modo seriale su una trama di 11 bit (figura 3). Il primo bit è lo Start-Bit seguito dagli 8 bit dati (a partire da LSB), quindi il bit di parità e lo Stop-Bit. La trasmissione è sincronizzata dal clock (generato sempre dalla tastiera) che permette di leggere i singoli bit in corrispondenza dei fronti di discesa del KBDclock. La frequenza di clock è compresa tra 20 e 30 KHz.
Il protocollo: da host verso tastiera
La comunicazione tra host e tastiera ha inizio da parte dell’host portando a livello basso la linea dati. Al fine di prevenire la situazione anomala in cui la tastiera inizia la trasmissione dati contemporaneamente rispetto all’host, viene mantenuto il clock a livello basso per un tempo superiore a 60ms quindi mantenuta a livello basso la linea dati finché il segnale di clock non viene rilasciato (figura 4).
Una volta inviati gli otto bit ed il bit di parità la linea dati viene portata a livello alto (Idle) per un ciclo di clock, quindi la tastiera risponde con un ACK mantenendo a livello basso la linea dati per il successivo ciclo di clock. Se dopo la trasmissione del bit di parità la linea dati non viene messa nello stato Idle la tastiera continuerà a generare il segnale di clock fino al verificarsi di tale condizione.
Interfaccia con PIC
Acquisizione dello scan code
Lo schema elettrico dell’interfaccia con un microcontrollore PIC è piuttosto semplice ed è riportata in figura 5. Si noti che sono sufficienti due resistenze di pull-up sulle linee KBDdata e KBDclock.
Dal punto di vista del firmware, alla pressione di un tasto sulla tastiera, il PIC ne acquisirà il relativo scan code e lo convertirà nell’opportuno codice ASCII che verrà memorizzato in un registro interno per il successivo utilizzo. L’acquisizione dello scan code viene effettuata utilizzando l’interrupt scatenato dal fronte di discesa della linea KDBclock su RB0/INT. L’interrupt handler si occuperà di acquisire il codice dalla linea KBDdata. Con questa tecnica, dopo undici cicli di KBDclock (quindi dopo undici occorrenze di interrupt su RB0/INT) l’interrupt handler avrà completato l’acquisizione del dato notificando l’avvenuta ricezione mediante un flag ready. La conversione dello scan code nella corrispondente codifica ASCII viene effettuata dal programma principale una volta settato il flag ready e mantenendo la tastiera non attiva (linea KBDclock a livello basso). L’uso dell’interrupt permette di non bloccare il micro durante l’acquisizione del dato. Nel listato 1 l’interrupt handler.
ORG 0x04 ; collocazione dell’handler ISR ;*** Salvataggio del contesto *** bcf INTCON,GIE ; disabilita le interruzioni movwf W_TEMP ; salvataggio di W swapf STATUS,W ; salvataggio di STATUS movwf STATUS_TEMP clrf STATUS ; spostamento su bank 0 movfw PCLATH ; salvataggio di PCLATH movwf PCLATH_TEMP clrf PCLATH ; spostamento su ‘page zero’ bcf STATUS,IRP ; bank 0 movfw FSR ; salvataggio di FSR movwf FSR_TEMP ;*** attesa dello start bit *** tstf KBDcnt bnz _KBDdat btfsc KBDdatapin ; controllo dello start bit sulla linea KBDdata goto _KBDabort ; esce se lo start bit non è valido goto _INCF ;*** Acquisizione dato da tastiera _KBDdat movfw KBDcnt ; caricamento del contatore sublw d'8' ; w = d'8' - KBDcnt bnc _KBDpari ; salta se negativo(carry = 0) btfss KBDdatapin ; acquisizione dato bcf KBD,0x07 ; salvataggio del bit a 0 in KBD btfsc KBDdatapin bsf KBD,0x07 ; salvataggio del bit a 1 in KBD bz _INCF rrf KBD,F ; scorrimento di KBD goto _INCF ;*** si ignora il bit di parità*** _KBDpari movfw KBDcnt ; caricamento del contatore sublw d'9' ; w = d'9' - KBDcnt bnc _KBDstp ; salta se negativo(carry = 0) goto _INCF ;*** controllo del bit stop*** _KBDstp btfss KBDdatapin ; controllo di validità del bit stop goto _KBDabort ; bit stop non valido bsf KBDflag ; impostazione del flag ready ;*** disabilitazione della tastiera per prevenire l’arrivo di altri ; dati prima del completamento della decodifica in ASCII bsf STATUS,RP0 ; spostamento su bank 1 bcf STATUS,RP1 bcf KBDclktris ; imposta KBDclock come uscita bcf STATUS,RP0 ; spostamento su bank 0 bcf STATUS,RP1 bcf KBDclkpin ; disabilita la tastiera (KBDclock = 0) ;*** disabilitazione delle interruzioni su RB0/INT bcf INTCON,INTE goto _KBDterm _KBDabort clrf KBD ; dato non valido _KBDterm clrf KBDcnt ; azzeramento del contatore goto _KBDend ; fine dell’interrupt handler _INCF incf KBDcnt,F ; incremento del contatore _ISR_RS232error _KBDend bcf INTCON,INTF ; azzeramento dell’interrupt flag RB0/INT ;*** Ripristino del contesto ISRend movfw FSR_TEMP ; ripristino di FSR movwf FSR movfw PCLATH_TEMP ; ripristino di PCLATH movwf PCLATH swapf STATUS_TEMP,W ; ripristino di W movwf STATUS ; ripristino di STATUS swapf W_TEMP,F swapf W_TEMP,W RETFIE
Listato 1 |
Ovviamente per utilizzare la routine del listato 1 è necessario dichiarare le opportune variabili e definire le giuste costanti come indicato nel listato 2. In fase di inizializzazione è necessario configurare le linee KBDdata e KBDclock come ingressi, configurare RB0/INT in modo da scatenare interruzioni sul fronte di discesa (azzerando il bit INTEDG del registro OPTION_REG) quindi abilitare le interruzioni (mettendo ad “1” il bit INTE del registro INTCON).
#defineKBDdatapin PORTA,0x04 ; KBDdata #defineKBDdatatris TRISA,0x04 ; direzione per KBDdata #defineKBDclkpin PORTB,0x00 ; KBDclock (IntB) #defineKBDclktris TRISB,0x00 ; direzione per KBDdata org 0x0C FLAGreg ; contiene vari flag KBDcnt ; contatore KBD ; registro dati (scan code e ASCII) KBDcopy ; registro dati (backup) #defineRELflagFLAGreg,0x00 ; flag di rilascio (0xF0) #defineSHIflagFLAGreg,0x01 ; flag tasto SHIFT(0x12 / 0x59) #defineSPEflagFLAGreg,0x02 ; flag codice esteso (0xE0) #defineCAPflagFLAGreg,0x03 ; flag tasto CAPS LOCK (0x0D) #defineALTflagFLAGreg,0x04 ; flag tasto ALT(0x11) #defineCTRLflag FLAGreg,0x05 ; flag tasto CTRL (0x14) #defineKBDflagFLAGreg,0x06 ; flag ready ; registri per il salvataggio del contesto W_TEMP ; per il salvataggio di W STATUS_TEMP ; per il salvataggio di STATUS PCLATH_TEMP ; per il salvataggio di PCLATH FSR_TEMP ; per il salvataggio di FSR
Listato 2 |
Conversione in ASCII del dato acquisito
Alla completa ricezione di uno scan code da parte dell’interrupt handler, il registro KBD conterrà il codice acquisito dalla tastiera. A questo punto è necessario interpretarlo e convertirlo nella rispettiva codifica ASCII. La routine di decodifica (KBDdecode) può essere suddivisa in tre parti: la prima sezione imposta i flag in base al dato ricevuto dalla tastiera, la seconda individua un range in cui è compreso il dato ricevuto mentre la terza sezione opera la decodifica vera e propria restituendo nel registro KBD il risultato della conversione. Eccole analizzate nel dettaglio. Il listato 3 riporta la prima sezione della routine KBDdecode che si occupa di attendere il rilascio di un tasto quindi di impostare correttamente i flag in base al dato ricevuto.
KBDdecode ;Sezione di impostazione flag ;Controllo rilasciamento tasto (scan code: F0) movfw KBD ; Prelevamento dello scan code ricevuto movwf KBDcopy ; Copia dello scan code sublw 0xF0 ; è stato ricevuto F0? bnz _KBD_1 ; no, salta a _KBD_1 bsf RELflag ; si, aggiorna il flag RELflag bcf SPEflag ; Resetta sempre il flag codici estesi al rilascio goto _ClrStall ; esci _KBD_1 btfss RELflag ; controlla il RELflag, è 0? goto _KBD_2 ; si, salta a _KBD_2 bcf RELflag ; no, azzera RELflag (rilasciamento tasto in corso) movfw KBD ; premuto SHIFT(0x12)? sublw 0x12 bz _clrSHI ; si, salta a _clrSHI movfw KBD ; premuto SHIFT DESTRO(0x59)? sublw 0x59 skpnz ; no, salta _clrSHIbcf SHIflag ; azzera flag shift movfw KBD ; premuto CAPS LOCK (0x58)? sublw 0x58 bnz _clrALT ; no, salta a _clrALT btfss CAPflag ; il flag CAPflag è già settato? goto _setCAP ; no, salta a _setCAP bcf CAPflag ; si, azzera il flag goto _ClrStall ; esci _setCAPbsf CAPflag ; setta il CAPflag goto _ClrStall ; esci _clrALTmovfw KBD ; premuto ALT (0x11)?: sublw 0x11 bnz _clrCTRL ; no, salta a _clrCTRL bcf ALTflag ; si, azzera il flag goto _ALTdec ; salta alla decodifica di ALT _clrCTRL movfw KBD ; premuto CTRL (0x14)? sublw 0x14 bnz _ClrStall ; no, esci bcf CTRLflag ; si, azzera il flag goto _CTRLhex ; salta alla decodifica di CTRL
Listato 3 |
Il listato 4 riporta invece la sezione di codice relativa all’individuazione del range in cui collocare il dato ricevuto. Questa fase permette di accelerare notevolmente il processo di decodifica in quanto gli scan code (apparentemente assegnati con logica random ai vari tasti) sono in qualche modo legati alla codifica ASCII del relativo carattere.
_KBD_2 ;verifica se è stato preventivamente ricevuto un codice speciale(0xE0) btfss SPEflag goto _KBD_3 movfw KBD sublw 0x4A ; ricevuto lo scancode 4A? bnz _NOSUP ; no, salta a _NOSUP movlw '/' ; si, memorizza '/' in KBD movwf KBD goto _ClrStall _NOSUP ;verifica se lo scan code è minore o uguale a 0x5A movfw KBD sublw 0x5A ; 0x5A - W bc _KBD_3 ; se risultato è maggiore di 0, salta a _KDB_3 ;il valore è maggiore di 0x5A quindi è uno dei seguenti tasti: ;tasti freccia, 'Home', 'Del', 'PageUp', 'PageDown', 'Insert', 'End' ;Questa routine non prevede la gestione di tali tasti goto _ClrStall ;esci _KBD_3 ;verifica se lo scan code è minore o uguale a 0x61 movfw KBD sublw 0x61 ; 0x61 - w bc KBD_dec ; se risultato è maggiore di 0, salta alla tabella movlw d'14' subwf KBD,F ; KBD = KBD - d'14' movfw KBD sublw 0x61 ; 0x61 - w bnc _KBD_4 ; re risultato minore di zero, salta a _KBD_4 movlw d'25' addwf KBD,F ; KBD = KBD + d'25' goto KBD_dec _KBD_4 ;verifica se lo scan code è maggiore o uguale a 0x78 (0x86 - d'14') movfw KBD sublw 0x77 ; 0x77 - w bc KBD_dec ; Risultato maggiore uguale a zero, salta ;Verifica dei codici estesi(0xE0): 0xD2 = 0xE0 - d'14' movfw KBD sublw 0xD2 ; 0xD2 - w skpnz bsf SPEflag ; ricevuto codice esteso, imposta flag goto _ClrStall ; esci
Listato 4 |
Questa sezione di routine fa riferimento alla tabella di decodifica KBDtable che contiene le corrispondenze tra scan code e codice ASCII. Tale tabella (riportata nel riquadro di approfondimento) è relativa ad una tastiera americana (figura 1) e può essere adattata a qualunque altro tipo di tastiera. Il listato 5 riporta infine l’ultima sezione della routine che è dedicata alla decodifica vera e propria. In questa sezione viene caricata la tabella di conversione, viene fatta la conversione minuscolo/maiuscolo (qualora sia necessaria) e vengono gestiti i tasti premuti contemporaneamente al tasto SHIFT (per la tabella di conversione dei tasti premuti con lo SHIFT si faccia riferimento al secondo riquadro di approfondimento).
;***SEZIONE DI DECODIFICA KBD_decmovlw HIGH KBDtable movwf PCLATH movfw KBD call KBDtable ; Acquisizione della corrispondenza nella tabella movwf KBD ; salvataggio del risultato in KBD tstf KBD ; controllo se acquisito valore nullo bz _ClrStall ; valore nullo ;***Controllo su ALT *** ;btfsc ALTflag ; controllo del flag ;goto _ALTstr ; salta se flag è on ;***controllo su CTRL *** ;btfsc CTRLflag ; controllo del flag ;goto _CTRLstr ; salta se il flag è on ;***conversione dei caratteri in caratteri maiuscolo *** movfw KBD ; controllo del range (le lettere sono tra 0x60 e 0x7A) sublw 0x60 bc _SHICHR movfw KBD sublw 0x7A bnc _SHICHR ; fuori dal range (il tasto premuto non è una lettera), salta movfw KBD btfsc CAPflag ; controllo del flag caps lock goto _SHIset ; flag on btfss SHIflag ; controllo del flag shift goto _ClrStall ; nessun flag goto _cnvCAP ; flag CAPS lock, conversione in maiuscolo _SHIsetbtfsc SHIflag ; gestione del flag shift goto _ClrStall _cnvCAPaddlw d'224' ; conversione in maiuscolo (+ d'224') movwf KBD goto _ClrStall _ClrStall BANK1 bsf KBDclktris ; imposta la linea clock come ingresso BANK0 ; bcf KBDflag ; azzeramento dei flag bsf INTCON,INTE ; abilitazione interrupt su RB0/INT RETURN _SHIFT bsf SHIflag ; gestione del flag shift RETLW 0 ; azzeramento di w (dato non valido) _ALT bsf ALTflag ; Gestione flag ALT RETLW 0 ; azzeramento di w (dato non valido) _CTRL bsf CTRLflag ; gestione del flag CTRL RETLW 0 ; azzeramento di w (dato non valido) _CTRLstr ;non implementato _ALTstr ;non implementato _ALTdec ;non implementato _CTRLhex ;implementato goto _ClrStall ;*** Gestione della decodifica con tasto SHIFT _SHICHR btfss SHIflag goto _ClrStall ; controllo per tasti 'backspace', 'tab', 'linefeed' e 'enter' : movfw KBD sublw d'13' ; d'13' - w bc _ClrStall movfw KBDcopy sublw 0x61 ; 0x61 - w bnc _ClrStall movfw KBDcopy sublw 0x3C ; 0x3C - w bc _SHICH1 movlw d'61' subwf KBDcopy,F ; KBDcopy = KBDcopy - d'61' goto _SHICH3 ;*** KBDcopy > 0x24 ?*** _SHICH1movfw KBDcopy sublw 0x24 ; 0x24 - w bc _SHICH2 movlw d'35' subwf KBDcopy,F ; KBDcopy = KBDcopy - d'35' goto _SHICH3 _SHICH2movlw d'4' addwf KBDcopy,F ; KBDcopy = KBDcopy + d'4' _SHICH3movlw HIGH KBDSHIFTtable ; preparazione al caricamento della tabella movwf PCLATH movfw KBDcopy call KBDSHIFTtable ; Acquisizione del codice di conversione movwf KBD ; posizionamento del risultato in KBD goto _ClrStall
Listato 5 |
PS/2 in MikroBASIC
Per completezza, ecco come viene gestita la connessione PS/2 utilizzando un linguaggio di alto livello come il Basic. Come riferimento sarà utilizzato il compilatore MikroBASIC di Mikroelekttronika. MikroBASIC prevede che la tastiera sia collegata al PIC mediante le consuete linee di clock e dati su cui devono essere collegate due resistenze di pull-up. Il micro deve lavorare con un clock di almeno 6MHz e il flusso dati non viene gestito mediante interruzioni. La comunicazione con la tastiera è, in questo caso unidirezionale, quindi il PIC potrà ricevere i dati dalla tastiera, ma non potrà inviarli (ad esempio per accendere i LED di CapsLock o NumLock). Le routine messe a disposizione da MikroBASIC sono 2: Ps2_Init e Ps2_Key_Read.
Ps2_Init (dim byref port as byte, dim clock, data as byte)
La Ps2_Init inizializza il micro per la comunicazione con la tastiera e richiede tre argomenti ciascuno di un byte: il primo (port) è la porta su cui è connessa la tastiera; il secondo (clock) è il bit della porta usato per la linea KBDclock; il terzo (data) è il bit della porta usato per la linea KBDdata. È evidente che clock e data dovranno essere diversi tra loro e compresi tra 0 e 7. Per usare la tastiera sulla PORTB usando RB2 come clock e RB3 come data, sarà sufficiente chiamare la funzione PS2_Init come: Ps2_Init(PORTB, 2, 3).
Tabella di corrispondenzascan code – ASCII ORG 0x?? ; impostare qui l’indirizzo a cui caricare la tabella KBDtable ; valida per i tasti premuti senza SHIFT addwf PCL,F retlw 0 ; codice non valido retlw A'9' ; F9 -> 9 0x01 retlw 0 retlw A'5' ; F5 -> 5 retlw A'3' ; F3 -> 3 retlw A'1' ; F1 -> 1 retlw A'2' ; F2 -> 2 retlw A'2' ; F12 -> 2 retlw 0 retlw A'0' ; F10 -> 0 retlw A'8' ; F8 -> 8 0x0A retlw A'6' ; F6 -> 6 retlw A'4' ; F4 -> 4 retlw 0x09 ; TAB retlw A'~' retlw 0 retlw 0 ; 0x10 goto _ALT ; ALT (modifica solo il flag ALT) goto _SHIFT ; SHIFT(modifica solo il flag SHIFT) retlw 0 goto _CTRL ; CTRL (modifica solo il flag CTRL) DT "q1" retlw 0 retlw 0 retlw 0 ; 0x19 DT "zsaw2" retlw 0 retlw 0 0x20 DT "cxde43" retlw 0 retlw 0 retlw A' ' ; SPAZIO DT "vftr5" retlw 0 retlw 0 ; 0x30 DT "nbhgy6" retlw 0 retlw 0 retlw 0 DT "mju78" retlw 0 retlw 0 ; 0x40 DT ",kio09" retlw 0 retlw 0 DT ".?l;p" retlw A'-' retlw 0 retlw 0 ; 0x50 retlw 0 DT "'" retlw 0 retlw A'[' retlw A'+' retlw 0 retlw 0 retlw 0 ; CAPS LOCK, (modifica solo il flag CAPflag al rilascio) goto _SHIFT ; SHIFT goto _CRLF ; CR,LF 0x5A retlw A']' retlw 0 retlw A'|' retlw 0 retlw 0 retlw 0 retlw A'<' ; 0x61 DT "0.2568" retlw 0 ; ESCAPE 0x76 retlw 0 ; NUM LOCK DT "1+3-*9" retlw 0 ; SCROLL LOCK 0x7E retlw 0x08 ; BACKSPACE retlw 0 ; retlw 0 ; retlw A'1' ; 0x82 retlw A'7' ; retlw A'4' KBDtableEND retlw A'7' Struttura della KBDtable per i tasti premuti senza SHIFT
Ps2_Key_Read (dim byref value, special, pressed as byte) as byte
Questa è la funzione che ritorna informazioni sul tasto che è stato premuto sulla tastiera. L’uscita di tale funzione darà il valore 1 se la lettura del dato dalla tastiera è avvenuta regolarmente, oppure 0 se il dato non è stato letto correttamente. Nel primo caso la variabile value conterrà direttamente il codice ASCII relativo al tasto premuto (per i tasti relativi ai caratteri, numeri, segni di punteggiatura e spazio) tenendo conto dell’inserimento o meno del CAPS Lock; special è invece un flag che notifica la pressione dei tasti speciali (F1, F2, …, Enter, Esc, ecc…); infine pressed vale 1 se il tasto è premuto oppure 0 se rilasciato. Tale funzione deve essere chiamata necessariamente dopo la Ps2_Init. Un esempio di uso di tale funzione può essere quello del listato 7 in cui il programma entra in un loop infinito leggendo i caratteri dalla tastiera ed esce dal ciclo solo se viene premuto il tasto Enter (codice ASCII 13). Si noti che la condizione di uscita prevede un controllo sia sul codice ASCII (13, appunto) che sul flag spec relativo ai tasti speciali.
Ps2_Init (PORTB,2,3) do if Ps2_Key_Read(val, spec, press) =1 then if (val=13) and (spec=1) then break end if end if loop until FALSE
Listato 7 |
Tastiere wireless
Una volta noto il protocollo di trasmissione, "tagliare i fili" diviene abbastanza semplice. La comunicazione è composta da una serie di bit consecutivi quindi utilizzando un semplicissimo modulo ibrido in radiofrequenza è possibile remotizzare l'intera tastiera rendendola wireless. La scelta è vasta data l'offerta del mercato: moduli ibridi in AM o FM alle frequenze di 433MHz o 868MHz. Viste le esigue distanze in gioco, non è da escludere anche una comunicazione ad infrarossi anche se questa tecnologia richiede che trasmettitore e ricevitore siano visibili reciprocamente. Nella figura 6 alcune possibili soluzioni per la remotizzazione della tastiera.
Tabella di corrispondenza scan code – ASCII (con tasto SHIFT) KBDSHIFTtable addwf PCL,F DT "&*$#<" ; 0x3D - 0x41 retlw 0 ; dato non valido retlw 0 retlw 0 DT ")(" ; 0x45 - 0x46 retlw 0 DT "%>/" ; 0x48 - 0x4A retlw 0 retlw A':' ; "\" 0x4C retlw 0 DT "_`^" ; 0x4E - 0x50 retlw 0 retlw A'"' ; 0x52 retlw 0 DT "{=" ; 0x54 - 0x55 retlw 0 retlw A'!' ; 0x57 retlw 0 retlw 0 retlw 0 retlw A'}' ; 0x5B retlw 0 retlw 0x5C ; 0x5D retlw 0 retlw A'@' ; 0x5F retlw 0 KBDSHIFTtableEND retlw A'>' ; 0x61 Struttura della KBDSHIFTtable per i tasti premuti con SHIFT
Leggi anche:
Sniffare i pulsanti premuti di una tastiera

Le tastiere PS2 sono ormai scomparse, ma ho voluto pubblicare ugualmente questo articolo per avere un progetto di riferimento comunque. Molti sistemi embedded ancora utilizzano vecchie tastiere Ps2. Inoltre è sempre utile didatticamente 😉
E’ un bel programma didattico che mette in luce molto dettagliatamente le funzionalità della keyboard. Molto utile anche per fare dei test all’interno di un software più complicato.