Modulo teclado PC con pic 16f87x

Hola amigos si por favor alguien me ayudara necesito comunicar un teclado de PC-PS2 a un pic 16f87x y visualizarlo en un display estoy programando en microcode y si pueden ayudarme con la documentación en español
 
Con este archivo podrás conectar el teclado. No lo he porbado pero la fuente es buena. Si te da problemas coméntalo y lo probaré.
Mantenos informaciónrmados como te ha ido

Saludos

TECPC.inc
Código:
;********************************************************************
;            "tecpc"
;Son un conjunto de subrutinas para comunicación con un teclado PC.
;Es necesaria la conexión del teclado y el entrenador a través de
;una placa de adaptación.
;Las señales a manejar son las siguientes:
;    CONECTOR TECLADO                                    CONECTOR MICRO
;         Reloj <---------INVERSOR-------------    RC1 (RELSAL)
;                    ----------------------------->   RC2 (RELEN)
;         Datos <------------------------------   RC7 (DATSAL)
;                    ----------------------------->   RC0 (DATEN)
;Subrutinas disponibles para el teclado PC.

;rtecpc: Recibe un dato de teclado que se guarda en Rdato.

;captec: Capta en serie el dato del teclado y actualiza el error.

;rsend: Envía el código de reeenvío al teclado.

;manda: Envía al teclado el byte contenido en Rdato.

;obtpar: Obtiene el bit de paridad del dato entrante en serie.

;cheqpar: Comprueba que la paridad de Rdato (parobt) y la del bit entrante coinciden en impar.

;mandack: Envía al teclado el byte de Rdato y espera hasta recibir un código ACK de reconocimiento.

;cheqbat: comprueba que el chequeo del teclado ha sido correcto y programa el bit de error
;en consecuencia.

;veltec: Programa la velocidad de escrutación de teclas y el retardo
;entre pulsaciones. El byte de programación debe estar contenido en Rdato.

;progled: Activación o desactivación de los leds del teclado.

;modtec: Programación del modo en que el teclado envía una tecla.
;El MSB del registro Rest es el bit de paridad leído en el
;dato recibido en serie.
;
;                            Registro Rest
;
;        Bit7   Bit6   Bit5   Bit4   Bit3   Bit2   Bit1   Bit0
;      parent   -      -    biterr   -      -      -    parobt
;********************************************************************

    CBLOCK        0x4A
    Rdato, T1rtec, T2rtec, Tinter 
    Cgentec, Rest, TRdato, Mtrisc
    Rtecla, Ccheqbat
    ENDC

;Rdato: 
#define     RELSAL    PORTC,1
#define    DATSAL    PORTC,7
#define    DATEN        PORTC,0
#define    RELEN        PORTC,2
#define    biterr    Rest,4
#define    parobt    Rest,0
#define    parent    Rest,7


;********************************************************************
;                        "rtecpc"
;Esta subrutina recibe un byte desde el teclado del PC, que estará
;disponible en el registro Rdato. Si en la recepción ocurriese algún
;error el registro Rest tendrá a 1 su quinto bit (biterr).
;********************************************************************

rtecpc:    bsf        STATUS,RP0        ;Selección de banco 1.
            movf        TRISC,W            ;Guarda las direcciones de las líneas
            bcf        STATUS,RP0        ;del puerto C en el registro Mtrisc,
            movwf        Mtrisc            ;del banco 0.
            andlw        b'01111101'        ;Programa RC7 y RC1 como salidas, RC2
            iorlw        b'00000101'        ;y RC0 como entradas. El resto no varía.
            bsf        STATUS,RP0        ;Selección de banco 1.
            movwf        TRISC                ;Programación del registro TRISC.
            bcf        STATUS,RP0        ;Selección del banco 0.
            bcf        RELSAL            ;Libera el reloj para el teclado.
            movlw        0x40                ;Carga valores para intentos de lectura.
            movwf        T1rtec            ;    "

