Comunicazione con un mouse PS/2

mediante PIC 16F84

Siete il visitatore n.

Click here for English version

Pagina ottimizzata per risoluzione 1024x768

     


Torna alla Home Page

Recapiti



Argomenti simili su questo sito:

PIC 16F84 F.F. Evaluation Board
Connessione e comunicazione PIC-mouse PS/2
Connessione di microcontrollori a porte RS-232 e dispositivi PS/2
 
Introduzione

Come spiegato nell'articolo sulla comunicazione hardware fra host e mouse PS/2, per testare sperimentalmente il protocollo da utilizzare nella comunicazione con un mouse PS/2 ho interfacciato quest'ultimo con un PIC 16F84 opportunamente programmato.

Se siete interessati ad un programma più completo, scritto per il PIC 16F877 ma adatto anche a molti altri microcontrollori PIC, potete dare un'occhiata all'articolo Connessione e comunicazione PIC-mouse PS/2 su questo stesso sito.

Nota bene: i dispositivi PS/2 sono diversi dai mouse seriali sia per quanto riguarda il protocollo di comunicazione che per quanto riguarda i livelli elettrici; nei mouse PS/2 i livelli utilizzati per l'alimentazione e la scambio dati sono 0 e +5V, in quelli seriali troviamo invece i livelli della RS-232, +12V e -12V. Questo articolo è relativo alla gestione di un mouse PS/2. Anche il PIC, quindi, deve essere alimentato con una tensione di +5V. In particolare, i terminali di comune (o massa) di PIC e mouse PS/2 devono essere collegati fra loro; stessa cosa per i terminali a +5V.

Per connettere mouse e microcontrollore suggerisco una presa PS/2 volante, alla quale connettere i 4 fili necessari. Tali fili possono essere portati su una basetta prototipi, e collegati su di essa agli opportuni piedini del PIC, dai quali si avrà cura di far giungere i fili necessari. Per far funzionare il PIC ho utilizzato la versione precedente della Evaluation Board descritta nell'articolo PIC 16F84 F.F. Evaluation Board su questo stesso sito. Per le connessioni vedere l'articolo citato in precedenza, l'eventuale piedinatura dei connettori PS/2 e le prime righe del listato. Se in questo modo il mouse non desse segno di vita, connettere due resistori di pull-up fra i piedini data e clock e l'alimentazione (che, ribadisco, deve essere la stessa per microcontrollore e mouse). Valori adatti dovrebbero aggirarsi su 3-10 KOhm.

Fate attenzione alle connessioni, onde evitare spiacevoli danni ai dispositivi! Prima di rovinare un PIC o un mouse, se proprio non siete sicuri di agire correttamente potete scrivermi.

Avvertenze

Il materiale contenuto in queste pagine costituisce il frutto di prove preliminari, sviluppo e verifica del progetto eseguiti in prima persona dall'autore di questa pagina.

L'autore garantisce l'assoluta originalità del materiale, pur ovviamente non escludendo che in rete sia possibile incontrarne di analogo.

Trattandosi di materiale messo gratuitamente a disposizione di chiunque lo desideri, ne è assolutamente vietata ogni forma di utilizzazione a fini commerciali. Non mi assumo naturalmente alcuna responsabilità per danni diretti o indiretti a cose o persone derivanti dalle informazioni attinte da questo articolo.

I marchi PIC e Microchip sono registrati.

Il programma assembler

A seguire il listato del programma assembler. Come si nota dal listato, si tratta sostanzialmente di una serie di routine per inviare comandi al mouse e memorizzarne le risposte. Trattandosi di un programma che mi è servito per condurre dei test, esso non è ottimizzato, né per quanto riguarda l'occupazione di memoria, né in riferimento ad altri aspetti. Contiene inoltre qualche sezione che mi è servita solo per verificare la corrispondenza fra il protocollo reale e quello descritto in alcuni documenti in rete (ho riscontrato una importante differenza; la corretta descrizione del protocollo di comunicazione si trova nell'articolo sulla comunicazione hardware fra host e mouse PS/2 in questo stesso sito). Per indicare a quale sezione del programma si sia arrivati durante l'esecuzione ed eventuali condizioni di errore, è previsto il lampeggio diversificato di un led collegato ai piedini del PIC (per chi non lo sapesse, è necessario un resistore in serie al LED; valori adatti da 330 Ohm a 1KOhm). I valori utilizzati per i cicli di attesa si riferiscono ad una frequenza di clock di 4 MHz, ovvero di 1 milione di istruzioni al secondo. I dati inviati dal mouse su spostamento e stato dei pulsanti non sono utilizzati. A voi il compito di scrivere programmi adatti alle vostre applicazioni, e di suggerirmi eventuali errori contenuti in qualche sezione di questo.

 

;pag.1

; nome file: mouseps2.asm
;
;
; riceve i dati in modo seriale da un mouse PS/2.
; le linee utilizzate sono due : clock e data.

; Poiché queste linee dovrebbero essere di tipo
; open collector, secondo quanto stabilito dal
; protocollo PS/2, sono utilizzati i piedini
; RA2 (Clock) ed RA3 (Data) come uscite
; BASSE quando è l'host a pilotarle,
; mentre quando devono essere alte o devono
;essere pilotate dal mouse vengono
; configurate come ingressi.

; RA0 (Clock) ed RA1 (Data) sono utilizzati
; come ingressi per testare le linee
; omonime.

; RB0 è utilizzata (come uscita) per indicazioni
; sullo stato del colloquio
; e su errori di ricezione.

PROCESSOR 16F84

RADIX DEC

__CONFIG 3FF1H

; XT

; /PWRO enable

; WDT disable

INCLUDE "P16F84.INC"

TOCS EQU 05H

CIN EQU 0
DIN EQU 1
COUT EQU 2
DOUT EQU 3
STBIT EQU 0
ENDBIT EQU 1

RA0 EQU 0
RA1 EQU 1
RA2 EQU 2
RA3 EQU 3
RA4 EQU 4
RB0 EQU 0
RB1 EQU 1
RB2 EQU 2
RB3 EQU 3
RB4 EQU 4
RB5 EQU 5
RB6 EQU 6
RB7 EQU 7

ORG 0CH

count RES 1

; pag.2

cbit RES 1
cbyte RES 1
delay1 RES 1
delay2 RES 1
delay3 RES 1
byteo RES 1
byteio RES 1
bytein RES 1
parbit RES 1
byte1 RES 1
byte2 RES 1
byte3 RES 1
byte4 RES 1
serv RES 1

hexd0 RES 1
hexd1 RES 1
hexd2 RES 1
decd0 RES 1
decd1 RES 1
decd2 RES 1
currd RES 1

number RES 1
workdi RES 1
servst RES 1
servw RES 1
servir RES 1

; ATTENZIONE: mantenere sempre a 0 il bit
; RP0 di STATUS ( selezione banco 0)
; per leggere il TMR0, settare tale bit solo ove
; serva e poi riazzerarlo

ORG 00H

goto start

ORG 50H

start

bsf STATUS,RP0

; RB1-7: INPUT
; RB0: INPUT

movlw 11111111B
movwf TRISB

; RA4 :INPUT (non utilizzato)
; RA3, RA2 : INPUT
; RA1, RA0 : INPUT

movlw 11111111B
movwf TRISA
bcf STATUS,RP0

; pag.3

; disattiva Clock e Data

movlw 11111111B
movwf PORTA
movlw 11111111B
movwf PORTB
bsf STATUS,RP0

; assegna al tmr0 la fosc/4

bcf OPTION_REG,TOCS

; assegna il prescaler al tmr0 con valore 256
; (111)

; bsf OPTION_REG,PSA
; bsf OPTION_REG,PS2
; bsf OPTION_REG,PS1
; bsf OPTION_REG,PS0
bcf STATUS,RP0

; movlw 00H
; movwf hexd2
; movwf hexd1
; movwf hexd0
; movwf decd2
; movwf decd1
; movwf decd0
; movwf number
; movwf servst
; movwf servw
; movwf serv
; movlw 00H
; movwf currd
; movwf workdi
; movlw 00H
; movwf count

movlw 00H
movwf TMR0

; attende 1 s

call del1s

; emette tre volte il segnale di comando inviato
; per indicare l'inizio operazioni

call cmdsnt
call cmdsnt
call cmdsnt

; invia il comando di reset (FFH)

movlw 0FFH
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt

; pag.4

; attende 1 s

call del1s

; emette il comando di enable (F4H)

movlw 0F4H
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt

; attende 1 s

call del1s

; emette il comando di impostazioni di default
; (F6H)

movlw 0F6H
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt

call del1s

; richiede la trasmissione dati (EBH)

movlw 0EBH
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt

call del1s

; richiede la trasmissione dati (EBH)

movlw 0EBH
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt

call del1s

; set stream mode (EAH)

movlw 0EAH
movwf byteo
movwf byteio

; pag.5

call cmdts
call sendby
call cmdsnt
call del1s

; richiede la trasmissione dati (EBH) dopo
; aver settato lo stream mode

movlw 0EBH
movwf byteo
movwf byteio
call cmdts
call sendby
call cmdsnt
call del1s

; ricezione dati continua (ogni 100 ms)

datain
call del.1s

; richiede la trasmissione dati (EBH)

movlw 0EBH
movwf byteo
movwf byteio
call sendby
call recby
movf byteio,W
xorlw 0FFH
btfsc STATUS,Z
goto datain
movf bytein,W
movwf byte4
call recby
movf byteio,W
xorlw 0FFH
btfsc STATUS,Z
goto datain
movf bytein,W
movwf byte3
call recby
movf byteio,W
xorlw 0FFH
btfsc STATUS,Z
goto datain
movf bytein,W
movwf byte2
call recby
movf byteio,W

; pag.6

xorlw 0FFH
btfsc STATUS,Z
goto datain
movf bytein,W
movwf byte1
bsf STATUS,RP0
bcf TRISB,RB0
bcf STATUS,RP0
bsf PORTB,RB0
call del10m
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
bcf PORTB,RB0
goto datain
goto fine

recby

; ricezione dati - restituisce il byte ricevuto in
; bytein; se c'e' stato
; un qualsiasi errore restituisce
; byteio=11111111B, altrimenti byteio=0

movlw 00H
movwf bytein
movlw 08H
movwf cbit

waitst

; attende che il clock vada a 0 e inserisce
; come bit numero 0 di byteio
; il bit presente su RA1 (Data)
; attende il bit di start (linea RA1)

movf PORTA,W
btfsc PORTA,RA0
goto waitst

; ad inizio ricezione porta alto il valore del
; piedino RB0

bsf STATUS,RP0
bcf TRISB,0
bcf STATUS,RP0
bsf PORTB,RB0
movwf serv
rrf serv,W
andlw 00000001B
xorlw STBIT
andlw 00000001B
call wcup

; pag.7

; se il bit di start è diverso da STBIT segnala
; errore

btfsc STATUS,Z
goto stbok
call estb
movlw 0FFH
movwf byteio
goto endrec

stbok

movlw 08H
movwf cbit
movlw 00H
movwf byteio

; riceve gli 8 bit

waitb

movf PORTA,W
btfsc PORTA,RA0
goto waitb
movwf serv
rrf serv,W
andlw 00000001B
btfsc STATUS,Z
goto carry0

carry1

bsf STATUS,C
goto storeb

carry0

bcf STATUS,C

storeb

rrf byteio,F
call wcup
decfsz cbit
goto waitb
movf byteio,W
movwf bytein

; riceve il bit di parità

waitpy

movf PORTA,W
btfsc PORTA,RA0
goto waitpy
movwf serv
call wcup

; calcola la parità del byte contenuto in byteio
; e la restituisce in parbit

call pargen
rrf serv,W
andlw 00000001B
xorwf parbit,W
btfss W,0
goto pbok
call eparb
movlw 0FFH
movwf byteio
goto endrec

; pag.8

pbok

nop

; attende il bit di stop

waitsb

movf PORTA,W
btfsc PORTA,RA0
goto waitsb
movwf serv
rrf serv,W
andlw 00000001B
xorlw ENDBIT
andlw 00000001B
call wcup

; se il bit di stop è diverso da ENDBIT segnala
; errore

btfsc STATUS,Z
goto ebok
call eendb
movlw 0FFH
movwf byteio
goto endrec

ebok

bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
bsf PORTB,RB0

; se byteio = FFH significa che c'è stato
; qualche errore; se si arriva qui
; vuol dire che il byte (che va in bytein
; comunque) è stato ricevuto correttamente

movlw 00H
movwf byteio

endrec

return

; non necessario

goto fine

; calcola la parità del byte contenuto in byteio
; e la restituisce in parbit

pargen

movlw 08H
movwf cbit
movlw 00H

pcycle

xorwf byteio,W
bcf STATUS,C
rrf byteio,F
decfsz cbit
goto pcycle

; pag.9

andlw 00000001B
movwf parbit
return

; pone sulla porta PORTA,DOUT il L.S.bit
; dell'accumulatore: se deve imporre 0,
; lo impone su PORTA,DOUT e configura tale
; piedino come uscita;
; se deve imporre 1, lo impone su tale porta
; (ma non serve) e configura tale
; piedino come ingresso

outbit

andlw 1H
btfsc STATUS,Z
goto outz
goto outuno

outz

bcf STATUS,RP0
bcf PORTA,DOUT
bsf STATUS,RP0
bcf TRISA,DOUT
bcf STATUS,RP0
goto endss

outuno

bsf STATUS,RP0
bsf TRISA,DOUT
bcf STATUS,RP0
bsf PORTA,DOUT

endss

return

; attende che il clock (PORTA,CIN) passi da
; basso ad alto

wcup

btfss PORTA,CIN
goto wcup
return

; attende che il clock (PORTA,CIN) passi da
; alto a basso

wcdown

btfsc PORTA,CIN
goto wcdown
return

; attende che la linea dati (PORTA,DIN) passi
; da basso ad alto

wdup

btfss PORTA,DIN
goto wdup
return

; attende che la linea dati (PORTA,DIN) passi
; da alto a basso

wddown

btfsc PORTA,DIN
goto wddown
return

; pag.10

; errore nel ricevere lo start bit (diversità dalla
; costante STBIT)
; alterna 1 e 0 su RB0 per 8 volte, con periodo
; di circa 0.2 sec, in totale circa 1 sec

estb

bsf STATUS,RP0
bcf TRISB,RB0
bcf STATUS,RP0
movlw 08H
movwf count

cycle2

movlw 00H
movwf delay1
movwf delay2
btfss count,0
goto ozero
goto ouno

ozero

bcf PORTB,RB0
goto cycle3

ouno

bsf PORTB,RB0

cycle3

decfsz delay1
goto cycle3
decfsz delay2
goto cycle3
decfsz count
goto cycle2
bcf PORTB,RB0
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
return

; errore nel ricevere lo start bit (diversità dalla
; costante STBIT)
; alterna 1 e 0 su RB0 per 16 volte, con periodo
; di circa 0.1 sec, in totale circa 1.5 sec

eparb

bsf STATUS,RP0
bcf TRISB,RB0
bcf STATUS,RP0
movlw 10H
movwf count

cycle4

movlw 00H
movwf delay1
movlw 80H
movwf delay2
btfss count,0
goto ozero1
goto ouno1

; pag.11

ozero1

bcf PORTB,RB0
goto cycle5

ouno1

bsf PORTB,RB0

cycle5

decfsz delay1
goto cycle5
decfsz delay2
goto cycle5
decfsz count
goto cycle5
bcf PORTB,RB0
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
return

; errore nel ricevere lo stop bit (diversità dalla
; costante ENDBIT)
; alterna 1 e 0 su RB0 per 32 volte, con periodo
; di circa 0.05 sec, in totale circa 1.5 sec

eendb

bsf STATUS,RP0
bcf TRISB,RB0
bcf STATUS,RP0
movlw 20H
movwf count

cycle6

movlw 00H
movwf delay1
movlw 40H
movwf delay2
btfss count,0
goto ozero2
goto ouno2

ozero2

bcf PORTB,RB0
goto cycle7

ouno2

bsf PORTB,RB0

