La interrupción no parece volver a habilitarse en PIC16F887

0

Estoy creando un temporizador con el PIC16F887, algunos botones y pantallas de siete segmentos. Estoy escribiendo el código en ensamblaje, y todo funciona muy bien, excepto el botón de inicio / parada que se maneja como parte de una rutina de servicio de interrupción. La rutina de servicio complementa la variable RUN que inicia el temporizador / incrementador. La rutina de incremento se omite si el bit de RUN menos significativo es 0. Puedo iniciar el temporizador, pero no puedo detenerlo. Borro el indicador INTF en el registro INTCON dentro del ISR, pero parece que el ISR sigue deshabilitado.


;******************************************************
;PIC Configuration for PIC16F887
#include "p16F887.inc"

; CONFIG1
; __config 0x2032
 __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_ON & _CPD_ON & _BOREN_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF
; CONFIG2
; __config 0x3FFF
 __CONFIG _CONFIG2, _BOR4V_BOR40V & _WRT_OFF
;******************************************************
  DCOUNT       EQU 20H
  CNT_100th    EQU 21H    ; counter for 0.01s
  CNT_10th     EQU 22H    ; counter for 0.1s
  CNT_sec      EQU 23H    ; counter for seconds
  CNT_10sec    EQU 24H    ; counter for tens of seconds
  CNT_min      EQU 25H    ; counter for minutes
  CNT_10min    EQU 26H    ; counter for tens of minutes
  RUN          EQU 70H    ;the run variable that does stuff to things
  OCOUNT       EQU 28H
  ICOUNT       EQU 29H

  ORG  000H
  GOTO MAIN

  ORG   004H
  GOTO  ISR


  ORG   008H
  GOTO  LOOP

;*******************************************************
MAIN
  CLRF STATUS


  CLRF  CNT_100th
  CLRF  CNT_10th
  CLRF  CNT_sec
  CLRF  CNT_10sec
  CLRF  CNT_min
  CLRF  CNT_10min
  CLRF  RUN

  BSF    STATUS,RP1             ;change to bank 3
  BSF    STATUS,RP0

  CLRF   ANSEL                 ;Using all digital mode, turns off analog
  CLRF   ANSELH                ;Make all analog ports digital

  BCF    STATUS,RP1             ;change to correct bank to configure TRIS registers
                             ;MAKE RA0 OUTPUT, RB0 INPUT, PORTC AND PORTD ALL OUTPUTS

  CLRF  TRISA
  CLRF  TRISB
  COMF  TRISB,1
  CLRF  TRISD 

  CLRF  INTCON

  BSF   INTCON,7
  BSF   INTCON,4
  MOVLW 040H
  MOVWF OPTION_REG

  BCF   STATUS,RP0

  GOTO  LOOP

LOOP
  MOVF    CNT_100th,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,5     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,5

  MOVF    CNT_10th,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,4     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,4

  MOVF    CNT_sec,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,3     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,3

  MOVF    CNT_10sec,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,2     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,2


  MOVF    CNT_min,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,1     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,1

  MOVF    CNT_10min,0 ; Put count of 1/100ths of second in W
  CALL    TABLE         ; Get value to write out to PORTD from table
  MOVWF   PORTD     ; Put value out to PORTD
  BCF     PORTA,0     ; Turn on and off display to show digit
  CALL    DELAY
  BSF     PORTA,0

  CALL    WAIT

  BTFSC   RUN,0
  CALL    INCCNT
  GOTO    LOOP

WAIT
    MOVLW     08H
    MOVWF     OCOUNT
    MOVLW     0FFH
    MOVWF     ICOUNT     

    OLOOP             
        ILOOP     
        DECFSZ    ICOUNT,1     
        GOTO      ILOOP      
        DECFSZ    OCOUNT,1                
        GOTO      OLOOP                 

        RETURN              

ISR
  COMF     RUN,1
  BCF      INTCON,1   
  RETFIE

Cualquier orientación sería muy apreciada aquí. Mi sospecha es que hay algo en la forma en que he estructurado el programa que está causando este error.

Actualizar

Resolví el problema borrando los siguientes registros asociados con PORTB:

  • CCP1CON
  • IOCB
  • WPUB

También reformateé el código de acuerdo con algunos de los estrictos consejos a continuación, y el PIC que estoy usando tiene registros ANSEL y ANSELH. Está ahí, en blanco y negro, en la hoja de datos .

Gracias a todos

    
pregunta marioIncandeza

1 respuesta

4

Hay mucho código malo aquí, es difícil saber por dónde empezar. Respondiendo la pregunta directamente sin sentido hasta que se solucionen otras cosas. Te preocupas por el color de los calcetines que debes usar al saltar desde un acantilado.

