Autor Tema: Desesperado con las interrupciones.  (Leído 2570 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Fulguitron

  • PIC16
  • ***
  • Mensajes: 122
    • Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.
Desesperado con las interrupciones.
« en: 01 de Enero de 2015, 14:02:56 »
Ante todo, Feliz año a todos. Pero año nuevo ... porque no se solucionan los problemas? el caso es que este año me he decidido finalmente entender las interrupciones (propósitos para este año, entre otros) porque estoy pensado en hacerme un reloj "sencillo" binario.
Ahora mismo me conformo con crear que un número incremente su valor y que cuando pulse el valor lo pueda ver, pero el dato siga incrementándose. Lo podría hacer sin interrupciones pero quiero empezar con algo simple e ir complicándolo poco a poco.

Código: [Seleccionar]
;---------------Encabezado-------------
LIST P=16F84A
INCLUDE <P16F84A.INC>

CBLOCK 0x0C
ContA
ENDC
;-------Configuración de puertos-------

ORG 0x00               
GOTO inicio
ORG 0x04         
GOTO ISR
ORG 0X05

inicio
BSF STATUS,RP0       ; configurando puertos
clrf TRISB
MOVLW b'11111111'          ; carga w con 0000 0001
MOVWF TRISA          ; RB0/INT es entrada
BCF OPTION_REG,6  ; seleccionamos flanco descendente
BCF STATUS,RP0

;-------Habilitación de interrupciones-------

BSF INTCON,GIE      ; habilitamos todas las interrupciones
BSF INTCON,INTE     ; que sean interrupciones externas
CLRF PORTB         ; limpio el puerto B

movlw d'1' ; Primer número por donde quieres que empiece el conteo.
movwf ContA ; Guarda el valor de W a F

Pulsador
btfsc PORTA,4 ; Botón pulsado.
goto Pulsador ; si no está pulsado vuelve a Pulsador
movf ContA,W ; Si esta pulsado? pasa ContA a W
movwf PORTB ; muestra el resultado por PORTB.
call Retardo_500ms
clrf PORTB
goto Pulsador

;-------------Rutina de servicio de interrupciones-------------

ISR
incf ContA ;incrementa en 1 los segundos
movf ContA,W
call Retardo_500ms
BCF INTCON,INTF     ; borro bandera de interrupción
RETFIE

INCLUDE <RETARDOS.INC>
END

Por supuesto, este programa solo muestra un "uno binario", pero en ningún momento incremente, porque???? si no consigo este propósito este año, para el otro me pongo a fumar y dejo ade hacer ejercicio.

PD: no me reenviéis al curso de asm del foro, que tampoco acabo de hacerme la idea, tengo las interrupciones atravesadas y estoy más que ofuscado.
Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.

http://hobbiesygadgets.blogspot.com.es/

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Desesperado con las interrupciones.
« Respuesta #1 en: 01 de Enero de 2015, 14:23:27 »
Tenes unos cuantos problemas xD

Primero que nada tenes que saber que cosas poseen interrupciones y que no. Las interrupciones son:

RB0 ( por flanco , lo cual lo hace ideal para un boton )
RB4/RB7 por nivel (lo cual para botones tenes que implementar algo mas )
TMR0 cuando se desborda el TMR0
Mas una de la  EEPROM, pero esa la dejamos..

Si fuera usar interrupciones, entonces pondria mi boton en RB0 y no en RA4, como lo tenes. De esa forma ante un flanco ascendente cambio (de 0 A 1) entraria en mi interrupcion. Como lo tenes configurado como salida no se si funciona la interrupcion, pero si supongo que funciona igual ( y veo que lo configuraste en flanco descendente ) deberias poner primero a 1 y luego a 0 el portb para que entre a la interrupcion, esto haria que incremente poniendo nuevamente a 1 y teniendo que volverlo a 0. Aunque la finalidad es para usarlo como una entrada.

Código: [Seleccionar]
clrf TRISB
MOVLW b'11111111'         ; carga w con 0000 0001
MOVWF TRISA         ; RB0/INT es entrada

Obviamente las instrucciones no corresponden tampoco con los comentarios, tal ves lo hiciste primero de una forma y luego lo cambiaste.

Creo que esto seria vital para que comienzes con las interrupciones, el resto del programa esta bien, lo que si en el vector de interrupcion guardaria todo el contexto ( STATUS y W ) en el datasheet esta como hacerlo:

Código: [Seleccionar]
PUSH MOVWF W_TEMP ; Copy W to TEMP register,
     SWAPF STATUS, W ; Swap status to be saved into W
     MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register
     ;
     ;
     ; Aca tu rutina de interrupcion
     ;
     ;
     ;
POP SWAPF STATUS_TEMP,W ; Swap nibbles in STATUS_TEMP register
     ; and place result into W
     MOVWF STATUS ; Move W into STATUS register
     ; (sets bank to original state)
     SWAPF W_TEMP, F ; Swap nibbles in W_TEMP and place result in W_TEMP
     SWAPF W_TEMP, W ; Swap nibbles in W_TEMP and place result into W
     RETFIE

Usa 2 variables W_TEMP y STATUS_TEMP que vas a tener que definir, esto por que al interumpir el flujo del programa y luego volver al mismo punto, estos registros deberian tener el mismo valor. Un ejemplo seria que ocurra algo asi:

INCF variable1
; Interrupcion aca
BTFSS STATUS,Z

Si ocurre eso sin salvar el contexto en la interrupcion, y si llegas a hacer una operacion en la rutina de interrupcion que modifique W o algun bit de STATUS y luego volver, tanto W como STATUS van a corresponder a esa suma y no al INCF. Lo que el programa va a hacer algo que no debe.

Para terminar xD, arregla el tema de los puertos cual vas a usar para poder usar la interrupcion o tambien podrias hacer uso del TMR0 y que genere una interrupcion cada X segundos asi prendes un led ( sin usar un retardo )
« Última modificación: 01 de Enero de 2015, 14:38:44 por KILLERJC »

Desconectado Fulguitron

  • PIC16
  • ***
  • Mensajes: 122
    • Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.
Re: Desesperado con las interrupciones.
« Respuesta #2 en: 03 de Enero de 2015, 13:40:37 »
A ver si me he enterado de algo, (de algo creo que si, pero de momento sigue sin funcionar). Primero, he cambiado por el 16F628, ya que tenía que cambiar el PORTB por el PORTA y a la larga quiería usar el 16F628 (más puertos, más salidas y más barato,...) con lo cual uso el PORTB,0 como interruptor para la interrupción.
He creado en el CP los diferentes registros que usar para guardar los datos antes de la interrupción.

Código: [Seleccionar]
CBLOCK 0x0C
Guarda_W
Guarda_Status
Guarda_Cont_A
Cont_A
ENDC

Y ahora viene el follón, he creado dos rutinas para guardar y reponer los datos antes y después de la interrupción, pero no sé donde ubicarlos en el código.
Antes de la interrupción, lo guardo todo con ...
Código: [Seleccionar]
movwf Guarda_W
swapf STATUS,W
movwf Guarda_Status
movf Cont_A,W
movwf Guarda_Cont_A

.... y antes que acabe la interrrupción lo recupero todo con ....

Código: [Seleccionar]
movf Guarda_Cont_A,W
movwf Cont_A
swapf Guarda_Status,W
movwf STATUS
swapf Guarda_W,F
swapf Guarda_W,W

BCF INTCON,INTF     ; borro bandera de interrupción
RETFIE

Y por último el código completo por si alguien quiee ayudarme o echarse unas risas ...

Código: [Seleccionar]
;---------------Encabezado-------------
LIST P=16F628A
INCLUDE <P16F628A.INC>

CBLOCK 0x0C
Guarda_W
Guarda_Status
Guarda_Cont_A
Cont_A
ENDC
;-------Configuración de puertos-------

ORG 0x00               
GOTO inicio
ORG 0x04         
GOTO ISR
ORG 0X05

inicio
BSF STATUS,RP0       ; configurando puertos
clrf TRISA
MOVLW b'11111111'      
MOVWF TRISB          
BCF OPTION_REG,6  ; seleccionamos flanco descendente
BCF STATUS,RP0

;-------Habilitación de interrupciones-------

BSF INTCON,GIE      ; habilitamos todas las interrupciones
BSF INTCON,INTE     ; que sean interrupciones externas
CLRF PORTA         ; limpio el puerto B

movlw d'1' ; Primer número por donde quieres que empiece el conteo.
movwf Cont_A ; Guarda el valor de W a F

; --------------Guardamos los registros antes de la interrupción ----------------------

movwf Guarda_W
swapf STATUS,W
movwf Guarda_Status
movf Cont_A,W
movwf Guarda_Cont_A

Pulsador
btfsc PORTB,0 ; Botón pulsado.
goto Pulsador ; si no está pulsado vuelve a Pulsador
movf Cont_A,W ; Si esta pulsado? pasa ContA a W
movwf PORTA ; muestra el resultado por PORTB.
call Retardo_500ms
clrf PORTA
goto Pulsador

;-------------Rutina de servicio de interrupciones-------------

ISR
incf Cont_A ;incrementa en 1 los segundos
movf Cont_A,W
call Retardo_500ms
; ---------------------- antes de acabar la interrupción ponemos todos los registros como antes.
movf Guarda_Cont_A,W
movwf Cont_A
swapf Guarda_Status,W
movwf STATUS
swapf Guarda_W,F
swapf Guarda_W,W

BCF INTCON,INTF     ; borro bandera de interrupción
RETFIE

INCLUDE <RETARDOS.INC>
END

De momento lo del TMR0 lo tengo en cuenta (porque creo que para hacer un reloj parece más factible) pero no quiero liar más el código, primero entender esto sencillo y luego ya me liaré.

Muchas gracias KILLERJC.
Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.

http://hobbiesygadgets.blogspot.com.es/

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Desesperado con las interrupciones.
« Respuesta #3 en: 08 de Enero de 2015, 19:24:19 »
Perdon por la demora, se me paso por el alto con algun otro mensaje lo mas seguro..

Citar
CBLOCK   0x0C
   Guarda_W
   Guarda_Status
   Guarda_Cont_A
   Cont_A
   ENDC

Fijate que en el 16f628 los registros de proposito general GPR, empiezan en 0x20 y no en 0x0C, lo cual estarias escribiendo sobre los registros
PIR1 , TMR1L, TMR1H


Citar
; --------------Guardamos los registros antes de la interrupción ----------------------

   movwf   Guarda_W
   swapf   STATUS,W
   movwf   Guarda_Status
   movf   Cont_A,W
   movwf   Guarda_Cont_A

Lo que quotee ( es decir lo que guarda el registro status Y deberia guardar el registro W, deberia estar dentro de la rutina de interrupcion), utiliza el codigo que te pase que proviene del datasheet y funciona como debe. La interrupcion deberia quedarte:

Guardo W
Guardo Status
Borro flag // Si es muy largo lo cual no deberia, deberia tambien desactivar la interrupcion
Hago lo que tengo que hacer
// habilitaria la interrupcion aca si es que la desactivo
Devuelvo Status
Devuelvo W
Vuelvo de interrupcion

Tambien no deberias de guardar/salvar el valor de Cont_A ya que este esta guardado de por si, comenzaria en 1, y solo incrementaria si pasa por la interrupcion que es lo que deberia. Solo se guarda W y STATUS para que el programa siga como estaba.

Otra cosa, no se si es lo que ideaste vos, por el momento incrementaria el valor de Cont_A solo cuando entra a la interrupcion, pero mienrtas este presionado estaria poniendo el valor de PORTA al valor y borrandolo continuamente:

Citar
Pulsador   
   btfsc   PORTB,0         ; Botón pulsado.
   goto   Pulsador      ; si no está pulsado vuelve a Pulsador
   movf   Cont_A,W         ; Si esta pulsado? pasa ContA a W
   movwf   PORTA         ; muestra el resultado por PORTB.
   call   Retardo_500ms
   clrf   PORTA   
   goto   Pulsador

Lo que podrias hacer es setear una bandera, es decir un bit de alguna variable que crees y preguntar por ese bit, eso te va a indicar que entro a la interrupcion. Ejemplo digamos que creo una variable FLAGS , y selecciono el bit 0 como el flag de interrupcion, entonces cuando entre a la interrupcion hago BSF FLAGS,0 , luego en el programa principal reemplazo el BTFSC PORTB,0 por BTFSS FLAGS,0  y antes del GOTO pulsador pongo un BCF FLAGS,0. Esto si lo seteas una sola ves.

Te faltaria tambien definir los fuses.
Tenes que recordar que RA5 es entrada unicamente. RA6/RA7 si usas cristal estan ocupados con OSC1/OSC2.


Desconectado Fulguitron

  • PIC16
  • ***
  • Mensajes: 122
    • Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.
Re: Desesperado con las interrupciones.
« Respuesta #4 en: 04 de Junio de 2015, 14:57:06 »
Pues ya estamos otra vez aquí, sigo con mis interrupciones que ahora ya es necesario aprender si quiero avanzar con mis programas (bueno y porque ya me toca). En este caso quiero que al apretar un botón se muestre un led parpadeando durante un segundo. Sin la interrupción el programa va OK, pero con la interrupción me salen estos fallos.

Error[118]   E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 20 : Overwriting previous address contents (0005)
Error[118]   E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 20 : Overwriting previous address contents (0005)
Message[302] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 21 : Register in operand not in bank 0.  Ensure that bank bits are correct.
Message[302] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 23 : Register in operand not in bank 0.  Ensure that bank bits are correct.
Message[305] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 75 : Using default destination of 1 (file).
Message[305] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 79 : Using default destination of 1 (file).
Halting build on first failure as requested.

Supongo que el problema es que uso el mismo TMR0 para dos cosas, pero no se como usar otro (si se puede) una ayudita??? como siempre el código completo

Código: [Seleccionar]
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT & _DATA_CP_OFF & _LVP_OFF & _MCLRE_OFF
LIST    P=16F628A
INCLUDE  <P16F628A.INC>

CBLOCK  0x20
contador
pulsador
ENDC

#DEFINE Salida PORTB,3 ; Puerto donde se conecta los diodos LED.
#DEFINE Un_segundo_carga -d'39'
; ZONA DE CÓDIGOS ********************************************************************

ORG 0x05 ; El programa comienza en la dirección 0.
goto Inicio
org 4
goto Boton_int

Inicio
bsf STATUS,RP0 ; Acceso al Banco 1.
clrf TRISB
movlw b'00000111'
movwf OPTION_REG
movwf CMCON
bcf STATUS,RP0 ; Acceso al Banco 0.
clrf PORTB
movlw b'10100000'
movwf INTCON

Memoria
movlw d'10'
movwf contador
movlw d'2'
movwf pulsador

Probar
movf pulsador,W
sublw d'2'
btfss STATUS,Z ; revisa si activar_display_1 ha llegado al límite superior, si no es asó salta una línea y sigue el conteo.
goto Principal
movf pulsador,W
sublw d'3'
btfss STATUS,Z ; revisa si activar_display_1 ha llegado al límite superior, si no es asó salta una línea y sigue el conteo.
goto Un_segundo

Principal
movlw d'100'
movwf contador
bsf Salida
call Un_segundo
movlw d'100'
movwf contador
bcf Salida
call Un_segundo
goto Inicio

Un_segundo
movlw Un_segundo_carga
movwf TMR0
bcf INTCON,T0IF

Timer0_Rebosamiento
btfss INTCON,T0IF
goto Timer0_Rebosamiento
decfsz contador,1
goto Un_segundo
RETURN

Boton_int
btfsc Salida
goto Principal_int
goto Un_segundo_int

Principal_int
incf pulsador
bcf INTCON,T0IF
retfie
Un_segundo_int
decf pulsador
bcf INTCON,T0IF
retfie

END
Disfruta de mi blog, hobbies y gadgets diferentes y poco comunes.

http://hobbiesygadgets.blogspot.com.es/

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Desesperado con las interrupciones.
« Respuesta #5 en: 04 de Junio de 2015, 15:23:08 »
Posteo ahora el tema de los errores/warnings y cuando tenga mas tiempo veo bien el programa


Citar
Error[118]   E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 20 : Overwriting previous address contents (0005)
Error[118]   E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 20 : Overwriting previous address contents (0005)

debido a:

Código: ASM
  1. ORG             0x05                    ; El programa comienza en la dirección 0.
  2.         goto    Inicio
  3.         org             4
  4.         goto    Boton_int

Los goto ocupan 2 posiciones de memoria. es decir si tenes un ORG 0x04 y pones un GOTO; este ocuparia el 0x04 y el 0x05
 Vos tenes mal los ORG. Cambia el primer ORG por 0x00, y se soluciona
Acordate que el vector de reset es en 0x00 y el de interrupcion en 0x04 en esa gama, es decir si se produce un reset comienza de 0x00, si hay una interrupcion se va a 0x04

Código: ASM
  1. ORG             0x00                    ; Vector de reset,
  2.         goto    Inicio
  3.         org             0x04                                ;Vector de interrupcion
  4.         goto    Boton_int


Apartir de aca son mensajes, que pueden ser relevantes o no.

Citar
Message[302] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 21 : Register in operand not in bank 0.  Ensure that bank bits are correct.
Message[302] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 23 : Register in operand not in bank 0.  Ensure that bank bits are correct.

Ese mensaje es solamente por que el compilador no sabe en que banco estas ubicado. si en ves de poner

Código: ASM
  1. bsf             STATUS,RP0              ; Acceso al Banco 1.
  2.         bcf             STATUS,RP0              ; Acceso al Banco 0.

usas

Código: ASM
  1. BANKSEL         TRISB           ; Acceso al Banco 1.
  2.         BANKSEL         PORTB           ; Acceso al Banco 0.

tal ves desaparesca el mensaje, es perfectamente valido en ambos casos,

Citar
Message[305] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 75 : Using default destination of 1 (file).
Message[305] E:\BINWATCH\PRUEBAS\UNSEGUNDO_PIC16F628_INT.ASM 79 : Using default destination of 1 (file).

Es por estas 2 instrucciones

Código: ASM
  1. incf    pulsador
  2.         decf    pulsador

esas instrucciones pueden ie a W o al mismo registro, al no escribirlas el compilador te avisa que van a ir al registro, la forma correcta seria:

Código: ASM
  1. incf    pulsador,f
  2.         decf    pulsador,f


Como dije luego veo el codigo
« Última modificación: 04 de Junio de 2015, 15:26:33 por KILLERJC »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Desesperado con las interrupciones.
« Respuesta #6 en: 04 de Junio de 2015, 18:45:19 »
Te dejo un codigo que puede que te sirva de guia:

Código: ASM
  1. __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT & _DATA_CP_OFF & _LVP_OFF & _MCLRE_OFF
  2.         LIST       P=16F628A
  3.         INCLUDE  <P16F628A.INC>
  4.  
  5.         CBLOCK  0x20
  6.         contador
  7.         STATUS_TEMP
  8.         W_TEMP
  9.         ENDC
  10.  
  11. #DEFINE Salida          PORTB,3         ; Puerto donde se conecta los diodos LED.
  12.  
  13.  
  14. ; ZONA DE CÓDIGOS ********************************************************************
  15.  
  16.         ORG     0x00                    ; El programa comienza en la dirección 0.
  17.         goto    Inicio
  18.         org     0x04
  19.         goto    Interrupcion
  20.  
  21. Inicio
  22.         bsf             STATUS,RP0              ; Acceso al Banco 1.
  23.         clrf    TRISB          
  24.         movlw   b'00000111'            
  25.         movwf   OPTION_REG
  26.         movwf   CMCON
  27.         bcf             STATUS,RP0              ; Acceso al Banco 0.
  28.         clrf    PORTB
  29.        
  30.         movlw   -d'39'                          ; Datos del TMR
  31.         movwf   TMR0
  32.         movlw   d'100'                 
  33.         movwf   contador
  34.  
  35.         movlw   b'10100000'
  36.         movwf   INTCON
  37.  
  38. Principal
  39.         GOTO    Principal                       ;Bucle infinito solo sale de aca con la interrupcion y vuelve al bucle
  40.  
  41.  
  42. Interrupcion
  43.  
  44.         MOVWF W_TEMP                            ;Guardo W y STATUS, a pesar que no los use en el bucle principal acostumbrarse a usarlo
  45.         SWAPF STATUS, W
  46.         MOVWF STATUS_TEMP
  47.  
  48.  
  49.         BTFSS   INTCON,T0IF                     ; Por si existe otra interrupcion
  50.         GOTO    Fin_interrupcion
  51.  
  52.         movlw   -d'39'                          ; Cargo nuevametne los datos del TMR
  53.         movwf   TMR0
  54.         BCF     INTCON,T0IF
  55.  
  56.         DECFSZ  contador,F
  57.         GOTO    Fin_interrupcion                ;No llego a decrementarse todo por lo tanto salgo
  58.        
  59.         BTFSS   Salida                          ;Se cumplio todo el contador, esta encendido la salida?
  60.         GOTO    Encender_Led
  61.         BCF     Salida                          ;Esta encendido? Lo apago y recargo el contador
  62.         GOTO    Recarga_contador
  63. Encender_Led
  64.         BSF     Salida                          ;Esta apagado? Lo enciendo y recargo el contador
  65. Recarga_contador
  66.         movlw   d'100'                 
  67.         movwf   contador       
  68.  
  69. Fin_interrupcion
  70.  
  71.         SWAPF STATUS_TEMP,W                     ;Vuelvo a poner los registros W y STATUS con los valores que tenian antes de entrar a la interrupcion
  72.         MOVWF STATUS
  73.         SWAPF W_TEMP, F
  74.         SWAPF W_TEMP, W
  75.         RETFIE
  76.  
  77.         END

Simplemente tome tu codigo y lo acomode para que se encienda y apague un LED cada un segundo. Facilmente adaptable a lo que queres hacer vos.
Imagino que si no queres ser muy perfeccionista te llevaria 2 instrucciones mas.