Download - Subrutinas pic
Subrutinas para Pic
2º DPEE Grado Superior Diciembre 2005
aschex
;********************************************************************; "aschex";Esta subrutina convierte el código ASCII existente en W en código;hexadecimal. El resultado de la conversión se obtiene en W.;El tiempo total de subrutina es de 10 us, incluido el call.;********************************************************************
CBLOCK 0x72TASCHENDC
aschex movwf TASCH ;Guarda el número original.sublw 0x39 ;¿Es cifra? (resultado positivo)btfss STATUS,C ; "goto Ajlet ;No: salta a ajuste de letra.movlw 0x30 ;Sí: carga valor para resta ysubwf TASCH,W ;obtención del hexadecimal.return
Ajlet: movlw .55 ;Carga el decimal 55 para ajustesubwf TASCH,W ;de cifra.return
Página 1
ascii
;********************************************************************; "ASCII";Esta subrutina convierte en código ASCII el byte existente en W.;La conversión del cuarteto mayor se deposita en el registro RASCH;y la del menor en RASCL.;El tiempo máximo de subrutina es de 32 us, incluido el call.;********************************************************************
CBLOCK 0x7ATASC1, TASC2, RASCH, RASCLENDC
ASCII: movwf TASC1 ;Guarda el número original.call AJASC ;Ajusta cuarteto menor. Valor en W.movwf RASCL ;Guarda ajuste de cuarteto menor.swapf TASC1,W ;Permuta cuartetos para ajuste del mayor.call AJASC ;Ajusta cuarteto mayor.movwf RASCH ;Guarda conversión de cuarteto mayor.return
AJASC: andlw B'00001111' ;Borra cuarteto mayor.movwf TASC2 ;Salva valor.sublw 9 ;Compara el número con 9.btfss STATUS,C ;¿Número > 9? ¿Cifra o letra?goto AJLET ;Si número > 9 (letra) salta a ajustarla.movf TASC2,W ;Si W < ó = 9 (cifra) recupera valor.addlw 0x30 ;Suma 30 para ajustar la cifra.retur
AJLET: movf TASC2,W ;Recupera valor.addlw 0x37 ;Suma para ajuste en ASCII de letra.return
Página 1
bbcd16
;********************************************************************; "bbcd16";Subrutina para convertir en BCD el número binario de 16 bits contenido;en los registros HBYTE y LBYTE (mayor y menor byte respectivamente).;El resultado queda en RBCDH, RBCDM y RBCDL, nombrados de mayor a menor;dígito, respectivamente.;El tiempo total de subrutina es de 887 us, incluido el call.;********************************************************************
CBLOCK 0x73HBYTE, LBYTE, RBCDL, RBCDM, RBCDH, Conbit, TBCD16ENDC
bbcd16: bcf STATUS,C ;Borra el acarreo.movlw .16 ;Carga contador de bits.movwf Conbit ; "clrf RBCDL ;Borra registros de resultado.clrf RBCDM ; "clrf RBCDH ; "
L16: rlf LBYTE,F ;Rota a izquierda los dos bytesrlf HBYTE,F ;del número.rlf RBCDL,F ;Rota a izquierda los tres registrosrlf RBCDM,F ;del resultado.rlf RBCDH,F ; "decfsz Conbit,F ;Decrementa contador de bits.goto Ajdec ;Si no se ha finalizado, salto a Ajdec.retlw 0 ;Si se ha finalizado, retorno con 0 en W.
Ajdec: movlw RBCDL ;Se carga dígito menor de resultadomovwf FSR ;para ser utilizado como dirección.call Ajbcd ;Ajuste en BCD.movlw RBCDM ;Se carga dígito medio de resultadomovwf FSR ;para ser utilizado como dirección.call Ajbcd ;Ajuste en BCD.movlw RBCDH ;Se carga dígito mayor de resultadomovwf FSR ;para ser utilizado como dirección.call Ajbcd ;Ajuste en BCD.goto L16 ;Repite 16 veces lo anterior.
Ajbcd: movlw 3 ;Carga 3 en W.addwf INDF,W ;Suma 3 al contenido direccionado por FSR.movwf TBCD16 ;Descarga en TBCD16 el resultado anterior.btfsc TBCD16,3 ;Chequea bit 3 del resultado anterior.movwf INDF ;Si bit 3 = 1, carga W en la dirección de FSR.movlw 0x30 ;Si bit 3 = 0, W se carga con 30h.addwf INDF,W ;Suma W con lo direccionado por FSR. movwf TBCD16 ;Carga W en TBCD16.btfsc TBCD16,7 ;Chequea bit 7 de TBCD16.movwf INDF ;Si bit 7 = 1, carga W en la dirección de FSR.retlw 0 ;Si bit 7 = 0 se retorna con 0 en W.
Página 1
contlcd
;********************************************************************************;CONJUNTO DE SUBRUTINAS QUE PUEDEN INCLUIRSE EN OTROS PROGRAMAS CON LA ORDEN; include "contlcd.inc";********************************************************************************
;Estas rutinas permitirán realizar el control de la pantalla visualizadora (LCD).
#define ACTIVEN bsf PORTA,2 ;Activa señal E.#define BORRAEN bcf PORTA,2 ;Desactiva señal E.#define LEELCD bsf PORTA,1 ;Lee el módulo.#define ESCRLCD bcf PORTA,1 ;Escribe en el módulo.#define ORDEN bcf PORTA,0 ;Prepara al módulo para recibir una orden.#define DATO bsf PORTA,0 ;Prepara al módulo para recibir un dato
CBLOCK 0x7ETLCD1, TLCD2ENDC
;********************************************************************; "PROGLCD";Realiza la programación de puerto A y puerto B de la manera que ;necesita el módulo LCD: PORTB como salida y las tres líneas de menos;peso del PORTA como salidas digitales.;********************************************************************
PROGLCD: bsf STATUS,RP0 ;Selecciona banco 1.movlw 06 ;Configura las patillas del puerto Amovwf ADCON1 ;como señales digitales.movf TRISA,W ;Lee la programación de TRISA paraandlw b'11111000' ;dejar como salidas las tres líneasmovwf TRISA ;de menor peso y no tocar las demás.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0.ORDEN ;RS=0.BORRAEN ;E=0.return
;********************************************************************; "INILCD";Realiza la inicialización del LCD con interface de 8 bits, 2 líneas ;de pantalla y caracteres de 5 x 7. La subrutina provocará un retardo;de 45,2 ms y un borrado de pantalla.;********************************************************************
INILCD call R20MS ;Retardo mayor de 30 ms necesario paracall R20MS ;que estabilice la tensión de
alimentación.call PROGLCD ;Programación de las líneas de puertos.movlw b'00111100' ;Programación de interface de 8 bits ycall ENVC ;pantalla de 2 líneas.call R100MI ;Retardo mayor de 39 microsegundos.movlw b'00001110' ;Programación de pantalla activa,
cursorcall ENVC ;visible y sin intermitencia.call R100MI ;Retardo aconsejado mayor de 39
microseg.movlw 01 ;Programación de borrado de pantalla.call ENVC ; "
call R5MS ;Retardo aconsejado mayor de 1,53 ms.movlw 06 ;Programación de cursor incremental.call ENVC ; "return
;********************************************************************; "ESPVI";Rutina de espera para que el visualizador quede libre.;********************************************************************
ESPVI LEELCD ;Pone al módulo LCD en modo lectura.bsf STATUS,RP0 ;Selecciona banco 1.movlw 0xFF ;Programa PORTB como entrada.movwf TRISB ; "bcf STATUS,RP0 ;Selecciona banco 0.ACTIVEN ;E=1: activa Enable.nop
ESPVI1: btfsc PORTB,7 ;Chequea bit "BUSY".goto ESPVI1 ;Si está OCUPADO repite el chequeo.BORRAEN ;E=0: desactiva Enable.bsf STATUS,RP0 ;Selecciona el banco 1.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0ESCRLCD ;Deja al módulo en escritura.return
;********************************************************************; "DurEN";Duración de ENABLE. En algunos LCD esta señal debe estar a "0" unos;40uS antes de volver a ponerse a "1".;********************************************************************
DurEN: ACTIVEN ;Activa ENABLE
Página 1
contlcdnop ;Retardo de seguridad.BORRAEN ;Desactiva ENABLEmovlw .14 ;Bucle de retardo 40 us.movwf TLCD1 ;Salva valor en temporal.
DurEN1: decfsz TLCD1,F ;Pierde unos 40 uS necesarios para losgoto DurEN1 ;módulos LCD de winteck.return
;********************************************************************; "ENVD";Rutina para enviar al visualizador el dato contenido en W.;********************************************************************
ENVD ORDEN ;RS=0.movwf PORTB ;Saca dato por el puerto B.call ESPVI ;Espera hasta visualizador
LIBRE.DATO ;RS=1: visualizador en modo
dato.goto DurEN ;Aplica pulso de ENABLE.
;********************************************************************; "ENVC";Rutina para enviar al visualizador una orden.;********************************************************************
ENVC ORDEN ;RS=0.movwf PORTB ;Saca en puerto B el valor de
W.call ESPVI ;Espera hasta visualizador
LIBRE.goto DurEN ;Finaliza.
;********************************************************************; "LEED";Rutina para leer el dato ubicado en la posición del cursor del LCD.;El dato leído estará disponible en W.;********************************************************************
LEED bsf STATUS,RP0 ;Selecciona banco 1.movlw 0xFF ;Programa PORTB como entrada.movwf TRISB ; "bcf STATUS,RP0 ;Selecciona banco 0.LEELCD ;R/-W= 1: visualizador en modo lectura.DATO ;RS=1: visualizador en modo dato.ACTIVEN ;E=1: activa Enable.movf PORTB,W ;Lee el dato en posición de cursor.BORRAEN ;E=0: desactiva Enable.movwf TLCD2 ;Salva dato en registro temporal.call ESPVI ;Espera a visualizador libre.bsf STATUS,RP0 ;Selecciona el banco 1.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0.movlw .14 ;Bucle de retardo 40 us.movwf TLCD1 ;Salva valor en temporal.
LEED1: decfsz TLCD1,F ;Pierde unos 40 uS necesarios para losgoto LEED1 ;módulos LCD de winteck.movf TLCD2,W ;Recupera valor leído.return
;********************************************************************;La señal RS está conectada a RA0 (PORTA0).;La señal R/-W está conectada a RA1 (PORTA1).;La señal E está conectada a RA2 (PORTA2).;RS = 0 para orden de control de pantalla.;RS = 1 para dato de o hacia pantalla.;R/-W = 0 para realizar una escritura en pantalla (envío).;R/-W = 1 para leer de pantalla (obtener una información).;E = 0 para inhibición de la pantalla.;E = 1 para habilitar los circuitos del visualizador.;********************************************************************
;********************************************************************;SUBRUTINAS PARA EMPLEAR LA RAM DE REGISTROS COMO PANTALLA LCD;Se emplean las direcciones 30h a 3Fh y 40h a 4Fh para visualizar;las dos líneas de pantalla.;El cursor siempre trabaja en modo incremental, tanto al escribir como;al leer datos.;Antes de escribir o leer, como es lógico, hay que situar el cursor.;********************************************************************INILCDM movlw 30
movwf FSRmovlw .16movwf TLCD1
INILCDM1: clrf INDFincf FSR,Fdecfsz TLCD1,Fgoto INILCDM1return
Página 2
contlcdENVDM movwf INDF
incf FSR,Freturn
ENVCM movwf TLCD1movlw 50subwf TLCD1,Wmovwf FSRreturn
LEEDM movf INDF,Wincf FSR,Freturn
Página 3
contlcd
;********************************************************************************;CONJUNTO DE SUBRUTINAS QUE PUEDEN INCLUIRSE EN OTROS PROGRAMAS CON LA ORDEN; include "contlcd.inc";********************************************************************************
;Estas rutinas permitirán realizar el control de la pantalla visualizadora (LCD).
#define ACTIVEN bsf PORTA,2 ;Activa señal E.#define BORRAEN bcf PORTA,2 ;Desactiva señal E.#define LEELCD bsf PORTA,1 ;Lee el módulo.#define ESCRLCD bcf PORTA,1 ;Escribe en el módulo.#define ORDEN bcf PORTA,0 ;Prepara al módulo para recibir una orden.#define DATO bsf PORTA,0 ;Prepara al módulo para recibir un dato
CBLOCK 0x7ETLCD1, TLCD2ENDC
;********************************************************************; "PROGLCD";Realiza la programación de puerto A y puerto B de la manera que ;necesita el módulo LCD: PORTB como salida y las tres líneas de menos;peso del PORTA como salidas digitales.;********************************************************************
PROGLCD: bsf STATUS,RP0 ;Selecciona banco 1.movlw 06 ;Configura las patillas del puerto Amovwf ADCON1 ;como señales digitales.movf TRISA,W ;Lee la programación de TRISA paraandlw b'11111000' ;dejar como salidas las tres líneasmovwf TRISA ;de menor peso y no tocar las demás.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0.ORDEN ;RS=0.BORRAEN ;E=0.return
;********************************************************************; "INILCD";Realiza la inicialización del LCD con interface de 8 bits, 2 líneas ;de pantalla y caracteres de 5 x 7. La subrutina provocará un retardo;de 15 ms y un borrado de pantalla.;********************************************************************
INILCD call PROGLCD ;Programación de las líneas de puertos.movlw b'00111100' ;Programación de interface de 8 bits ycall ENVC ;pantalla de 2 líneas.movlw b'00001110' ;Programación de pantalla activa,
cursorcall ENVC ;visible y sin intermitencia.movlw 01 ;Programación de borrado de pantalla.call ENVC ; "
movlw 06 ;Programación de cursor incremental.call ENVC ; "return
;********************************************************************; "ENVD";Rutina para enviar al visualizador el dato contenido en W.;********************************************************************
ENVD DATO ;RS=1: visualizador en modo dato.
ESCRLCD ;R/-W = 0movwf PORTB ;Saca dato por el puerto B.ACTIVENBORRAENcall R1MSreturn
;********************************************************************; "ENVC";Rutina para enviar al visualizador una orden.;********************************************************************
ENVC ORDEN ;RS=0.ESCRLCD ;R/-W = 0movwf PORTB ;Saca en puerto B el valor de
W.ACTIVENBORRAENcall R1MSreturn
;********************************************************************; "LEED";Rutina para leer el dato ubicado en la posición del cursor del LCD.;El dato leído estará disponible en W.;********************************************************************
LEED bsf STATUS,RP0 ;Selecciona banco 1.movlw 0xFF ;Programa PORTB como entrada.
Página 1
contlcdmovwf TRISB ; "bcf STATUS,RP0 ;Selecciona banco 0.LEELCD ;R/-W= 1: visualizador en modo lectura.DATO ;RS=1: visualizador en modo dato.ACTIVEN ;E=1: activa Enable.movf PORTB,W ;Lee el dato en posición de cursor.BORRAEN ;E=0: desactiva Enable.movwf TLCD2 ;Salva dato en registro temporal.bsf STATUS,RP0 ;Selecciona el banco 1.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0.movf TLCD2,W ;Recupera valor leído.call R1MSreturn
;*****************************************************************; "LEES";Rutina para leer la palabra de Estado del LCD.;El dato leído estará disponible en W.;********************************************************************
LEES bsf STATUS,RP0 ;Selecciona banco 1.movlw 0xFF ;Programa PORTB como entrada.movwf TRISB ; "bcf STATUS,RP0 ;Selecciona banco 0.LEELCD ;R/-W= 1: visualizador en modo lectura.ORDEN ;RS=1: visualizador en modo dato.ACTIVEN ;E=1: activa Enable.movf PORTB,W ;Lee el dato en posición de cursor.BORRAEN ;E=0: desactiva Enable.movwf TLCD2 ;Salva dato en registro temporal.bsf STATUS,RP0 ;Selecciona el banco 1.clrf TRISB ;Programa PORTB como salida.bcf STATUS,RP0 ;Selecciona banco 0.movf TLCD2,W ;Recupera valor leído.call R1MSreturn
Página 2
eeprom;********************************************************************; "EEPROM";Estas subrutinas permiten la lectura y escritura de la EEPROM de;datos. Manejan los registros EEdir y EEdat, para dirección y dato;respectivamente.;********************************************************************
CBLOCK 0x67EEdir, EEdatENDC
;********************************************************************; "LeeEE";Lee un byte de la dirección EEdir de la EEPROM de datos y lo carga;en el registro EEdat.;********************************************************************
LeeEE movf EEdir,W ;Copia en W la dirección de la EEPROM.bsf STATUS,RP1 ;Selecciona banco 2.movwf EEADR ;Escribe la dirección actual.bsf STATUS,RP0 ;Selecciona banco 3.bcf EECON1,EEPGD ;Selecciona memoria EEPROM de datos.bsf EECON1,RD ;Activa modo lectura.bcf STATUS,RP0 ;Selecciona banco 2.movf EEDATA,W ;Lee el byte.bcf STATUS,RP1 ;Selecciona banco 0.movwf EEdat ;Salva en registro el dato leído.return
;********************************************************************; "GrabEE";Graba un byte en la dirección contenida en EEdir. El byte a grabar;estará ubicado en la variable EEdat.;********************************************************************
GrabEE bcf PIR2,EEIF ;Borra el flag de la EEPROM.movf EEdat,W ;Copia en W el dato.bsf STATUS,RP1 ;Selecciona el banco 2.movwf EEDATA ;Copia en registro el dato a grabar.bcf STATUS,RP1 ;Selecciona el banco 0.movf EEdir,W ;Copia en W la dirección de EEPROM.bsf STATUS,RP1 ;Selecciona el banco 2.movwf EEADR ;Copia en registro la dirección actual.
bsf STATUS,RP0 ;Selecciona el banco 3.bcf EECON1,EEPGD ;Selecciona EEPROM de datos.bsf EECON1,WREN ;Habilita la escritura en EEPROM.movlw 0x55 ;Secuencia de escritura en EEPROM,movwf EECON2 ;descrita por Microchip.movlw 0xAA ; "movwf EECON2 ; "bsf EECON1,WR ;Comienza la escritura en EEPROM.bcf STATUS,RP0 ;Selecciona banco 0.bcf STATUS,RP1 ; "
Fingra: btfss PIR2,EEIF ;¿Fin del ciclo de escritura?goto Fingra ;No: continúa chequeo.bcf PIR2,EEIF ;Borra indicador de interrupción.return
Página 1
mul16x16
;********************************************************************; "mul16x16";Se realiza el producto de dos números de dos bytes cada uno, con un;resultado de cuatro bytes.;El multiplicando se encuentra en los registros MCDOH y MCDOL (bytes;alto y bajo respectivamente) y el multiplicador en MDORH y MDORL.;El resultado se encontrará disponible en los registros RESHH, RESHM,;RESLM y RESLL, ordenados de mayor a menor según pesos.;********************************************************************
CBLOCK 0x69MCDOH, MCDOL, MDORH, MDORL, RESHHRESHM, RESLM, RESLL, CONROTENDC
mul16x16: movlw .16movwf CONROTmovf MDORH,Wmovwf RESHHmovf MDORL,Wmovwf RESHMclrf MDORHclrf MDORLmovlw 0
reprot: rrf RESHH,F ;Rota byte cuarto de resultado.rrf RESHM,F ;Rota byte tercero de resultado.btfsc STATUS,C ;¿Hay que sumar?call ajsuma ;Sí: suma bytes menores.rrf MDORH,F ;Rota bytes de resultados.rrf MDORL,F ; "rrf RESLM,F ; "rrf RESLL,F ; "decfsz CONROT,F ;¿Se han efectuado 8 bucles?goto reprot ;No: repite proceso.movf MDORH,W ;Sí: ordena resultados en registros.movwf RESHH ; "movf MDORL,W ; "movwf RESHM ; "retlw 0
ajsuma:movf MCDOL,W ;Suma bytes bajos.addwf MDORL,F ; "btfsc STATUS,C ;¿Hay acarreo?incf MDORH,F ;Sí: incrementa byte mayor de MDOR.movf MCDOH,W ;No: suma bytes mayores.addwf MDORH,F ; "retlw 0
Página 1
paridad
; - PROGRAMA Nº -;********************************************************************; "Paridad";Calcula la paridad del byte dado W y deja el resultado en el bit de;acarreo, de la siguiente manera:; Paridad PAR en W ==> C=0; Paridad IMPAR en W ==> C=1.;********************************************************************
CBLOCK 0x49PAR1ENDC
Par: movwf PAR1 ;Carga el dato en registro Temp.swapf PAR1,W ;Conmuta cuartetos y lo deja en W.xorwf PAR1,F ;Función OREX entre B7-B3, B6-B2, B5-B1
y
B4-B0.rlf PAR1,W ;Rota a izquierda para posicionar bits.xorwf PAR1,W ;OREX entre (B7-B3)-(B6-B2),
5-B1)-(B4-B0).movwf PAR1rlf PAR1,Frlf PAR1,Fxorwf PAR1,Frlf PAR1,Freturn
Página 1
retardos
;********************************************************************;CONJUNTO DE SUBRUTINAS QUE PUEDEN INCLUIRSE EN OTROS PROGRAMAS CON;LA ORDEN include "retardos.inc";Se dispone de retardos de 100 microseg., 1 ms, 5 ms, 10 ms, 20 ms,;100 ms y 1 s, y las más largas tratan el WDT.;********************************************************************
CBLOCK 0x64RET1, RET2, RET3ENDC
;************************************************************************; Cálculo del tiempo;Para una Fclock = 4 MHz, Tclock = 0,25 microsegundos.;Un ciclo de instrucción se ejecuta en 4 Tclock = 1 microsegundo (us).;;tsubrutina R100MI = (3.RET1 + 7) micseg.;tsubrutina R1MS = (4.RET1 + 8) micseg.;tsubrutina R5MS = (4.RET1.RET2 + 4.RET2 + 8) micseg.;tsubrutina R10MS = (4.RET1.RET2 + 4.RET2 + 5) micseg.;tsubrutina R20MS = (4.RET1.RET2 + 4.RET2 + 5) micseg.;tsubrutina R100MS = (4.RET1.RET2 + 4.RET2 + 5) micseg.;tsubrutina R1S = (4.RET1.RET2.RET3 + 4.RET2.RET3 + 4.RET3 + 5) micseg.;************************************************************************
;********************************************************************; "R100MI";Rutina de temporización 100 microsegundos.;********************************************************************
R100MI: movlw .31 ;Carga RET1.movwf RET1 ; "
R100MI1: decfsz RET1,F ;Decrementa RET1 hasta su valor 00h.goto R100MI1 ;Si RET1 no es cero repite decremento.nop ;Si RET1=0 ajusta tiempo y retorna.nop ; "return
;********************************************************************; "R1MS";Rutina de temporización 1 milisegundo.;********************************************************************
R1MS movlw .248 ;Carga RET1.movwf RET1 ; "
R1MS1: clrwdt ;Borra WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R1MS1 ;Si RET1 no es cero repite decrementonop ;Si RET1=0 ajusta tiempo y retorna.nop ; "nop ; "return
;********************************************************************; "R5MS";Rutina de temporización 5 milisegundos.;********************************************************************
R5MS movlw .24 ;Carga RET2.movwf RET2 ; "
R5MS1: movlw .51 ;Carga RET1.movwf RET1 ; "
R5MS2: clrwdt ;Inicializa WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R5MS2 ;Si RET1 no es cero repite decremento.decfsz RET2,F ;Si RET1=0 decrementa RET2.goto R5MS1 ;Si RET2 no es 0 repite el bucle.nop ;Si RET2=0 ajusta tiempo y retorna.nop ; "nop ; "return
;********************************************************************; "R10MS";Rutina de temporización 10 milisegundos.;********************************************************************
R10MS movlw .25 ;Carga RET2.movwf RET2 ; "
R10MS1: movlw .99 ;Carga RET1.movwf RET1 ; "
R10MS2: clrwdt ;Inicializa WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R10MS2 ;Si RET1 no es cero repite decremento.decfsz RET2,F ;Si RET1=0 decrementa RET2.goto R10MS1 ;Si RET2 no es 0 repite el bucle.return ;Si RET=0 retorna.
Página 1
retardos
;********************************************************************; "R20MS";Rutina de temporización 20 milisegundos.;********************************************************************
R20MS movlw .25 ;Carga RET2.movwf RET2 ; "
R20MS1: movlw .199 ;Carga RET1.movwf RET1 ; "
R20MS2: clrwdt ;Inicializa WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R20MS2 ;Si RET1 no es cero repite decremento.decfsz RET2,F ;Si RET1=0 decrementa RET2.goto R20MS1 ;Si RET2 no es 0 repite el bucle.return
;********************************************************************; "R100MS";Rutina de temporización 100 milisegundos.;********************************************************************
R100MS movlw .100 ;Carga RET2.movwf RET2 ; "
R100MS1: movlw .249 ;Carga RET1.movwf RET1 ; "
R100MS2: clrwdt ;Inicializa WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R100MS2 ;Si RET1 no es cero repite decremento.decfsz RET2,F ;Si RET1=0 decrementa RET2.goto R100MS1 ;Si RET2 no es 0 repite el bucle.return
;********************************************************************; "R1S";Rutina de temporización 1 segundo.;********************************************************************
R1S movlw .250 ;Carga RET3.movwf RET3 ; "
R1S1: movlw .100 ;Carga RET2.movwf RET2 ; "
R1S2: movlw 9 ;Carga RET1.movwf RET1 ; "
R1S3: clrwdt ;Inicializa WDT.decfsz RET1,F ;Decrementa RET1 hasta cero.goto R1S3 ;Si RET1 no es cero repite decremento.decfsz RET2,F ;Si RET1=0 decrementa RET2.goto R1S2 ;Si RET2 no es 0 repite el bucle 2.decfsz RET3,F ;Si RET2=0 decrementa RET3.goto R1S1 ;Si RET3 no es 0 repite el bucle 3.return
;********************************************************************; CBLOCK dirección o etiqueta; variables; ENDC;Ejemplo:; CBLOCK 0x40; RET1, RET2, RET3; ENDC;Se asignará la dirección 40h a RET1, la 41h a RET2 y la 43h a RET3.;Se conseguirá lo mismo así:; CBLOCK variables; RET1, RET2, RET3; ENDC; Y en el programa principal asignamos:; variables equ 40;********************************************************************
Página 2
rs232
; "rs232.inc";********************************************************************;Conjunto de rutinas de control de transmisión vía RS232.;El programa principal que usa estas rutinas tiene que cargar las;siguientes variables:
;CLKIN: Frecuencia del oscilador en ciclos/segundo.;BAUDIOS: Frecuencia de comunicación.;TRMODO: Modo de transmisión: "1" transmite primero bit LSB.;REMODO: Modo de recepción: "1" recibe primero bit LSB.;TRANBIT: Número de bits a transmitir: 7 u 8.;RECNBIT: Número de bits a recibir: 7 u 8.;STOPNBIT: Número de bits de stop: 1 o 2.;CONT: Contador de bits.
CLKOUT equ CLKIN >> 2 ;Calcula duración del ciclo máquina (CLKOUT=CLKIN/4).DURBIT equ ((CLKOUT/BAUDIOS)/3)-.5 ;Calcula la duración del bit.DURBITL equ low DURBIT ;Calcula la parte baja de RET.DURBITH equ high DURBIT+1 ;Calcula la parte alta de RET.DURST equ (DURBIT/2)+DURBIT ;Calcula duración del bit de inicio (START).DURSTL equ low DURST ;Calcula parte baja de START.DURSTH equ high DURST+1 ;Calcula parte alta de START.
CBLOCK 0x5E ;Inicio de las variables para RS232. REGREC ;Registro de recepción.REGTRAN ;Registro de transmisión.CONTRAN ;Contador de bits transmitidos.CONDURL ;Contador de delay parte baja.CONDURH ;Contador de delay parte alta.CONT ;Contador de bits.ENDC
#define PATTRAN PORTB,4 ;Línea de transmisión#define PATREC PORTB,5 ;Línea de recepción
;********************************************************************; "RECEP";Rutina de recepción. Después de la detección del bit de inicio;espera la recepción de una palabra de 7 u 8 bits, según se programe;la variable "RECNBIT". Además, según el valor de "REMODO", se podrá;recibir primero el bit de mayor o menor peso ("REMODO"=1 primero el LSB).;********************************************************************
RECEP clrf REGREC ;Borrar registro receptor.
RECEP1: clrwdt ;Refresco del WDT.btfsc PATRECgoto RECEP1 ;Espera el bit de inicio (0).call TBSTREC ;Tiempo de retraso del bit de inicio
;(1.5 de la célula de bit).
IF RECNBIT == 8
movlw 8 ;8 bits de datos.
ELSE
movlw 7 ;7 bits de datos.
ENDIF
movwf CONT
RECSIG: bcf STATUS,C
IF REMODO == 1
rrf REGREC,F ;Recibir primero el LSB.
ELSE
rlf REGREC,F ;Recibir primero el MSB.
ENDIF
btfsc PATREC ;Chequea bit de entrada.
IF REMODO == 1IF RECNBIT == 8
bsf REGREC,7 ;Activa bit 7 de REGREC si nºbits=8;y 1º bit LSB.
ELSE
bsf REGREC,6 ;Activa bit 6 de Rxdreg si nºbits=7;y 1º bit LSB.
ENDIFELSE
bsf REGREC,0 ;Activa bit 0 de Rxdreg si 1º el bit
Página 1
rs232MSB.
ENDIF
call RETBIT ;Espera entre bits.decfsz CONT,F ;Decrementa contador de nº de bits.goto RECSIGcall RETBIT
IF STOPNBIT == 2
call RETBIT
ENDIF ;Espera 1 o 2 bits de stop.
retlw 0
;********************************************************************; "TRANSM";Rutina de transmisión. Tras el bit de inicio se transmite la palabra;contenida en el registro transmisor REGTRAN, seguido de uno o dos;bits de stop, según se programe la variable STOPNBIT.;********************************************************************
TRANSMIF TRANBIT == 8
movlw 8 ;Transmisión de palabras de 8 bits.
ELSE
movlw 7 ;Transmisión de palabras de 7 bits.
ENDIF
movwf CONT
IF TRMODO == 1 ;Si se transmite 1º el LSB y la palabraELSE ;es de 7 bits, el registro transmisor
IF TRANBIT == 8 ;se desplaza una posición a la izquierda
ELSE ;para descartar el 8º bit.
rlf REGTRAN,F
ENDIFENDIF
bcf PATTRAN ;Transmite el bit de inicio.call RETBIT
TRANSIG: bcf STATUS,C
IF TRMODO == 1
rrf REGTRAN,F ;Desplaza a dcha. si 1º es el LSB.
ELSE
rlf REGTRAN,F ;Desplaza a izda. si 1º es el MSB.
ENDIF
btfsc STATUS,C ;Si el carry es uno, se transmite 1bsf PATTRAN ; "btfss STATUS,C ;Si el carry es cero se transmite 0.bcf PATTRAN ; "call RETBIT ;decfsz CONT,F ;Decrementa contador de bits.goto TRANSIG ;Si no es cero repite ciclo.bsf PATTRAN ;Si es cero transmite un bit de stop.call RETBIT ;
IF STOPNBIT == 2
bsf PATTRAN ;Transmite segundo bit de stop.call RETBIT ;
ENDIF
retlw 0
;********************************************************************; "RETBIT";Rutina de temporización para los intervalos entre bit y bit.;********************************************************************
RETBIT: clrwdtmovlw DURBITHmovwf CONDURH
RETBIT1: movlw CONDURLmovwf CONDURL
Página 2
rs232RETBIT2: decfsz CONDURL,F
goto RETBIT2decfsz CONDURH,Fgoto RETBIT1retlw 0
;********************************************************************; "TBITST";Rutina de temporización para el bit de inicio en modo Recepción.;Esta temporización es de 1,5 con respecto a la del resto de bits.;Así se consigue que el chequeo se produzca, aproximadamente, en el;centro de cada célula de bit recibido.;********************************************************************
TBITST: clrwdtmovlw DURSTHmovwf CONDURH
TBITST1: movlw DURSTLmovwf CONDURL
TBITST2: decfsz CONDURL,Fgoto TBITST2decfsz CONDURH,Fgoto TBITST1retlw 0
Página 3
rs232b
; - PROGRAMA Nº 53 -; "rs232.inc";********************************************************************;Conjunto de rutinas de control de transmisión vía RS232.;El programa principal que usa estas rutinas tiene que cargar las;siguientes variables:
;CLKIN: Frecuencia del oscilador en ciclos/segundo.;BAUDIOS: Frecuencia de comunicación.;TXMOD: Modo de transmisión: "1" transmite primero bit LSB.;RXMOD: Modo de recepción: "1" recibe primero bit LSB.;BITTR: Número de bits a transmitir: 7 u 8.;BITRC: Número de bits a recibir: 7 u 8.;BITSP: Número de bits de stop: 1 o 2.;CONBIT: Contador de bits.;********************************************************************
CLKOUT equ CLKIN >> 2 ;CLKOUT=CLKIN/4.DURBIT equ ((CLKOUT/BAUDIOS)/3)-.5 ;Establece duración del bit.DURBITL equ low DURBIT ;Calcula la parte baja de RET.DURBITH equ high DURBIT+1 ;Calcula la parte alta de RET.DURST equ (DURBIT/2)+DURBIT ;Calcula duración del bit de inicio (START).DURSTL equ low DURST ;Calcula parte baja de START.DURSTH equ high DURST+1 ;Calcula parte alta de START.
CBLOCK 0x5E REGRC ;Registro de recepción.REGTR ;Registro de transmisión.CONTR ;Contador de bits transmitidos.CONDURL ;Contador de delay parte baja.CONDURH ;Contador de delay parte alta.CONBIT ;Contador de bits.ENDC
#define PATTR PORTB,4 ;Línea de transmisión#define PATRC PORTB,5 ;Línea de recepción
;********************************************************************; "REC";Rutina de recepción. Después de la detección del bit de inicio;espera la recepción de una palabra de 7 u 8 bits, según se programe;la variable "BITRC". Además, según el valor de "RXMOD", se recibirá;primero el bit de mayor o menor peso ("RXMOD"=1 primero el LSB).;********************************************************************
REC: clrf REGRC ;Borrar registro receptor.
REC1: clrwdtbtfsc PATRCgoto REC1 ;Espera el bit de inicio (0).call TBSTREC ;Tiempo de retraso del bit de inicio
;(1.5 de la célula
de bit).
IF BITRC == 8
movlw 8 ;8 bits de datos.
ELSE
movlw 7 ;7 bits de datos.
ENDIF
movwf CONBIT
REC2:bcf STATUS,C
IF RXMOD == 1
rrf REGRC,F ;Recibir primero el LSB.
ELSE
rlf REGRC,F ;Recibir primero el MSB.
ENDIF
btfsc PATRC ;Chequea bit de entrada.
IF RXMOD == 1IF BITRC == 8
bsf REGRC,7 ;Activa bit 7 de REGREC si nºbits=8;y 1º bit LSB.
ELSE
bsf REGRC,6 ;Activa bit 6 de Rxdreg si nºbits=7
Página 1
rs232b;y 1º bit LSB.
ENDIFELSE
bsf REGRC,0 ;Activa bit 0 de Rxdreg si 1º el bit MSB.
ENDIF
call RETBIT ;Espera entre bits.decfsz CONBIT,F ;Decrementa contador de nº de bits.goto REC2call RETBIT
IF BITSP == 2
call RETBIT
ENDIF ;Espera 1 o 2 bits de stop.
retlw 0
;********************************************************************; "TR";Rutina de transmisión. Tras el bit de inicio se transmite la palabra;contenida en el registro transmisor REGTR, seguido de uno o dos;bits de stop, según se programe la variable BITSP.;********************************************************************
TR:IF BITTR == 8
movlw 8 ;Transmisión de palabras de 8 bits.
ELSE
movlw 7 ;Transmisión de palabras de 7 bits.
ENDIF
movwf CONBIT
IF TXMOD == 1 ;Si se transmite 1º el LSB y la palabraELSE ;es de 7 bits, el registro transmisor IF BITTR == 8 ;se desplaza una posición a la
izquierda ELSE ;para descartar el 8º bit.
rlf REGTR,F
ENDIFENDIF
bcf PATTR ;Transmite el bit de inicio.call RETBIT
TR1:bcf STATUS,C
IF TXMOD == 1
rrf REGTR,F ;Desplaza a dcha. si 1º es el LSB.
ELSE
rlf REGTR,F ;Desplaza a izda. si 1º es el MSB.
ENDIF
btfsc STATUS,C ;Si el carry es uno, se transmite 1bsf PATTR ; "btfss STATUS,C ;Si el carry es cero se transmite 0.bcf PATTR ; "call RETBIT ;decfsz CONBIT,F ;Decrementa contador de bits.goto TR1 ;Si no es cero repite ciclo.bsf PATTR ;Si es cero transmite un bit de stop.call RETBIT ;IF BITSP == 2
bsf PATTR ;Transmite segundo bit de stop.call RETBIT ;
ENDIF
retlw 0
;********************************************************************; "TempB";Rutina de temporización para los intervalos entre bit y bit.;********************************************************************
TempB: clrwdt
Página 2
rs232bmovlw DURBITHmovwf CONDURH
TempB1: movlw CONDURLmovwf CONDURL
TempB2: decfsz CONDURL,Fgoto TempB2decfsz CONDURH,Fgoto TempB1retlw 0
;********************************************************************; "TempST";Rutina de temporización para el bit de inicio en modo Recepción.;Esta temporización es de 1,5 con respecto a la del resto de bits.;Así se consigue que el chequeo se produzca, aproximadamente, en el;centro de cada célula de bit recibido.;********************************************************************
TempST: clrwdtmovlw DURSTHmovwf CONDURH
TempST1:movlw DURSTLmovwf CONDURL
TempST2: decfsz CONDURL,Fgoto TempST2decfsz CONDURH,Fgoto TempST1retlw 0
Página 3
rut_i2c
;******************************************************************************; "rut_i2c";Aquí se engloban el conjunto de subrutinas necesarias para la comunicación I2C.;Subrutinas:;; ENVINI: envía el MAESTRO la condición de inicio.; ENVSTOP: envía el MAESTRO la condición de STOP.; ENVBYTE: envía el byte contenido en el registro W.; LEEBYTE: se lee un byte del SERVIDOR. El byte leído estará en W.;******************************************************************#define SCL PORTC,3#define SDA PORTC,4
;******************************************************************; "SDABAJO";Pone la línea de dato en nivel bajo;******************************************************************SDABAJO:
bsf STATUS,RP0 ;Programa SDA como salida.bcf SDA ; "bcf STATUS,RP0 ;bcf SDA ;Pone a 0 la línea SDA.return
;******************************************************************; "SCLBAJO";Pone la línea de reloj en nivel bajo.;******************************************************************SCLBAJO:
bsf STATUS,RP0 ;Programa SDL como salida.bcf SDL ; "bcf STATUS,RP0 ;bcf SDL ;Pone a 0 la línea SDL.return
;******************************************************************; "SDAZ;Pone la línea de datos en alta impedancia.;******************************************************************SDAZ:
bsf STATUS,RP0 ;Programa SDA como entrada.bsf SDA ; "bcf STATUS,RP0 ;return
;******************************************************************; "ENVINI;Se envía la condición de Inicio.;******************************************************************ENVINI: bcf PIR1,SSPIF ;Borra indicador de interrupción.
bsf STATUS,RP0 ;Selecciona banco 1.bsf SSPCON2,SEN ;Activa secuencia de inicio.bcf STATUS,RP0 ;Selecciona banco 0.
ENVINI1: btfss PIR1,SSPIF ;¿Fin de secuencia de inicio?goto ENVINI1 ;No: espera.return ;Sí: retorna
;********************************************************************; " ENVSTOP ";Envía la secuencia de stop.;********************************************************************
ENVSTOP: bcf PIR1,SSPIF ;Borra indicador de interrupción.bsf STATUS,RP0 ;Selecciona banco 1.bsf SSPCON2,PEN ;Activa secuencia de Stop.bcf STATUS,RP0 ;Selecciona banco 0.
ENVSTOP1:btfss PIR1,SSPIF ;¿Fin de secuencia de Stop?goto ENVSTOP1 ;No: espera.return ;Sí: retorna.
;********************************************************************; " ENVBYTE ";Transmite byte del W vía I2C. La rutina finalizará al recibir /ACK.;********************************************************************
ENVBYTE: bcf PIR1,SSPIF ;Borra indicador de interrupción.movwf SSPBUF ;Carga byte en buffer de salida el
;byte a transmitir.
ENVBYTE1: btfss PIR1,SSPIF ;¿Recibido el bit /ACK?goto ENVBYTE1 ;No: espera.return ;Sí: retorna.
;********************************************************************; " LEEBYTE ";Lee byte procedente del dispositivo I2C seleccionado, y lo devuelve;en W. Seguidamente se genera y transmite el bit /ACK.;********************************************************************
Página 1
rut_i2c
LEEBYTE: bcf PIR1,SSPIF ;Borra indicador de interrupción.bsf STATUS,RP0 ;Selecciona banco 1.bsf SSPCON2,RCEN ;Activa el modo receptor.bcf STATUS,RP0 ;Selecciona banco 0.
LEEBYTE1: btfss PIR1,SSPIF ;¿Recibidos los 8 bits?goto LEEBYTE1 ;No: espera.bcf PIR1,SSPIF ;Sí: restaura el indicador.bsf STATUS,RP0 ;Selecciona banco 1.bcf SSPCON2,ACKDT ;Pone bit ACK a "0".bsf SSPCON2,ACKEN ;Activa secuencia de generación de ACK.bcf STATUS,RP0 ;Selecciona banco 0.
LEEBYTE2: btfss PIR1,SSPIF ;¿Secuencia ACK finalizada?goto LEEBYTE2 ;No: espera.movf SSPBUF,W ;Sí: lee el byte recibido.return
Página 2
ruti2c;********************************************************************; I2C.INC;;Conjunto de rutinas para transmisión/recepción de bytes en bus I2C.;********************************************************************
;********************************************************************;Definición de registros empleados por el software del bus I2C ;********************************************************************Clkout equ CLKIN >> 2 ;Frecuencia de trabajo (Clkin/4)
Ret4us set (Clkout/.250000) ;Constante para 4 uSRet47us set (Clkout/.212766) ;Constante para 4.7 uSRet5us set (Clkout/.200000) ;Constante para 5 uS
CBLOCK 0x58
Datrans ;Dato que va a ser transmitidoConbit ;Nº de bits a transmitir/recibir (0:7)Estadobus ;Registro de estado del bus I2CControlbus ;Registro de control del bus I2CRetcon ;Variable de temporizaciónDatranscop ;Copia del dato a transmitirENDC
;********************************************************************;Definición de las líneas del bus I2C;********************************************************************
#define SCL PORTB,7#define SDA PORTB,6#define SCLDIR PORTB,7#define SDADIR PORTB,6#define ESCRITURA 0#define LECTURA 1
;********************************************************************;Definición de los bits del registro de estado del bus I2C;********************************************************************
#define Busocup Estadobus,0 ;Bus I2C ocupado#define Abandon Estadobus,1 ;Comunicación abortada#define Transprog Estadobus,2 ;Transmisión en progreso#define Recprog Estadobus,3 ;Recepción en progreso#define Transfin Estadobus,4 ;Transmisión finalizada#define Recfin Estadobus,5 ;Recepción finalizada#define Errcom Estadobus,6 ;Error en comunicación#define ErrACK Estadobus,7 ;Error en bit ACK
;********************************************************************;Definición de los bits del registro de control del bus I2C;********************************************************************
#define Ultbytetr Controlbus,2 ;Indica si es el último byte a recibir
;********************************************************************; Macro de propósito general;********************************************************************
LIBUS MACRO bsf STATUS,RP0 ;Selecciona banco 1 bsf SDA ;SDA en triestado bsf SCL ;SCL en triestado bcf Busocup ENDM
;********************************************************************; " Inibus ";Inicialización del Bus I2C;********************************************************************
Inibus: bcf STATUS,RP0 ;Selecciona página 0 de datos movf PORTB,W ;Carga puerta B andlw 0x3f movwf PORTB ;Pone a 0 los latch internos ;de las líneas SCL y SDALIBUS ;Coloca SDA y SCL en triestad
clrf Controlbus ;Borra registro de controlclrf Estadobus ;Borra registro de estadoreturn
;********************************************************************; " Inic ";Transmisión de la condición de inicio;********************************************************************
Inic: bsf STATUS,RP0 ;Selecciona página 1bsf SDA ;Pone como entradas las señales SDA ybsf SCL ;SCL que al estar con resistencia
Página 1
ruti2c ;pull-up, las líneas SDA y SCL se mantienen a "1"
call Ret4uSbcf SDA ;La señal SDA se configura como salida
;que saca el "0" del latch interno ha-;ciendo que la línea SDA caiga a "0";mientras SCL se mantiene a "1" (con-;dición de inicio)
call Ret47uSbsf Busocup ;Activa flag de bus ocupadoreturn
;********************************************************************; " Envstop ";Transmisión de la condición de stop;********************************************************************
Envstop: bsf STATUS,RP0 ;Selecciona página 1 de datosbcf _SCL ;Las señales SCL y SDA se programanbcf _SDA ;como salidas. El contenido de los
;latch internos hace que las líneas;SCL y SDA se pongan a "0"
bsf _SCL ;Esta señal se programa ahora como;entrada en alta impedancia que, gra-;cias a las pull-up internas, pone a;"1" la línea SCL.
call Delay4uSbsf _SDA ;Esta señal se programa ahora como
;entrada en alta impedancia que, gra-;cias a las pull-up internas, genera un;flanco de subida en la línea SDA (con-;dición de stop).
call Delay47uS ;Asegura que no se envía una nueva;condición de start justo después de la;de stop.
bcf _Bus_Busy ;Tras el stop se considera que el bus ;está libre borrando el bit de estado
return
;********************************************************************; " Trcancel ";Abortar la transmisión;********************************************************************
Trcancel: call Txt_Stop_Bit ;Transmite la condición de stopbsf _Abort ;Activa flag en registro de estadoreturn
;********************************************************************; " Trbyte ";Transmisión de un byte de datos. El byte a transmitir debe cargarse;previamente en el registro DataByte (---0xCh---);********************************************************************
Trbyte: movf DataByte,w ;Realiza una copia del byte a trans-movwf DataByteCopy ;mitir (pos.0x0e)bsf _Txmt_Progreso ;Activa flag de transmisión en cursobcf _Txmt_Acabada ;Desactiva flag de finalizaciónmovlw 8movwf BitCount ;Número de bits a transmitirbsf STATUS,RP0 ;Selecciona página 1 de datos
TxtNextBit:clrwdt ;Refresco del WDTbcf _SCL ;Pone a "0" la línea SCLrlf DataByteCopy,f ;Desplaza bit de más pesobcf _SDA ;Pone a "0" la l¡nea SDAbtfsc STATUS,C ;Testea bit a sacar sito en el carrybsf _SDA ;Saca "1" por la línea SDA poniendo
;la señal SDA como entrada pull-upcall Delay47uSbsf _SCL ;Pone a "1" la línea SCL poniendo
;la señal SCL como entrada pull-upcall Delay4uSdecfsz BitCount,f ;Decrementa contador de bitsgoto TxtNextBit ;Chequeo del bit ACK
bcf _SCL ;Pone a "0" la línea SCLbsf _SDA ;Pone a "1" la línea SDA para detec-
;tar cuándo el slave la pone a "0"call Delay47uSbsf _SCL ;Pone a "1" línea de relojcall Delay4uSbcf STATUS,RP0 ;Selecciona página 0 de datosbtfsc _SDA ;La señal SDA debe estar a "0" envia-
;do por el slavegoto TxtErrorAckbsf STATUS,RP0 ;Selecciona página 1 de datosbcf _SCL ;Pone a "0" la línea SCLbcf _Txmt_Progreso ;Borra flag de transmisión en cursobsf _Txmt_Acabada ;Activa flag de fin de transmisiónbcf _ACK_Error ;Bit ACK okey
Página 2
ruti2cbcf _Bus_Busy ;Flag de que el bus está librereturn
TxtErrorAck:LIBERA_BUS bcf _Txmt_Progreso ;Borra flag de transmisión en cursobcf _Txmt_Acabada ;Borra flag de fin de transmisiónbsf _ACK_Error ;Activa bit de error ACK (NACK)
return
;********************************************************************; " RecByte ";Recepción de un byte desde el slave;El dato recibido se almacena en el registro DataByte (posición 0xch);El bit _Ultimo_Byte del registro de control determina si se espera recibir;más bytes desde el slave, en cuyo caso se le manda ACK o, si es el último,;en cuyo caso se envía NACK.;********************************************************************
RcvByte: bsf _Rcv_Progreso ;Flag de recepción en cursobcf _Rcv_Acabada ;Desactiva flag de fin de recepciónmovlw 0x08 ;Carga el contador de bits a recibirmovwf BitCount
RcvNextBit:clrwdtbsf STATUS,RP0 ;Selección de página 1 de datosbcf _SCL ;Pone a "0" la línea de relojbsf _SDA ;Pone a "1" la línea de datoscall Delay47uSbsf _SCL ;El reloj pasa a "1". El bit de datos
;es puesto por el slavecall Delay4uSbcf STATUS,RP0 ;Seleciona página 0 de datosbcf STATUS,C ;Pone el flag carry a "0"btfsc _SDA ;Chequea el nivel en línea de datosbsf STATUS,C ;Está a "1", activa el carryrlf DataByte,f ;Desplaza a la izda. (primero el bit
;de más peso)decfsz BitCount,f ;Decrementa contador de bits a recibirgoto RcvNextBit
;El Master genera ACK si no es el último byte a recibir. Si es el último;se genera NACK y a continuación se debe generar la condición de stop.
bsf STATUS,RP0 ;Selecciona página 1 de datosbcf _SCL ;Pone a "0" la línea de relojbcf _SDA ;Pone a "0" la línea de datos (ACK)btfsc _Ultimo_Byte ;Determina si es el último bytebsf _SDA ;Pone a "1" la línea de datos (NACK)call Delay47uSbsf _SCL ;Pone a "1" la línea de relojcall Delay4uSbcf _SCL ;Pone a "0" la línea de relojbcf _Rcv_Progreso ;Desactiva flag de recepción en cursobsf _Rcv_Acabada ;Activa flag de fin de recepciónbcf _ACK_Error ; ACK okreturn
;********************************************************************;Rutinas de temporización de propósito general;********************************************************************
Delay5uS:movlw ((_5uS_Delay-5)/3+1)
delay: movwf DelayCountdecfsz DelayCount,fgoto $-1return
Delay47uS:movlw ((_47uS_Delay)-8/3+1)goto delay
Delay4uS:movlw ((_4uS_Delay)-8/3+1)goto delay
end
Página 3
teclado;********************************************************************; "teclado.inc";;Es un conjunto de subrutinas para la gestión de un teclado hexadecimal;organizado en una matriz de 4 x 4, tal y como es el caso del teclado;incorporado en la tarjeta de ampliación MicroPic Trainer PLUS.;Este fichero se debe incluir en los futuros programas fuente mediante;la directiva INCLUDE.;;CHEQTEC: Realiza un barrido del teclado y detecta si hay alguna; tecla pulsada. La variable "CODTEC" retorna con el código; de la tecla pulsada, o el 0x80 en caso de no existir; pulsación.;;TECHEX: Convierte el código de tecla en código HEX (del 0 a F).; Antes de llamar a esta rutina, la variable "CODTEC" debe; contener el código de tecla; al finalizar, la rutina; devolverá, en la misma variable "CODTEC", el código HEX.;;El teclado está conectado al PORTB, y su disposición es la siguiente:;; RB0 RB1 RB2 RB3; ^ ^ ^ ^ TECLA CODIGO; | | | | ----- --------------; |---|---|---|---| 0 01111101 = 0x7D; RB4 --> | 1 | 2 | 3 | F | 1 11101110 = 0xEE; |---|---|---|---| 2 11101101 = 0xED; RB5 --> | 4 | 5 | 6 | E | 3 11101011 = 0xEB; |---|---|---|---| 4 11011110 = 0xDE; RB6 --> | 7 | 8 | 9 | D | 5 11011101 = 0xDD; |---|---|---|---| 6 11011011 = 0xDB; RB7 --> | A | 0 | B | C | 7 10111110 = 0xBE; |---|---|---|---| 8 10111101 = 0xBD; 9 10111011 = 0xBB; A 01111110 = 0x7E; B 01111011 = 0x7B; C 01110111 = 0x77; D 10110111 = 0xB7; E 11010111 = 0x; F 11100111 = 0xE7;;Hubiera sido más interesante que RB4-RB7 actuaran como entradas para;poder utilizar la capacidad que tiene el PIC de provocar interrupción;al cambiar de estado estas líneas. Pero esto no es posible dado que,;en la Trainer, las líneas RB6 y RB7 forman parte también del circuito;de grabación.
CBLOCK 0x54 ;Inicio de las variables.CODTEC ;Código final de tecla.COLUM ;Nº de columnas a explorar.TTEC ;Temporal de código.TTRISB ;Estado temporal de TRISBENDC
;********************************************************************; "CHEQTEC";Rutina de exploración del teclado. La variable "CODTEC" retorna con;el código de la tecla pulsada, o el código 0x80 si no hay pulsación.;********************************************************************
CHEQTEC: bsf STATUS,RP0 ;Selecciona banco 1.movf TRISB,W ;Salva el estado actual de TRISB.movwf TTRISB ; "movlw b'00001111' ;Programa RB0-RB3 como entradasmovwf TRISB ;y RB4-RB7 como salidas.bcf OPTION_REG,7 ;Habilita resistencias de PORTB.bcf STATUS,RP0 ;Selecciona banco 0.movlw 4 ;Nº de columnas a explorar.movwf COLUM ; "movlw b'01111111' ;Saca "0" por la fila RB7.movwf CODTEC ; "
CHEQTEC1:movf CODTEC,W ; "movwf PORTB ; "
nop ;Separación de seguridad.movf PORTB,W ;Lectura del PORTB.movwf TTEC ;Guarda temporalmente la lectura.subwf CODTEC,W ;Chequea pulsación.btfss STATUS,Z ;Hay alguna pulsada ?goto CHEQTEC2 ;Sí: va a CHEQTEC2.bsf STATUS,C ;No: activa Carry.rrf CODTEC,F ;Prepara selección de ladecfsz COLUM,F ;siguiente columna.goto CHEQTEC1 ;Si no es la última salta a CHEQTEC1.movlw 0x80 ;Si es la última carga 80h en W.
Sale: movwf CODTEC ;Carga el 80h en CODTEC (sin pulsación).
movf TTRISB,W ;Recupera dirección de PORTB original.bsf STATUS,RP0 ;Selecciona banco 1.movwf TRISB ;Repone valor original en TRISB.bsf OPTION_REG,7 ;Inhibe resistencias de PORTB.bcf STATUS,RP0 ;Selecciona banco 0.
Página 1
tecladoreturn
CHEQTEC2: call R20MS ;Retardo de 20 ms para rebotes.movf CODTEC,W ;Chequea teclado para ver hay nuevamovwf PORTB ;pulsación.nop ; "movf PORTB,W ; "subwf TTEC,W ; "btfss STATUS,Z ;¿Es la misma pulsación?goto CHEQTEC1 ;No: continúa con la exploración.movf TTEC,W ;Si: se guarda valor en "CODTEC" elgoto Sale
;********************************************************************; "TECHEX";Convierte el código de tecla que haya en la variable "CODTEC" a código;Hexadecimal. El resultado se tiene en la variable "CODTEC".;******************************************************************** TECTAB movf COLUM,W
addwf PCL,F ;Calcula desplazamientoretlw 0x7D ;0retlw 0xEE ;1retlw 0xED ;2retlw 0xEB ;3retlw 0xDE ;4retlw 0xDD ;5retlw 0xDB ;6retlw 0xBE ;7retlw 0xBD ;8retlw 0xBB ;9retlw 0x7E ;Aretlw 0x7B ;Bretlw 0x77 ;Cretlw 0xB7 ;Dretlw 0xD7 ;Eretlw 0xE7 ;F
TECHEX: movf CODTEC,W ;Carga en W el código de tecla. movwf TTEC ;Salva el código temporalmente. clrf COLUM ;Pone a 0 el contador de columnas, que
;en este caso se emplea como código de;carácter hexadecimal.
TECHEX1: call TECTAB ;Busca código en la tabla. subwf TTEC,W ;Compara con el de la tecla. btfsc STATUS,Z ;¿Coincide? goto TECHEX2 ;Sí: va a conseguir el código hexadecimal. incf COLUM,F ;No: incrementa contador columnas. goto TECHEX1 ;Repite conversión.
TECHEX2: movf COLUM,W ;Graba en CODTEC el contadormovwf CODTEC ;de columnas.return
Página 2
tecpc
;********************************************************************; "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 0x4ARdato, T1rtec, T2rtec, Tinter Cgentec, Rest, TRdato, MtriscRtecla, CcheqbatENDC
;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íneasbcf STATUS,RP0 ;del puerto C en el registro Mtrisc,movwf Mtrisc ;del banco 0.andlw b'01111101' ;Programa RC7 y RC1 como salidas, RC2iorlw 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
Página 1
tecpcrtecpc3: 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 0goto rel0_1 ;su señal de reloj.btfsc DATEN ;Espera a recibir el bit de STARTgoto 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 delgoto rel0_2 ;reloj emitido por el teclado.
rel1_1: btfsc RELEN ;Espera a que pase el nivel 1 delgoto rel1_1 ;reloj emitido por el teclado.btfss DATEN ;Capta bit entrante y lo va cargandogoto 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 delgoto rel0_3 ;reloj emitido por el teclado.
rel1_3: btfsc RELEN ;Espera a que pase el nivel 1 delgoto rel1_3 ;reloj emitido por el teclado.btfsc DATEN ;Capta bit entrante de paridad.goto captec3bcf 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 delgoto rel0_4 ;reloj emitido por el teclado.
rel1_4: btfsc RELEN ;Espera a que pase el nivel 1 delgoto 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 delgoto 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".;********************************************************************
Página 2
tecpcrsend: 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íneasbcf STATUS,RP0 ;del puerto C en el registro Mtrisc,movwf Mtrisc ;del banco 0.andlw b'01111101' ;Programa RC1 y RC7 como salidas, RC0iorlw 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 demovwf 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 elgoto mrel0_1 ;nivel bajo del reloj procedente deldecfsz 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 ponerbtfsc STATUS,C ;en C el bit a enviar.goto manda2bcf 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 delgoto mrel0_2 ;reloj.
mrel1_1: btfsc RELEN ;Espera a que pase el nivel 1 delgoto 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 estabacall 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 delgoto mrel0_3 ;reloj.
mrel1_2: btfsc RELEN ;Espera a que pase el nivel 1 delgoto 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 delgoto 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 delgoto mrel0_5 ;reloj.
mdat1: btfss DATEN ;Espera a encontrar el nivel 1 en
Página 3
tecpcgoto 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 intentosreturn ;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 demovwf Rdato ;velocidad y retardo.btfss biterr ;¿Ha habido error en el envío anterior?call mandack ;No: envía el byte de programación.
Página 4
tecpcreturn ;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 teclacall 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 delmovwf Rdato ;teclado.call mandack ; "movf TRdato,W ;Recupera valor de Rdato.movwf Rdato ; "return ;Retorna.
Página 5
tecpc
;********************************************************************; "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 delmovwf 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 elxorlw 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 esxorlw 00 ;igual a 00h?btfss STATUS,Z ; "return ;No: retorna.call rtecpc ;Sí: recibe el byte de teclado quereturn ;informará del Modo actual.
;********************************************************************; "restec";Subrutina que envía al teclado el código de RESET.;Si se produce error se activa biterr.;********************************************************************
Página 6
tecpc
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.
Página 7