Solo mencionaré algunas cosas:

  DCOUNT       EQU 20H
  CNT_100th    EQU 21H    ; counter for 0.01s
  CNT_10th     EQU 22H    ; counter for 0.1s
  CNT_sec      EQU 23H    ; counter for seconds
  CNT_10sec    EQU 24H    ; counter for tens of seconds
  CNT_min      EQU 25H    ; counter for minutes
  CNT_10min    EQU 26H    ; counter for tens of minutes
  RUN          EQU 70H    ;the run variable that does stuff to things
  OCOUNT       EQU 28H
  ICOUNT       EQU 29H

Parece que piensas que estás asignando variables aquí, pero todo lo que realmente estás haciendo es crear constantes que tienen valores específicos. Solo usted sabe que estos valores son las direcciones de las ubicaciones de memoria. Eso es bastante malo, pero también está especificando direcciones fijas en el código fuente. Puede tener una razón para saber en qué banco están estas variables, pero no tiene sentido especificar direcciones exactas. Si alguna vez mueve este código a un PIC diferente, es posible que el PIC no tenga RAM general a las 20 h. Especifique el banco si es necesario, pero deje que el vinculador coloque las variables dentro del banco.

La forma única de asignar variables con MPASM / MPLINK es usar la directiva RES.

También, veo algunos comentarios, pero "¿una variable que hace cosas para las cosas"? ¿Y qué pasa con DCOUNT, OCOUNT y ICOUNT? ¿Qué se supone que deben hacer?

Veo que pones RUN en la región compartida, pero no lo señalaste. Eso es astuto y desagradable.

  ORG   004H
  GOTO  ISR

Esto no solo es tonto, sino que también es totalmente incorrecto en esta máquina. Primero, ¿por qué no poner la rutina de interrupción a las 4? Algunos códigos terminarán ahí, por lo que podría ser la única rutina que realmente se beneficia de estar allí. En segundo lugar, esto es totalmente erróneo en una máquina que tiene más de una página de códigos. La instrucción GOTO solo codifica los 11 bits bajos de la dirección, con los 2 bits de dirección superiores provenientes de PCLATH. No sabe a qué se puede configurar PCLATH cuando se produce una interrupción, por lo que tiene una posibilidad entre 4, esto realmente irá al lugar correcto.

Inicia la rutina de interrupción en 4 y deja que todo lo demás fluya a su alrededor.

  ORG   008H
  GOTO  LOOP

¿Qué? Eh Esto no tiene ningún sentido en absoluto. ¿Incluso miró la hoja de datos?

  BSF    STATUS,RP1             ;change to bank 3
  BSF    STATUS,RP0

No hagas ajustes bancarios fijos. Por lo menos usa BANKSEL.

  CLRF   ANSEL                 ;Using all digital mode, turns off analog
  CLRF   ANSELH                ;Make all analog ports digital

Al menos, tenemos algunos comentarios aquí para que podamos decir lo que pretendía. Sin embargo, esta máquina no tiene registros ANSEL, que incluso un breve vistazo a la hoja de datos habría revelado. Para hacer que todos los pines analógicos sean digitales, utilice los registros ADCON. De nuevo, LEA LA HOJA DE DATOS.

  BCF    STATUS,RP1             ;change to correct bank to configure TRIS registers

Esto realmente cambiará el banco a 0 o 1, dependiendo de la configuración del bit RP0. El código anterior establece RP0, por lo que en realidad va al banco 1. Sin embargo, esta dependencia no se establece y este código se interrumpirá si el código anterior se modifica para dejar RP0 establecido en 0. De nuevo, al menos use BANKSEL. Hay formas más inteligentes y eficientes de administrar la configuración del banco, pero BANKSEL es totalmente confiable y autónomo. Cuando recién estés comenzando, úsalo en lugar de tratar de complicarte.

  GOTO  LOOP

LOOP

¿A dónde más crees que irá el código?

ISR
  COMF     RUN,1
  BCF      INTCON,1   
  RETFIE

En este caso, coloca RUN en el banco compartido e INTCON se asigna a todo el banco, por lo que estas dos instrucciones realmente funcionarán. Sin embargo, nunca borró la condición de interrupción! El procesador generará una nueva interrupción inmediatamente después de que RETFIE vuelva a habilitar las interrupciones. Una vez más, tienes que leer la hoja de datos , que es bastante clara sobre cómo funcionan las interrupciones.

Luego está el tema del debouncing, del cual no veo nada. Incluso si tuvieras que eliminar la condición de interrupción correctamente, esto no funcionaría, ya que obtendrás múltiples conteos por cada pulsación y liberación del botón.

He omitido otros problemas y hay más códigos que ni siquiera he mirado, pero estoy abandonando aquí.

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas