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.