TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: JoseLuis2801 en 12 de Mayo de 2014, 18:22:51
-
Hola a todos, pues resulta que me hace todo tal y como indica el programa, osea 1º se queda en intermitencia rapida infinitamente , (tengo conectado un led a la patita 2 del portC), y hasta que pulso el interruptor asociado al bit 2 del puerto A.
;;; CLK 4 MHz
w EQU 0h
f EQU 1h
LIST P=16F1503
INCLUDE <P16F1503.INC>
;;;;; 4 Mhz
CONT EQU 20H
CONTMAX EQU 21H
CONTMIN EQU 23H
RET1 EQU 25H
RET2 EQU 26H
RET3 EQU 27H
INDI EQU 28H
ORG 00H
GOTO INICIALIZACION
ORG 04H
GOTO ISR
;;;;;;; INICIALIZACION PORT C
;;;;;;;; Y PORTA
INICIALIZACION NOP
BANKSEL OSCCON ;; RELOJ A 4MHZ
MOVLW 6AH
MOVWF OSCCON
BANKSEL PORTA
CLRF PORTA
BANKSEL LATA
CLRF LATA
BANKSEL ANSELA ; Puerto A
CLRF ANSELA
BANKSEL TRISA
MOVLW 0Ch
MOVWF TRISA
BANKSEL PORTC
CLRF PORTC
BANKSEL LATC
CLRF LATC
BANKSEL ANSELC ; Puerto C SIN RES. POL.
CLRF ANSELC
BANKSEL TRISC
MOVLW 02h
MOVWF TRISC
banksel OPTION_REG
CLRF OPTION_REG
movlw 0x07
movwf OPTION_REG
BANKSEL WPUA
MOVLW 0Ch
MOVWF WPUA ;ACTIVADA, BIT 2, 3
BANKSEL INTCON ; Rut. servicio interrupciones
CLRF INTCON
MOVLW 0X88
MOVWF INTCON ;PONER A 1 GIE e IOCIE
BANKSEL IOCAN
CLRF IOCAN
BSF IOCAN,2 ; a 1 IOCAN2
BANKSEL PORTC
INT.RAPIDA NOP
BSF PORTC,2
CALL DEMORA406 ;;; RUTINA INTERMITENCIA
BCF PORTC,2 ;;;;; RAPIDA
CALL DEMORA406
GOTO INT.RAPIDA
ISR BSF PORTC,2
CALL DEMORA406 ;;; RUTINA INTERMITENCIA
CALL DEMORA406 ;;; LENTA
CALL DEMORA406
BCF PORTC,2
CALL DEMORA406
CALL DEMORA406
CALL DEMORA406
BSF PORTC,2
CALL DEMORA406
CALL DEMORA406
CALL DEMORA406
BCF PORTC,2
RETORNAR NOP
BANKSEL INTCON ; Rut. servicio interrupciones
MOVLW 0X08
MOVWF INTCON ;PONER A 1 IOCIE
BANKSEL IOCAN
BSF IOCAN,2 ; a 1 IOCAN2
BANKSEL IOCAF
BCF IOCAF,2 ; BORRA FLAG
RETFIE
DEMORA406 MOVLW 10h ; CARGA VARIABLES DEMORA
MOVWF RET1
MOVLW 0h
MOVWF RET2
MOVLW 03H
MOVWF RET3
DEC2 DECFSZ RET2 ; RETARDO DE 406 ms
GOTO DEC2
DECFSZ RET1 ;
GOTO DEC2
DECFSZ RET3 ; 3 BUCLES
GOTO DEC2
RETURN
FIN NOP
END
En ese momento, se genera la interrupción , y entra en la rutina de interrupciones ISR, y hace la intermitencia lenta, pero no vuelve a la rutina de int. rapida, sino que, hace el 1,2seg ON, 1,2seg. OFF, 1,2 seg. ON, y se queda apagado.
La verdad no se que me falta poner para que retorne correctamente a la rapida.
Muchas gracias
un saludo
-
Hace mucho que no programo; pero por lo poco que lo estudié, te falta restaurar ciertos valores que; previamente, tendrías que haber guardado al momento de entrar a una interrupción.
Buscando en mis programas de asm; encontré un "trabajo" que se hace cuando se entra a la interrupción; y antes de salir de la interrupción.
Es para un micro 16F877:
MOVWF SALVAR_W ;SALVA EL CONTENIDO DE W
SWAPF STATUS,W ;PASAMOS A W STATUS (ES CON SWAPF PARA NO AFECTAR EL BIT Z)
MOVWF SALVAR_STATUS ;SALVA EL CONTENIDO DE STATUS
SWAPF FSR,W ;PASAMOS A W FSR
MOVWF SALVAR_FSR ;SALVA FSR
SWAPF PCLATH,W ;PASAMOS A W PCLATH (Pagina de programa)
MOVWF SALVAR_PCLATH ;SALVA EL CONTENIDO DE PCLATH
BCF STATUS,RP1
BSF STATUS,RP0 ;BANCO 1
SWAPF OPTION_REG,W ;PASAMOS A W OPTION_REG (Bancos)
MOVWF SALVAR_OPTION_REG ;SALVA EL CONTENIDO DE OPTION_REG
BCF STATUS,RP0 ;BANCO 0
BTFSC PIR1,RCIF ;¿SE ACTIVÓ RECEPCIÓN USART?
GOTO RX_USART
BTFSS INTCON,T0IF ;¿HUBO DESBORDE EL TIMER?
GOTO SALIR ;FALSA INTERRUPCIÓN
SALIR BSF STATUS,RP0 ;BANCO 1
SWAPF SALVAR_OPTION_REG,W ;RESTAURA EL VALOR A OPTION_REG
MOVWF OPTION_REG
SWAPF SALVAR_PCLATH,W ;RESTAURA EL VALOR A PCLATH
MOVWF PCLATH
SWAPF SALVAR_FSR,W ;RESTAURA EL VALOR A FSR
MOVWF FSR
SWAPF SALVAR_STATUS,W ;RESTAURA EL VALOR A STATUS
MOVWF STATUS
SWAPF SALVAR_W,F
SWAPF SALVAR_W,W ;RESTAURA EL VALOR A W
BCF PORTC,0 ;APAGAMOS EL LED DE RECEPCIÓN
RETFIE
Presta atención, que primero guardo algunos datos importantes; luego me fijo si lo que tendría que haber producido la interrupción, fue así (en mi caso, son varios; pero verás que uno es interrupción del TMR0)
Cuando termino de hacer lo necesario en la interrupción, restauro todo lo que salvé anteriormente; y luego salgo.
Ahora quiero ir más a tu problema. Cada vez que sale de la interrupción, ¿siempre va al mismo punto; o es aleatorio? Si es aleatorio, al no estar salvando el valor del PCLATH, hace que retorne en cualquier lugar.
¿Lo estás simulando o directamente haces la prueba en placa real?
-
Gracias, seguro que es algo de eso que comentas, pero es que como indica esto en el datasheet, en el apartado de las interrupciones :
7.5 Automatic Context Saving
Upon entering an interrupt, the return PC address is
saved on the stack. Additionally, the following registers
are automatically saved in the shadow registers:
• W register
• STATUS register (except for TO and PD)
• BSR register
• FSR registers
• PCLATH register
Upon exiting the Interrupt Service Routine, these registers
are automatically restored. Any modifications to
these registers during the ISR will be lost. If modifications
to any of these registers are desired, the corresponding
shadow register should be modified and the
value will be restored when exiting the ISR. The
shadow registers are available in Bank 31 and are
readable and writable. Depending on the user’s application,
other registers may also need to be saved.
Claro a algún lado retorna pero teoricamente deberia ser a cualquier punto de la rutina INT.RAPIDA, que por otra parte, tiene llamada a la subrutina demora406, con lo cual cuando se produjese la interrupcion, que es cuando pulso el microSWitch, pudiese estar ejecutando los bucles la subrutina406, que ademas seria lo mas normal, pienso, y quizas venga de ahi todo el follón del retorno.
Bueno mañana lo estudio todo mejor, y voy salvado tal y como me indicas, registros.
Directamente en placa lo grabo y lo ejecuto.
Y otra cosa que si que ni idea de XQ, al cabo de unos 55 seg., es como si se resetease el PIC, y vuelve a la intermitencia rapida. Por supuesto yo no hago absolutamente nada.
-
El PIC16F1503, al igual que muchos nuevos de la familia 16F lanzados por Microchip, guardan automáticamente y restauran los registros clave. Por lo tanto el problema no es ese.
La rutina de interrupción suele estar pensada para procesar información rápidamente, no para generar demoras o procesos lentos. Te recomiendo que setees banderas (flags) dentro de la interrupción y las revises y ejecutes acorde en el loop principal, porque por estar haciendo procesos lentos dentro de la ISR, te debés estar perdiendo nuevos eventos que deberían interrumpir.
Saludos
-
OK BunoF, XQ con tantas demoras se puede poner a 0 el flag ?
Bueno, como ahora mismo lo único que quiero es ver si lo he hecho bien o no el proceso, voy a utilizar otra patita de salida, y simplemente en la RSI voy a poner un BSF para activar un led y ya esta, seteo flag y vuelvo con el RETFIE.
Os cuento............
-
Pues acabo de poner un solo BSF y efectivamente si me vuelve a la rutina de intermitencia lenta.
Posteriormente, acabo de incluir un solo call demora406, y ya no me retorna.
Pero claro, no sabemos si es mucho tiempo como decias brunoF, o que se empana la saltar a demora406 dentro de la rutina ISR.
Idea, pongo el bucle dentro de la misma ISR, y a ver que pasa.
Os cuento............
-
Vale tengo progresos, como dije he conectado otro led rojo a la patita bit 4 del puerto A.
Led portA es rojo
Led portC es verde.
Pues bien, he incluido la rutina de 406ms dentro de la ISR, y nada, he bajado el tiempo, y nada , he bajado hasta solo 7 microsegundos, se sigue empanando, se queda bloqueado en la propia rutina ya que el led rojo se queda encendido, y el verde se queda en el estado uqe este cuando yo pulso el microSw de la placa, el asociado al bit 2 del portA. (ver archivo adjunto).
INT.RAPIDA NOP
BSF PORTC,2
CALL DEMORA406 ;;; RUTINA INTERMITENCIA
BCF PORTC,2 ;;;;; RAPIDA
CALL DEMORA406
GOTO INT.RAPIDA
ISR BSF PORTA,4 ; ENCIENDO LED DE LA RUTINA
; DE LA INTERRUPCION
MOVLW 2h ; CARGA VARIABLES DEMORA
MOVWF RET1 SE BLOQUEA
DEC22 DECFSZ RET1 ; RETARDO DE 7 us
GOTO DEC22
RETORNAR NOP
BANKSEL INTCON ; Rut. servicio interrupciones
MOVLW 0X88
MOVWF INTCON ;PONER A 1 IOCIE
BANKSEL IOCAN
BSF IOCAN,2 ; a 1 IOCAN2
BANKSEL IOCAF
BCF IOCAF,2 ; BORRA FLAG
RETFIE
Luego cambio ese pequeño bucle por 7 NOPs que abarcan el mismo tiempo, y , se enciende un brevisimo instante el led, y sale de la rutina ISR , ASI QEU RETORNA CORRECTAMENTE y continua con el flash rapido indefinidamente.
ISR BSF PORTA,4 ; ENCIENDO LED DE LA RUTINA
; DE LA INTERRUPCION
NOP
NOP
NOP
NOP
NOP
NOP
NOP
RETORNAR NOP
BANKSEL INTCON ; Rut. servicio interrupciones
MOVLW 0X88
MOVWF INTCON ;PONER A 1 IOCIE
BANKSEL IOCAN
BSF IOCAN,2 ; a 1 IOCAN2
BANKSEL IOCAF
BCF IOCAF,2 ; BORRA FLAG
RETFIE
Entonces, no es por el tiempo sino que algo hay en el bucle que no le gusta a la rutina ISR.
Otra cosa es que si el tiempo es grande se dejen de atender otros eventos al estar el bit GIE a 1, eso por supuesto.
-
Hola,
grave complicación rehabilitar las interrupciones dentro de la interrupción. Sólo deberías limpiar el flag. Las Inter no se desconfiguran por ingresar a la isr.
-
OK BrunoF, reseteare solo el flag.
...........
-
Vale por fin, he quitado lo que me has dicho y solo he dejado el seteo del flag, y un perfecto, lo que antes no funcionaba con el bucle de 7us. ahora si lo hace, es más lo hace perfecto, XQ ahora si vuelve y ademas se queda encendido el led rojo, como debia ser. Esta noche os pongo el emlace a un video.
Por otra parte , una vez esto correcto, voy con las demoras, y he aumentado el tiempo al max. con un bucle, y sigue funcionando perfectamente.
INT.RAPIDA NOP
BSF PORTC,2
CALL DEMORA406 ;;; RUTINA INTERMITENCIA
BCF PORTC,2 ;;;;; RAPIDA
CALL DEMORA406
GOTO INT.RAPIDA
ISR BSF PORTA,4 ; ENCIENDO LED DE LA RUTINA
; DE LA INTERRUPCION
MOVLW 0x0 ; CARGA VARIABLES DEMORA
MOVWF RET1
DEC22 DECFSZ RET1 ; RETARDO DE 769 us
GOTO DEC22
RETORNAR NOP
BANKSEL IOCAF
BCF IOCAF,2 ; BORRA FLAG
RETFIE
Pero si pongo la demora de 406ms., (no la llamo), se bloquea en la rutina de ISR. Asi que me queda ver si por anidar bucles, o por el tiempo como un valor absoluto, si es éste último, descubriré el limite, ya puestos, o ámbos.............
Muchisimas gracias a los dos, SOLUCIONADO. :-/
-
Hola,
me alegra poder ayudar.
En cuanto al supuesto bloqueo de la ISR al llamar a la subrutina DEMORA406, creo que lo que está sucediendo no es que se bloquee, es que estás compartiendo las variables que generan la demora, y eso es un problema.
Piensa que cuando se produce la ISR, la posibilidad de que el CPU se encuentre ejecutando la demora de 406mS es altísima, lo que también significa que los valores de RET1, RET2 y RET3 ya fueron establecidos por única vez al ingresar a la subrutina y están decrementandose. Ahora, cuando se produce la ISR, tu vuelves a llamar a DEMORA406, lo que sobreescribe los valores previos de RET1, RET2 y RET3, y no sólo eso, sino que al terminar de ejecutarse, deja las tres variables con valor 0x00, ese 0x00 en las 3 variables, hará que a retornar de la subrutina, el CPU retome desde donde había dejado antes de interrumpir (la demora406) y genere que la demora sea ENORME, debido especialmente al 0x00 de RET3, que requerirá de 256 decrementos antes de poder escapar a la subrutina de demora, siempre y cuando no presiones el pulsador nuevamente, y tenga que volver a contar 256 ciclos largos más.
Espero haber explicado el comportamiento del algoritmo. Si deseas reutilizar la demora fuera y dentro de la ISR, vas a tener que pensar en una solución: una puede ser resguardando manualmente los valores de los registros RET1, RET2 y RET3 al ingresar a la ISR, y restaurarlos antes de salir.
Saludos.
-
Si entendido, y eso explicaría que saliese a los 55 seg. aprox.
Ok OK, te cojo la idea. No de esa forma, pero si tengo que utilizar esas demoras de 406ms.
Y el video, para terminar:
En el seg. 19 pulso el microswitch de la placa, luego lo pulso mas veces por si ocurre algo raro, pero va a ser que no.
Q bien verlo funcionar como debe. :P
Bueno otra preguntilla, para que sirve LatC o LatA ? pero un ejemplo practico por favor para que asi yo me entere bien de su utilidad .
Infinitas gracias
;-)
-
BIEN :-/ :-/
He puesto 4 rutinas de 406ms. se van ejecutando sucesivamente, dentro de la ISR, cambiando los nombres a las variables y etiquetas claro. Bueno, las variables solo he definido 3 mas , asi qeu las 4 demoras incluidas, contienen la misma, RET11, RET22, y RET33.
Y funciona perfecto, no era el valor absoluto del tiempo, sino que se lia al utilizar las mismas como dijistes brunoF.
Es que en mi aplicación, la ISR dura bastante, y como no hay ningún otro recurso que atender, el watchdog lo tengo desactivado.
Bueno, pues ya está todo, infinitas gracias, he aprendido mucho sobre el tema éste de las interrupciones.
Un saludo.
-
Ya por último, he puesto la subrutina de la demora 406ms, fuera de la ISR, y la he ejecutado 14 veces dentro de la ISR, y sin problema alguno, funciona perfectamente.
INT.RAPIDA NOP
BSF PORTC,2
CALL DEMORA406 ;;; RUTINA INTERMITENCIA
BCF PORTC,2 ;;;;; RAPIDA
CALL DEMORA406
GOTO INT.RAPIDA
ISR BSF PORTA,4 ; ENCIENDO LED DE LA RUTINA
; DE LA INTERRUPCION
MOVLW 0x0 ; CARGA VARIABLES DEMORA
MOVWF RET1
DEC222 DECFSZ RET1 ; RETARDO DE 769 us
GOTO DEC222
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
CALL DEMORA406A
BCF PORTA,4 ;; APAGO LED DE LA RUTINA
RETORNAR NOP
BANKSEL IOCAF
BCF IOCAF,2 ; BORRA FLAG
RETFIE