cycle7

decfsz delay1
goto cycle7
decfsz delay2
goto cycle7
decfsz count
goto cycle6
bcf PORTB,RB0
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
return

; pag.12

; comando inviato - alterna 1 e 0 su RB0 per 2
; volte, con periodo di
; circa 0.5 sec, in totale circa 1 sec

cmdsnt

bsf STATUS,RP0
bcf TRISB,RB0
bcf STATUS,RP0
movlw 02H
movwf count

cycle8

movlw 00H
movwf delay1
movlw 00H
movwf delay2
movlw 02H
movwf delay3
btfsc count,0
goto ozero3
goto ouno3

ozero3

bcf PORTB,RB0
goto cycle9

ouno3

bsf PORTB,RB0

cycle9

decfsz delay1
goto cycle9
decfsz delay2
goto cycle9
decfsz delay3
goto cycle9
decfsz count
goto cycle8
bcf PORTB,RB0
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
return

; riceve in byteo e byteio il byte da inviare

sendby

bcf STATUS,RP0
bsf PORTB,0
bsf STATUS,RP0
bcf TRISB,0
bcf STATUS,RP0

; forza il clock a 0 e attende circa 200 us
; per far questo pone a 0 e configura come
; uscita il piedino PORTA,COUT

bcf STATUS,RP0
bcf PORTA,COUT

; pag.13

bsf STATUS,RP0
bcf TRISA,COUT
bcf STATUS,RP0

; mettere 42H in delay1 (circa 200 us)

movlw 42H
movwf delay1

cycle1

decfsz delay1
goto cycle1
movlw STBIT
call outbit

; rilascia il clock

bsf STATUS,RP0
bsf TRISA,COUT
bcf STATUS,RP0
bsf PORTA,COUT
call wcup
call wcdown
movlw 08H
movwf cbit

detbit

bcf STATUS,C
rrf byteo,F
btfss STATUS,C
goto bitz
goto bituno

bitz

movlw 00H
goto callob

bituno

movlw 01H
callob
call outbit
call wcup
call wcdown
decfsz cbit
goto detbit
call pargen
movf parbit,W

; PROVA INVERSIONE PARITA'

xorlw 00000001B
call outbit
call wcup
call wcdown

; pag.14

movlw ENDBIT
call outbit
call wddown
call wcdown
call wdup
call wcup
return

; routine di attesa di circa 1ms

del1ms

movlw 02H
movwf delay2
movlw 0A0H
movwf delay1

cyc21

decfsz delay1
goto cyc21
decfsz delay2
goto cyc21
return

; routine di attesa di circa 10ms

del10m

movlw 0DH
movwf delay2
movlw 00H
movwf delay1

cyc51

decfsz delay1
goto cyc51
decfsz delay2
goto cyc51
return

; routine di attesa di circa 100ms

del.1s

movlw 0A0H
movwf delay2
movlw 00H
movwf delay1

cyc41

decfsz delay1
goto cyc41
decfsz delay2
goto cyc41
return

; routine di attesa di circa 1s

del1s

; pag.15

movlw 05H
movwf delay3
movlw 00H
movwf delay2
movwf delay1

cyc11

decfsz delay1
goto cyc11
decfsz delay2
goto cyc11
decfsz delay3
goto cyc11
return

; indica che si sta per inviare un comando - mette 1 su RB0 con un

; impulso di circa 0.1 sec e poi 0 per altri 0.1 sec

cmdts

bsf STATUS,RP0

; pag.16

bcf TRISB,RB0
bcf STATUS,RP0
bsf PORTB,RB0
movlw 00H
movwf delay1
movlw 00H
movwf delay2

cyc31

decfsz delay1
goto cyc31
decfsz delay2
goto cyc31
bcf PORTB,RB0
bsf STATUS,RP0
bsf TRISB,RB0
bcf STATUS,RP0
call del.1s
return

fine

END

 

Buon lavoro!
 

Se volete contattarmi per chiarimenti o suggerimenti potete farlo al seguente indirizzo:

f_iacopetti@libero.it

 
Ultimo aggiornamento: 20 Dicembre 2001, 21.45 HyperCounter