rtecpc1:    movlw        0xFF                ;    "
            movwf        T2rtec            ;    "

rtecpc2:    btfsc        RELEN                ;¿Reloj de entrada=0?
            goto        rtecpc3            ;No: sigue intentando leer 0.
            btfsc        DATEN                ;Sí: ¿Teclado envía bit de START?
            goto        rtecpc3            ;No: sigue intentando bit de START.
            call        captec            ;Sí: captura byte.
            goto        rtecpc4

rtecpc3:    decfsz    T2rtec,F            ;Bucle de retardo.
            goto        rtecpc2            ;    "
            decfsz    T1rtec,F            ;    "
            goto        rtecpc1            ;    "
            bsf        biterr            ;Activa bit de error.

rtecpc4:    bsf        RELSAL            ;Cancela reloj al teclado.
            movf        Mtrisc,W            ;Recupera direcciones de PORTC.
            bsf        STATUS,RP0        ;    "
            movwf        TRISC                ;    "
            bcf        STATUS,RP0        ;    "
            return
    

;********************************************************************
;                        "captec"
;Subrutina encargada de leer bit a bit los nueve que envía el teclado,
;incluída la paridad. Si existe algún error en la comunicación o en
;paridad, la subrutina activa el bit de error. El dato estará presente
;en el registro Rdato.     
;********************************************************************

captec:    bcf        biterr            ;Borra marca de error.
            bcf        RELSAL            ;Pone a "1" el reloj al teclado PC.

rel0_1:    btfsc        RELEN                ;Espera a que el teclado ponga a 0
            goto        rel0_1            ;su señal de reloj.
            btfsc        DATEN                ;Espera a recibir el bit de START
            goto        rel0_1            ;    "
            movf        INTCON,W            ;Salva registro de interrupciones.
            movwf        Tinter            ;    "
            bcf        INTCON,GIE        ;Inhibe interrupciones.
            movlw        8                    ;Carga el número de bits a recibir,
            movwf        Cgentec            ;sin contar el de paridad.

rel0_2:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        rel0_2            ;reloj emitido por el teclado.
    
rel1_1:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        rel1_1            ;reloj emitido por el teclado.
            btfss        DATEN                ;Capta bit entrante y lo va cargando
            goto        captec2            ;en Rdato mediante rotaciones.
            bsf        STATUS,C            ;Carga 1 en Rdato.
    
captec1:    rrf        Rdato,F            ;    "
            decfsz    Cgentec,F        ;Decrementa contador de bits.
            goto        rel0_2            ;Si no se ha terminado salta a rel0_2.
            goto        rel0_3            ;Si ha finalizado sigue en rel0_3.

captec2:    bcf        STATUS,C            ;Carga 0 en Rdato.
            goto        captec1

rel0_3:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        rel0_3            ;reloj emitido por el teclado.
    
rel1_3:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        rel1_3            ;reloj emitido por el teclado.
            btfsc        DATEN                ;Capta bit entrante de paridad.
            goto        captec3
            bcf        parent            ;Programa bit de paridad entrante.
            goto        captec4

captec3:    bsf        parent            ;Programa bit de paridad entrante.

captec4:    call        obtpar            ;Se obtiene la paridad del byte de
                                            ;Rdato y se compara con la recibida.
            call        cheqpar            ;Programa bit de error.

rel0_4:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        rel0_4            ;reloj emitido por el teclado.

rel1_4:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        rel1_4            ;reloj emitido por el teclado.
            btfss        DATEN                ;¿Bit de STOP=1?
            bsf        biterr            ;No: error.

rel0_5:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        rel0_5            ;reloj emitido por el teclado.
            movf        Tinter,W            ;Recupera estado de interrupciones.
            movwf        INTCON            ;    "
            bsf        RELSAL            ;Anula reloj al teclado PC.
            btfss        biterr            ;¿Existe condición de error?
            return                        ;No: retorno.
            call        rsend                ;Sí: rutina de reenvío de byte.
            btfss        biterr            ;¿Existe condición de error?
            goto        captec            ;No: repite captación de byte.
            return                        ;Sí: retorna con marca de error.

;********************************************************************
;                        "rsend"
;Esta subrutina envía al teclado el código que aquél interpreta como
;petición de reenvío del último byte. El código concreto es "FEh".
;********************************************************************

rsend:    movlw        0xFE                ;Escribe código de reenvío.
            call        manda                ;Envía al teclado un byte.
            return

;********************************************************************
;                        "manda"
;Subrutina que envía al teclado el byte contenido en el registro Rdato.
;Se activa el bit de error si éste se produjese. No altera Rdato.
;********************************************************************

manda:    bsf        STATUS,RP0        ;Selección de banco 1.
            movf        TRISC,W            ;Guarda las direcciones de las líneas
            bcf        STATUS,RP0        ;del puerto C en el registro Mtrisc,
            movwf        Mtrisc            ;del banco 0.
            andlw        b'01111101'        ;Programa RC1 y RC7 como salidas, RC0
            iorlw        b'00000101'        ;y RC2 como entradas. El resto no varía.
            bsf        STATUS,RP0        ;Selección de banco 1.
            movwf        TRISC                ;Programación del registro TRISC.
            bcf        STATUS,RP0        ;Selección del banco 0.
            bcf        DATSAL            ;Pone bit de START.
            bcf        RELSAL            ;Libera señal de reloj.
            movlw        0xFF                ;Carga valores para intentos de
            movwf        T1rtec            ;comunicación.

mrecar:    movlw        0xFF                ;    "
            movwf        T2rtec            ;    "

mrel0_1:    btfss        RELEN                ;¿Reloj de teclado igual a 1?
            goto        conrut            ;No: continúa rutina.
            decfsz    T2rtec,F            ;Sí: Bucle de espera hasta ver el
            goto        mrel0_1            ;nivel bajo del reloj procedente del
            decfsz    T1rtec,F            ;teclado PC.
            goto        mrecar            ;salta a recargar registro.    
            bsf        biterr            ;Se activa la señal de error.

salida:    bsf        RELSAL            ;Bloquea la línea de reloj.
            movf        Mtrisc,W            ;Recupera direcciones de PORTC.
            bsf        STATUS,RP0        ;    "
            movwf        TRISC                ;    "
            bcf        STATUS,RP0        ;    "
            return

conrut:    movf        INTCON,W            ;Salva registro de interrupciones.
            movwf        Tinter            ;    "
            bcf        INTCON,GIE        ;Inhibe interrupciones.
            movlw        8                    ;Carga el número de bits a enviar,
            movwf        Cgentec            ;sin contar el de paridad.

manda1:    rrf        Rdato,F            ;Rotamos dato a enviar para poner
            btfsc        STATUS,C            ;en C el bit a enviar.
            goto        manda2
            bcf        DATSAL            ;Envía un 0 al teclado.
            goto        mrel0_2

manda2:    bsf        DATSAL            ;Envía un 1 al teclado.    

mrel0_2:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        mrel0_2            ;reloj.
    
mrel1_1:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        mrel1_1            ;reloj.
            decfsz    Cgentec,F        ;Decrementa contador de bits.
            goto        manda1            ;Repite envío de bit.
            rrf        Rdato,F            ;Rota dato para dejarlo como estaba
            call        obtpar            ;Obtiene la paridad del byte.
            btfss        parobt            ;¿Paridad impar?
            goto        manda3            ;No: sigue en manda3.
            bcf        DATSAL            ;Sí: saca 0 para paridad impar.
            goto        mrel0_3

manda3:    bsf        DATSAL            ;Manda 1 para paridad impar.
    
mrel0_3:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        mrel0_3            ;reloj.

mrel1_2:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        mrel1_2            ;reloj.
            bsf        DATSAL            ;Deja a nivel alto la línea de datos
                                            ;para quedar en ESPERA.
