- Cuando entrás en la interrupción ¿Salvás estado?hola eduardo, gracias por contestar.
- Al volver ¿Lo recuperás?
org 0x04
operaciones
guardo el resultado en valor_real
movfw valor_real
movwf portb ;test para comprobar que se tiene el contenido esperado
retfie ;para regresar de la interrupcion
el problema ocurre de regreso a la rutina MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,R
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3
MOVWF PCLATH_TEMP ;Save PCLATH into W
CLRF PCLATH ;Page zero, regardless of current page
:
:(ISR) ;(Insert user code here)
:
MOVF PCLATH_TEMP, W ;Restore PCLATH
MOVWF PCLATH ;Move W into PCLATH
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W
A esto me refería, es la secuencia que Microchip pone en todos los datasheets.tengo entendido que esto se hace para guardar los datos que se tienen antes de una interrupcion, ya que estos suelen cambiar durante las interrupciones. Pero en mi casoCódigo: [Seleccionar]MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,R
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3
MOVWF PCLATH_TEMP ;Save PCLATH into W
CLRF PCLATH ;Page zero, regardless of current page
:
:(ISR) ;(Insert user code here)
:
MOVF PCLATH_TEMP, W ;Restore PCLATH
MOVWF PCLATH ;Move W into PCLATH
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W
Si no salvás y recuperás el estado el retorno es impredecible salvo que se esté en un bucle ocioso.
List p=16f84a
#include <p16f84a.inc>
__config _XT_OSC & _PWRTE_ON & _CP_OFF & _WDT_OFF
org 0x00
;declaracion de variables
tmr0 equ 0x01
pcl equ 0x02
status equ 0x03
porta equ 0x05
portb equ 0x06
intcon equ 0x0b
option_reg equ 0x81
trisa equ 0x85
trisb equ 0x86
cblock 0x0c
conta
filas
columnas
contaf
f
c
valor_real
temp
d1
d2
flag
endc
goto principal ;####################################
org 0x04 ;######INTERRUPCIONES################
movfw portb ;estoy leyendo 'abcdxxxx'
movwf columnas
clrf porta ;limpio porta para que no se queden colgados valores
swapf columnas,1 ; ahora tengo 'xxxxabcd'
call delaym;
bsf flag,0
nop
movfw contaf ;carga w con el valor de contaf , conta
xorlw .1 ;comprueba si contaf vale 1
btfsc status,2 ;revisa : si Z=1 caso1, si Z=0 , volver a preguntar
goto casof1 ;;; aqui va si son iguales , caso1
movfw contaf ;aqui va si no es caso 1
xorlw .2
btfsc status,2
goto casof2 ;;aqui va si es caso2
movfw contaf
xorlw .3
btfsc status,2
goto casof3 ;caso3
casof4 movlw .12 ;de lo contrario pasa a casof4
movwf f
goto chkcol;return
casof3 movlw .8
movwf f
goto chkcol;return
casof2 movlw .4
movwf f
goto chkcol;return
casof1 movlw .0
movwf f
chkcol ;movfw columnas;carga w con el valor capturado de portb en columnas
btfss columnas,0
goto $+2
goto casoc1 ;aqui va caso1
btfss columnas,1
goto $+2
goto casoc2
btfss columnas,2
goto $+2
goto casoc3
btfss columnas,3
goto $+2
casoc4 movlw .3
movwf c
goto sumar;retfie
casoc3 movlw .2
movwf c
goto sumar;retfie
casoc2 movlw .1
movwf c
goto sumar;retfie
casoc1 movlw .0
movwf c
goto sumar;retfie
sumar movf c,0 ;cargamos w con el valor de c
addwf f,0 ;sumamos w con f y lo guardamos en w
movwf valor_real ;cargamos valor_real con el valor de la suma
;ya tengo mi valor real################################!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;ya tengo mi valor real################################!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
verificar movfw contaf ;verifica sin contaf=4 para reiniciarlo, casos contrarios <4 se incrementa su valor en 1
xorlw .1
btfss status,2 ;1 si son iguales, 0 si son diferentes
goto $+2
goto increment
movfw contaf
xorlw .2
btfss status,2 ;1 si son iguales, 0 si son diferentes
goto $+2
goto increment
movwf contaf
xorlw .3
btfss status,2
goto $+2
goto increment ; si esq si es el caso 3
re movlw .1 ;
movwf contaf ;reinicia conta=1
movwf filas ;filas=0001
movfw valor_real ;cargamos w con valor_real para pruebas
movwf portb
call delay500ms
;call delay500ms
;call delay500ms
;call delay500ms
movfw filas ;reinicia filas=0001
goto salir
increment incf contaf,1
rlf filas,1
movfw valor_real
movwf portb
call delay500ms
;call delay500ms
;call delay500ms
;call delay500ms
movfw filas ; 0002,3,4
salir bcf intcon,0
retfie
principal ;##############################################
;IOs
bsf status,5
movlw b'10000' ;porta como salidas
movwf trisa
movlw b'11110000'
movwf trisb
movlw b'11010111' ;rbpullup no, intedge=subida, t0cs=f/4 ,t0ie:bajada, psa->tmr0 ratio 1:256
movwf option_reg
bcf status,5;de vuelta al banco0
movlw b'10001000'
movwf intcon
clrf porta
clrf portb
movlw .1 ;cargar 1
movwf contaf ;se inicia con 1
movwf filas ;se inicia con 0001
clrf valor_real
clrf columnas
goto inicio
delay50ms
movwf temp
movlw .60
movwf tmr0
btfss intcon,2
goto $-1
bcf intcon,2
movfw temp
return
delaym
movwf temp
movlw .220
movwf tmr0
btfss intcon,2
goto $-1
bcf intcon,2
movfw temp
return
delay500ms
movwf temp
movlw .10
movwf d1
call delay50ms
decfsz d1
goto $-2
movfw temp
return
notecla
movfw contaf ;verificar si contaf es 4
xorlw .4 ;verificar si contaf es 4
btfsc status,2;verificar si contaf es 4
goto si4
incf contaf,1 ;si son diferentes
rlf filas,1
movfw filas
return
si4 movlw .1
movwf contaf
movwf filas
movfw filas
return
inicio
btfss flag,0
goto aqui
bcf flag,0
clrf porta
nop
aqui ;bsf intcon,7
movfw filas ;w se carga con el valor de filas *******
movwf porta
nop
call delaym
call notecla
nop
nop;aqui va lo que se hará si no se presiono una tecla
goto inicio
end
es un programa para leer un teclado matricial y mostrar la tecla presionada en un diplay a traves de un codificador bcd 74ls48tengo entendido que esto se hace para guardar los datos que se tienen antes de una interrupcion
Me parece, que el problema te lo da el call delaym dentro de la interrupción.
Por un tema del contador de programa, es preferible que todas las subrutinas estén por encima del programa, así cuando el CP tiene que volver, lo puede hacer sin problemas.
Entonces, en tu programa, el call tiene que ir más abajo y al subir, puede ser que lo esté haciendo en cualquier lado del programa; y no desde lo llamaste. Deberías simular esto con MPLAB; y asegurarte que retorne al lugar correcto.
buenas, ya implementé el codigo de salvar status y w y recuperarlos antes de volver a la interrupción pero sigue ocurriendo lo mismo,Citartengo entendido que esto se hace para guardar los datos que se tienen antes de una interrupcion
Ese codigo que te pasaron se DEBE realizar SIEMPRE, te doy un ejemplo:
Tu programa principal esta corriendo y antes de un BTFSS STATUS,Z salta a la interrupcion, vamos as decir que las banderas estaban en Z=1 C=0 (es decir no ejecuta el BTFSS)
En la interrupcion entras y operas, el registro STATUS cambia por las instrucciones que usas, llegas al final y tu registro status quedo Z=0 C=0
Vuelve al programa y ejecuta el BTFSS... Sorpresa, el BTFSS no salta porque Z=0...
Lo mismo puede ocurrir con W, si tenes cualquier instruccion que tome de W para operar y tenes una interrupcion antes, vas a tener problemas. Entonces ese código ES OBLIGATORIO en es PIC (hay otros PIC que tiene un auto-guardado)
Y como ves en tu programa estas modificando W y STATUS (con otras instrucciones) en todo momento.
Me parece, que el problema te lo da el call delaym dentro de la interrupción.
Por un tema del contador de programa, es preferible que todas las subrutinas estén por encima del programa, así cuando el CP tiene que volver, lo puede hacer sin problemas.
Entonces, en tu programa, el call tiene que ir más abajo y al subir, puede ser que lo esté haciendo en cualquier lado del programa; y no desde lo llamaste. Deberías simular esto con MPLAB; y asegurarte que retorne al lugar correcto.
hola, en este caso todas las subrutinas estan por encima del programa pero debajo de la interrupción, debería colocar las subrutinas por arriba de org0x04?
Me parece que ya encontré el error.Hola de nuevo, ya lo probé y sigue igual,
La subrutina notecla te estaba cambiando el valor de w. En la subrutina de delay, lo salvabas en una variable llamada temp para luego recuperar este dato antes de salir, pero en la otra no lo hiciste.
Volvé a carga mi programa de mi mensaje anterior, que ya lo actualicé.
Vamos a partir del principio, como debimos hacerlo.Ok aqui vamos:
Primero, explicá mejor como funciona, ya que no se bien que es lo que tiene que hacer.
Necesito saber que hace cada rutina o subrutina; excepto las de delay que son obvias; ya que me pierdo en el programa. Que obtenés en cada rutina y en donde se guarda y para qué.
¿Cómo está conectado el teclado al PIC? y ¿como está conectado el LCD al PIC?(https://lh3.googleusercontent.com/kMPytM-S2e9H340qYIohPT-TU7rHCtztOksX3VN1zM22MXCxNQTNWZl-YtLGC4BhSbcSYxpI--363FAvj90LAo_YFF2NVXwpZffOwDDQxCv8BfTT66Ltydfgk1BGc_D9tjbrvuqC_wUmAUvb6l14Apg7IScmOtpgsSc68D0XqtYEYz14OgxnTZCyC9LDaZAIBJ1uQUYZfAfasdseU37dfAQpUJqNLifSuSRs_Wt7rTj5dzZHzgDruamCDW7vmSYVDjHrBBmNTdvoPW3aPnuJbvlECcXLfuY0wT6cxakCdE4SPlUuRGKUxDWkr_gwg8t5g5Std2_TAZXh8_CPVGvC3831BX_MqVJfBIImWDDgcBaSWIaJ1I8MTVXNXjKLH_z-3LyzzaF7NEk8PbzmizIgPQAQq4qQzwcm73ALc3gp6DnlvoSfJVcQmEbeDVhLfOWbBv05AeGB4JCIjHJj4Zn9gdFBBt3OdgtFLp5KnWudTnhsrCKF1F4TZJ3xcUHIfqYfm5ABkKCEprFZH2g8jRAR-HkFWnqhJAedKpzYdbdz_ZA00PETpXIiDfBDqaCQ5OlLevrW-CVQEHPvvYdOdID_ZKcLxFQ2jv5wPts5C9fXcJdO7fpmO6mZULOArG7Kn-aPJUhNQ8owl40gmqnnO_KkDkihXtI1EwNjCEydphG1rUFzXJTxUH1dDJLrFyBP=w1336-h706-no?authuser=0)
No puedo ver la imagen.listo :-/ :-/
Adjuntalo aquí en un tamaño no mayor de 800 x 600 pixeles.
En la ventana de respuestas, abajo, hay una opción que dice Adjuntos y otras opciones. Haz click en el + y podrás adjuntarlo.
Ahora entiendo bastante, pero me pierdo.Así es León, recupero el valor de porta que esta en filas, y recupero el valor de rb4-rb7 que está en columnas, hago operaciones para convertirlo en el valor de la tecla que se presionó y lo muestro al display.
Dame un tiempo considerable, ya que debo simularlo para ver que está pasando.
Me da la impresión que; cuando lees el puerto a, que lo tienes como salida, recuperas el valor de lo que entrega este puerto. Como lo hace a 4mhz los cambios son muy rápidos, y en 1 segundo, el puerto cambió muchas veces. También, al tener RA4 como entrada, y al aire, está entrando mucho ruido. Pero es una teoría.
No obstante, tu programa para escanear un puerto y mostrarlo en un código BCD es muy complicado. En la red hay muchísimos programas ya escrito que hacen esto.
Tienes razon que en 1 segundo mientras se presiona una tecla seguro se llevan a acabo varias interrupciones, pero todas deberían mostrar el mismo resultado ya que se está presionando la misma tecla.
En la imagen que subiste no se ven resistencias de pulldown en RB4..7Hola Eduardo, si llevan resistencias pulldown, por eso esque hago rotar un 1
En lugar de confiar en que la electrostatica va a estar a tu favor, agregalas o activá las resistencias de pullup del puerto.
Esto último es mas "correcto" pero es mas trabajo porque hay que reescribir el escaneo desplazando un 0 e invirtiendo la lógica de lectura.
Algo mas ismple para leer el teclado:hola Killer, gracias por el code, lo voy a probar.
No esta probado el codigo, pero es mas cortoCódigo: ASM
CLRF PORTA BSF STATUS, C LOOPLEER: RLF PORTA, F BTFSC PORTA, 4 GOTO NO_BOTON MOVLW 0xF0 ANDWF PORTB, W BTFSS STATUS, Z GOTO LOOPLEER ;Esta todo en 0, nada presionado MOVF PORTA, W ;Si llego aca algo presionado hay ANDLW 0xF MOVWF BOTONES MOVF PORTB, W ANDLW 0xF0 MOVWF BOTONES ;Quedaria PORTB:PORTA ;SWAPF BOTONES, F CLRF PORTA RETURN NO_BOTON CLRF PORTA CLRF BOTONES RETURNCitarTienes razon que en 1 segundo mientras se presiona una tecla seguro se llevan a acabo varias interrupciones, pero todas deberían mostrar el mismo resultado ya que se está presionando la misma tecla.
Si estas usando la interrupcion de RB4-7, estos se activan por cambio de nivel, es decir cuando pasan de 0 a 1, o de 1 a 0. Por lo cual al tener presionado 1 sola tecla, entraria dos veces.
Cuando lo detecta el 1 (ya que activaste esa fila) o el 0 cuando cambiaste de fila o soltaste. Por lo que no creo que sea lo correcto usar este tipo de interrupcion para un teclado. Es mas rapido leerlo directamente, y luego si queres que se lea mas lento o no se repita podes hacerlo bajo interrupcion de un timer (mas lento) o comprobar que no es la misma tecla y esperar que se suelte (no se repita)
pero todas deberian arrojar el mismo resultado mientres presione la misma tecla
Una pregunta, cuando ocurre una interrupcion, acaso no se detiene todo para atender lo que este dentro de la interrupcion?Citarpero todas deberian arrojar el mismo resultado mientres presione la misma tecla
A eso voy que es erroneo lo que planteas... Ya que para leer el teclado haces un barrido... Voy a intentar ser mas claro con un ejemplo.
Supongamos que tenes presionado la tecla 7 (para hacerlo mas corto)
Estados iniciales-> PORTA=0 , PORTB = 0 (solo la parte alta que es del teclado voy a escribir)
Iniciamos el barrido hacemos PORTA = 0001 (RA0 - Primera fila) PORTB = 0001 (RB4 - primera columna)
Se dispara la interrupcion y obtenes tu tecla.
Aca puede suceder varias cosas segun tu programa y/o lo que suceda primero:
- Si seguis con el barrido del teclado:
PORTA = 0010 PORTB = 0000 , Se dispara de nuevo la interrupcion. No tengo el mismo valor que antes.
- No seguis con el barrido y se suelta el boton:
PORTA = 0001 PORTB = 0000, Se dispara de nuevo la interrupcion. Tampoco tengo el mismo valor que antes.
- No seguis con el barrido y reinicias el PORTA:
PORTA = 0000 PORTB = 0000, Se dispara de nuevo la interrupcion. Tampoco tengo el mismo valor que antes.
- No seguis con el barrido y se presiona el 8,9 o el %
PORTA = 0001 PORTB = 0101, Se dispara la interrupcion. Tampoco tengo el mismo valor que antes.
osea si ocurre una interrupcion el codigo que hace el barrido se detendra y se ejecutara lo que esta dentro de la interrupcion, una vez terminado(obtengo mi resultado en display) se vuelve con lo del barrido, y si aun tengo la misma tecla presionada(cosa que si, porq el barrido ocurre en micro segundos o milisegundos) vuelve a ejecutar la misma interrupcion y vuelvo a obtener el mismo resultado en display