elektra

Microcontrollers, pic


    Communication with a PS/2 mouse using a PIC 16F84

    Share

    thaers3d

    عدد المساهمات : 23
    تاريخ التسجيل : 2009-03-12

    Communication with a PS/2 mouse using a PIC 16F84

    Post  thaers3d on Thu Apr 02, 2009 12:31 pm

    Communication with a PS/2 mouse
    using a PIC 16F84
    Introduction
    As explained in the article Host - PS/2 mouse hardware communication on this site, to test the protocol needed to communicate with a PS/2 mouse I have interfaced it with a properly programmed PIC 16F84.

    Pay attention: PS/2 devices are different from serial mice, concerning both communication protocol and electrical levels; in PS/2 mice levels used for supply and data exchange are 0 and +5V, in serial mice we instead find the RS-232 levels, +12V and -12V. This article is concerning a PS/2 mouse. The PIC too must receive a +5V supply. In particular, common (or ground) pins of PIC and PS/2 mouse must be connected together; the same for +5V pins.

    To connect the mouse and the microcontroller together I suggest a flying PS/2 plug, to which you can connect the four needed wires. Such wires can then be carried to a prototype board and connected on it to the wires coming from the proper PIC's pins. To operate the PIC I have used the version previous to the one described in the article PIC 16F84 F.F. Evaluation Board on this site. For connections refer to the article about Host - PS/2 mouse hardware communication, to the PS/2 connector pin-out and to the first lines of the assembler list below. If in this way the mouse shouldn't show any sign of life, connect two pull-up resistors between data and clock and +5V supply (that, I repeat, must be the same for the microcontroller and the mouse). Proper values are around 3-10 KOhm.

    Take care to connections, to avoid unpleasant damages to devices! Instead of damaging a PIC or a mouse, if you are not really sure of acting correctly you can write me.

    Acknowledgement and disclaimers

    The material contained in these pages is the result of preliminary tests, project developement and verify carried on by the undersigned in first person.

    I guarantee the absolute originality of the material, though obviously not excluding that on the net it could be possible to find something analogous.

    Being this material at free disposal of whoever desires it, it is absolutely forbidden any form of use for commercial purposes. I don't assume, of course, any responsibilty for possible direct or indirect damages to things or persons deriving by the use of the informations contained in this article.

    PIC and Microchip are registered trademarks.

    The assembler program.

    Below you can find the list of the assembler program. As you can see watching it, it is substantially a set of routines I have written to send command to the mouse and to receive its answers. As it is a program I have used to carry on some tests, it is not optimized, neither concerning memory usage, nor concerning other aspects. It also contains some sections I used only to check the correspondence between the real protocol and the one described in some other papers on the net (I recognized an important difference; you can find the correct description of the communication protocol in the article Host - PS/2 mouse hardware communication on this site). To show which section of the program is currently executed and eventual error conditions, I used different kinds of blinking of a LED connected to the PIC (for whom who doesn't know it, a series resistor between the PIC's pin and the LED is needed; proper values are from 330 Ohm to 1 KOhm). Values used for waiting cycles refers to a clock frequency of 4 MHz, that is 1 million instructions per second. Data sent from the mouse about motion and switches status are not used. If you wish, to you now the task to use my routines making them suitable for your applications. Good luck!


    ;pag.1

    ; filename: mouseps2.asm
    ;
    ;
    ; receives data in a serial way from a
    ; PS/2 mouse;
    ; used lines are two: clock and data.

    ; As these lines must be open collector,
    ; RA2 (Clock) and RA3 (Data) are used as
    ; LOW output when it's to the host to drive
    ; them, while when they must be HIGH or
    ; when they have to be driven by the mouse
    ; they are set as inputs.

    ; RA0 (Clock) and RA1 (Data) are used
    ; as inputs to test Clock and Data lines.

    ; RB0 is used (as output) for giving
    ; informations about the communication
    ; status and about reception errors.

    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

      Current date/time is Thu Dec 13, 2018 7:46 pm