mrel0_4:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        mrel0_4            ;reloj.

mrel1_3:    btfsc        RELEN                ;Espera a que pase el nivel 1 del
            goto        mrel1_3            ;reloj.
            btfss        DATEN                ;Chequea el dato de entrada.
            goto        manda4            ;Error si datos está a 0.
            bsf        biterr            ;Borra ERROR si datos está a 1.

mrel0_5:    btfss        RELEN                ;Espera a que pase el nivel 0 del
            goto        mrel0_5            ;reloj.
    

mdat1:    btfss        DATEN                ;Espera a encontrar el nivel 1 en
            goto        mdat1                ;línea de datos.
            bsf        RELSAL            ;Bloquea reloj.
            movf        Tinter,W            ;Recupera estado de interrupciones.
            movwf        INTCON            ;    "
            goto        salida

manda4:    bcf        biterr            ;Si DATEN=1 programa ERROR.
            goto        mrel0_5


;********************************************************************
;                        "cheqpar"
;Subrutina para chequear paridad y programar en consecuencia el bit
;de error.
;********************************************************************        

cheqpar:    btfss        parobt            ;¿Paridad obtenida es impar?
            goto        cheqpar2            ;No: continúa en proger1.
            btfsc        parent            ;Sí: ¿bit de paridad entrante es 0?
            goto        cheqpar3            ;No: va a programar error.
    
cheqpar1:bcf        biterr            ;Sí: borra bit de error y retorna.
            return

cheqpar2:btfsc        parent            ;¿Paridad entrante es par?
            goto        cheqpar1            ;No: va a borrar el error.

cheqpar3:bsf        biterr            ;Programa bit de error.
            return

;********************************************************************
;                        "mandack"
;Subrutina que envía al teclado el byte contenido en el registro
;Rdato y espera recibir un ACK (0xFA). Altera el registro Rdato.
;Se activa el bit de error si éste se produjese.
;********************************************************************

mandack:    call        manda                ;Envía el dato al teclado.
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna con el error.
            call        rtecpc            ;Subrutina para recibir un byte.
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna con el error.
            movf        Rdato,W            ;¿Dato recibibido es ACK?
            xorlw        0xFA                ;    "
            btfsc        STATUS,Z            ;    "
            return                        ;Sí: retorno.
            movf        Rdato,W            ;No: ¿es un RESEND?
            xorlw        0xFE                ;    "
            btfsc        STATUS,Z            ;    "
            goto        mandack            ;Sí: repite el envío.
            bsf        biterr            ;No: activa error.
            return

;********************************************************************
;                        "cheqbat"
;Subrutina que mira si el chequeo del teclado ha sido correcto. Si no
;lo fuese se activaría el bit de error.
;********************************************************************

cheqbat:    movlw        0xFF                ;Carga número de intentos.
            movwf        Ccheqbat            ;    "

cheqbat1:call        rtecpc            ;Recibe byte desde el teclado.
            btfss        biterr            ;¿Hay error?
            goto        cheqbat3            ;No: sigue en cheqbat3.
            decfsz    Ccheqbat,F        ;Sí: decrementa contador.
            goto        cheqbat1            ;Salto a repetir consulta.

cheqbat2:bsf        biterr            ;Si hay error después de los intentos
            return                        ;se retorna con el error.

cheqbat3:movf        Rdato,W            ;¿Byte es AAh?
            xorlw        0xAA                ;    "
            btfss        STATUS,Z            ;    "
            goto        cheqbat2            ;No: activa error.
            return

;********************************************************************
;                        "veltec"
;Subrutina que programa la velocidad de escrutación de las teclas y el
;retardo entre pulsaciones. El byte de programación debe estar en el
;registro Rdato.
;********************************************************************

veltec:    movf        Rdato,W            ;Salva Rdato en registro temporal.
            movwf        TRdato            ;    "
            movlw        0xF3                ;Envía el código previo a la programa-
            movwf        Rdato                ;ción de velocidad y retardo.
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera byte de programación de
            movwf        Rdato                ;velocidad y retardo.
            btfss        biterr            ;¿Ha habido error en el envío anterior?
            call        mandack            ;No: envía el byte de programación.
            return                        ;Retorna.

;********************************************************************
;                        "progled"
;Subrutina que activa o desactiva los leds del teclado de acuerdo al
;1 o 0, respectivamente, que programemos en los bits de Rdato, de la
;siguiente, manera:
;Rdato0: Scroll Lock
;Rdato1: Num Lock
;Rdato2: Caps Lock
;Rdato3 - Rdato7 = 0
;biterr: 1 si hay error.
;********************************************************************

progled:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xED                ;Envía código para activación o desac-
            movwf        Rdato                ;tivación de leds.
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera valor de Rdato.
            movwf        Rdato                ;    "
            btfss        biterr            ;¿Hay error en envío?
            call        mandack            ;No: manda código de leds.
            return                        ;Retorna.

;********************************************************************
;                        "modtec"
;Subrutina que programa el modo en que el teclado va a enviar una
;tecla.
;Rdato = 0xFB -> Typematic
;Rdato = 0xFC -> Make/Break
;Rdato = 0xFD -> Make
;Rtecla = Código de tecla.
;biterr: 1 si hay error.
;********************************************************************

modtec:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            call        mandack            ;Envía el código de modo.
            btfss        biterr            ;¿Error en el envío?
            goto        modtec2            ;No: sigue en modtec2.

modtec1:    movf        TRdato,W            ;Sí: recupera valor de Rdato.
            movwf        Rdato                ;    "
            return

modtec2:    movf        Rtecla,W            ;Envía el código de la tecla
            call        mandack            ;correspondiente a ese modo.
            goto        modtec1

;********************************************************************
;                        "teciden"
;Subrutina que lee la identificación del teclado. Si no fuese correcta
;se activaría el bit de error.
;********************************************************************

teciden:    movlw        0xF2                ;Envía el código de identificación.
            movwf        Rdato                ;    "
            call        mandack            ;    "
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna con el error.
            call        rtecpc            ;No: recibe byte desde teclado.
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna con el error.
            movf        Rdato,W            ;No: ¿dato es igual a 0xAB?
            xorlw        0xAB                ;    "
            btfsc        STATUS,Z            ;    "
            goto        teciden1            ;Sí: sigue en teciden1.
            bsf        biterr            ;No: activa error.
            return                        ;Retorna.

teciden1:call        rtecpc            ;Recibe byte de identificación.
            btfsc        biterr            ;¿Error en la recepción?
            return                        ;Sí: retorno con error.
            movf        Rdato,W            ;No: ¿byte es igual a 83h?
            xorlw        0x83                ;    "
            btfss        STATUS,Z            ;    "
            bsf        biterr            ;No: activa error y retorna.
            return

;********************************************************************
;                        "acttec"
;Subrutina para activar el teclado. Si se produce error se activa el
;bit de error.
;********************************************************************

acttec:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xF4                ;Envía código para activación del
            movwf        Rdato                ;teclado.
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera valor de Rdato.
            movwf        Rdato                ;    "
            return                        ;Retorna.

;********************************************************************
;                        "destec"
;Subrutina para desactivar el teclado. Si se produce error se activa
;el bit de error.
;********************************************************************

destec:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xF5                ;Envía código para desactivación del
            movwf        Rdato                ;teclado.
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera valor de Rdato.
            movwf        Rdato                ;    "
            return                        ;Retorna.

;********************************************************************
;                        "echotec"
;Subrutina que manda un ECHO al teclado y espera la recepción del ECO
;de éste. Si se produce error se activa biterr.
;********************************************************************

echotec:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xEE                ;Envía código de ECHO.
            movwf        Rdato                ;    "
            call        manda                ;    "
            btfss        biterr            ;¿Hay error?
            goto        echotec2            ;No: sigue en echotec2.

echotec1:movf        TRdato,W            ;Sí: recupera valor de Rdato.
            movwf        Rdato                ;    "
            return                        ;Retorna.
    
echotec2:call        rtecpc            ;Recibe del teclado el byte de ECO.
            btfsc        biterr            ;¿Hay error?
            goto        echotec1            ;Sí: recupera Rdato y retorna.
            movf        Rdato,W            ;No: compara byte recibido con el
            xorlw        0xEE                ;valor del byte de ECO.
            btfss        STATUS,Z            ;¿Es byte de ECO?
            bsf        biterr            ;No: activa error.
            goto        echotec1            ;Sí: recupera Rdato y retorna.


;********************************************************************
;                        "initec"
;Subrutina que inicializa al teclado en las condiciones por defecto.
;Si se produce error se activa biterr.
;********************************************************************

initec:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xF6                ;Envía código de ECHO.
            movwf        Rdato                ;    "
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera valor de Rdato.
            movwf        Rdato                ;    "
            return

;********************************************************************
;                        "modcod"
;Subrutina que determina el modo en que va a enviar el teclado el
;código de exploración.
;Rdato = 01    Modo 1
;Rdato = 02    Modo 2
;Rdato = 03    Modo 3
;Rdato = 00    Detecta el modo actual, que queda depositado en Rdato.
;biterr = 1 si hay error.
;********************************************************************

modcod:    movf        Rdato,W            ;Salva Rdato en TRdato.
            movwf        TRdato            ;    "
            movlw        0xF0                ;Envía código de ECHO.
            movwf        Rdato                ;    "
            call        mandack            ;    "
            movf        TRdato,W            ;Recupera valor de Rdato.
            movwf        Rdato                ;    "
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna.
            call        mandack            ;No: envía el contenido de Rdato.
            btfsc        biterr            ;¿Existe error?
            return                        ;Sí: retorna.
            movf        TRdato,W            ;¿El contenido de Rdato inicial es
            xorlw        00                    ;igual a 00h?
            btfss        STATUS,Z            ;    "
            return                        ;No: retorna.
            call        rtecpc            ;Sí: recibe el byte de teclado que
            return                        ;informaciónrmará del Modo actual.

;********************************************************************
;                        "restec"
;Subrutina que envía al teclado el código de RESET.
;Si se produce error se activa biterr.
;********************************************************************

restec:    movlw        0xFF                ;Envía código de RESET.
            movwf        Rdato                ;    "
            call        mandack            ;    "
            btfss        biterr            ;¿Hay error?
            call        cheqbat            ;No: chequea la correcta inicialización.
            return                        ;Sí: retorna.
 
Última edición por un moderador:
Buenas Amigo "El Nombre" yo nesecito usar la misma aplicacion que el otro usuario pero en el pic16f877 me comentaron que no hacia falta ninguna placa de adaptacion que se podia pegar directamente al micro ya que el teclado trabaja con niveles TTL, mi pregunta es referida a tu codigo... no tienes la version en asm, te pregunto esto por dos razones... al principio dices que el archivo es .inc y la otra es porque estoy viendo el codigo de programacion y hay varios comandos que desconosco.... agradeceria toda la ayuda de tu parte o de cualquier usuario de este gran foro que tenga conociemientos sobre este tema Muchas Gracias
 
Hola yo me encontre un archivo porque quiero lo mismo y me tope con este que te lo dejo en archivos adjuntos, espero que te sirva, el codigo esta en asembler.
 

Adjuntos

  • teclado con PIC.pdf
    643.3 KB · Visitas: 470
hola compañeros soy nuevo en esto de programacion y quisiera saber para que sirve esto?
lo entendido en que el teclado lo conectan al Pic y esto les genera una salida de un numero o algo asi?
 
Atrás
Arriba