Autor Tema: Contador por timer0 en pic16f88  (Leído 3808 veces)

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

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Contador por timer0 en pic16f88
« en: 07 de Julio de 2015, 15:33:20 »
Hola tengo que realizar un contador descendente con cuatro pulsadores, uno que decremente, otro que incremente, un start y un reset.
El contador debe funcionar por timer0 por segundo, este es mi código y tuve algunos problemas para poder simularlo quisiera que alguien me diga si esto esta bien, o si estoy haciendo cualquier cosa.Muchas gracias




 LIST           P=16F88
                #INCLUDE   <P16F88.INC>


;Estas son las palabras de configuracion necesarias para este microconlador
      __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC

     __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF

;dentro de esta directiva CBLOCK   se especifican las variables con las que voy a trabajar en el programa
                 CBLOCK               0X20
                 START
                 CUENTA
                 SEG
                 MIN
                 HOR
                 REG_W  
                 REG_S
                 ESTADO
                 d1
                 d2
                 d3
                 d4
                 EMPIEZA
                 NUM
                 ENDC
                  

                 ORG                      00
                 GOTO                    CONFIGURA
          
                
                
;Este bloque lo uso para configurar los perofericos del microcontrolador------
CONFIGURA                    NOP
                             BANKSEL   OSCCON
                             MOVLW   0X60   ;RELOJ INTERNO 4MHZ
                             MOVWF   OSCCON
                             BANKSEL   TXSTA
                             CLRF      ANSEL
                             MOVLW     B'11110000'
                             MOVWF     TRISA
                             MOVLW     B'00000000'
                             MOVWF     TRISB;       CONFIGURE ENTRADAS Y SALIDAS
                             BANKSEL   TXREG
                            
                             movlw     B'00000000'   ;HABILITA TEMPORIZADOR Y CLOCK INTERNO
                            movwf       OPTION_REG
                          
                            MOVLW       D'226'
                            MOVWF       NUM
                            
                             MOVLW      B'1001'
                             MOVWF      SEG
                             MOVLW      B'1001'
                             MOVWF      MIN
                             MOVLW      B'1001'
                             MOVWF      HOR
                             MOVLW      D'100'
                             MOVWF      CUENTA


;PROGRAMA PRINCIPAL------------------------------------------------------------
 INICIO         CALL    INC    
                CALL    DEC
                CALL    STRT
                CALL    PRESET
                CALL    PRUEBA
                CALL    MUESTRA
                GOTO    INICIO
;RUTINAS-----------------------------------------------------------------------
INC             BTFSC       PORTA,0
                RETURN  
                CALL        DELAY
                BTFSC       PORTA,0
                RETURN
                INCF      SEG,1
                MOVLW      B'1010'
                SUBWF      SEG,0
                BTFSS      STATUS,Z
                RETURN
                MOVLW      B'0000'
                MOVWF      SEG
                INCF      MIN,1
                MOVLW      B'1010'
                SUBWF      MIN,0
                BTFSS      STATUS,Z
                RETURN
                MOVLW      B'0000'
                MOVWF      MIN
                INCF      HOR,1
                MOVLW      B'1010'
                SUBWF      HOR,0
                BTFSS      STATUS,Z
                RETURN
                MOVLW      B'0000'
                MOVWF      HOR
                RETURN


DEC             BTFSC      PORTA,1
                RETURN
                CALL       DELAY
                BTFSC      PORTA,1
                RETURN
                DECFSZ       SEG,1
                RETURN
                MOVLW      B'1001'
                 MOVWF      SEG
                 DECFSZ     MIN,1
                 RETURN
                 MOVLW      B'1001'
                 MOVWF      MIN
                 DECFSZ     HOR
                 RETURN
                 MOVLW      B'1001'
                 MOVWF      HOR
                 RETURN
        
STRT    BTFSC       PORTA,2
        RETURN
        CALL        DELAY
        BTFSC       PORTA,2
        RETURN
        MOVLW     NUM
        MOVWF     TMR0
        BSF       EMPIEZA,0
        RETURN
        
PRESET  BTFSC   PORTA,3
        RETURN
        CALL    DELAY
        BTFSC   PORTA,3
        MOVLW   NUM
        MOVWF   TMR0
        MOVLW   B'1001'
        MOVWF   SEG
        MOVWF   MIN
        MOVWF   HOR
        RETURN


PRUEBA  BTFSS   INTCON,2
        RETURN
         BTFSS       EMPIEZA,0 ;PREGUNTO SI PRESIONE START
         RETURN
         DECFSZ      SEG,1  ;DECREMENTO UNIDAD
         RETURN
         MOVLW       B'1001'      ;PREGUNTO SI LLEGO A CERO
         MOVWF       SEG   ;LO PONGO EN NUEVE
         DECFSZ      MIN,1        ;DECREMENTO DECENA
         RETURN
         MOVLW       B'1001' ;PREGUNTO SI LLEGO A CERO
         MOVWF       MIN ;    LO PONGO EN NUEVE
         DECFSZ      HOR ;DECREMENTO CENTENA
         RETURN      ;PREGUNTO SI LLEGO A CERO
         MOVLW       B'1001' ; LO PONGO EN NUEVE
         MOVWF       HOR
         BCF         INTCON,2
         RETURN
        
MUESTRA MOVF    SEG,W
        MOVWF   PORTB
        BSF     PORTA,4
        CALL    ESPERO
        BCF     PORTA,4
        MOVF    MIN,W
        MOVWF   PORTB
        BSF     PORTA,5
        CALL    ESPERO
        BCF     PORTA,5
        MOVF   HOR,W
        MOVWF   PORTB
        BSF     PORTA,6
        CALL    ESPERO
        BCF     PORTA,6
        RETURN
        
ESPERO  movlw   0x03
   movwf   d1
   movlw   0x18
   movwf   d2
   movlw   0x02
   movwf   d3
Delay_1
   decfsz   d1, f
   goto   $+2
   decfsz   d2, f
   goto   $+2
   decfsz   d3, f
   goto   Delay_1
    RETURN




DELAY   movlw   0xCF
   movwf   d1
   movlw   0x08
   movwf   d2
Delay_0
   decfsz   d1, f
   goto   $+2
   decfsz   d2, f
   goto   Delay_0
   RETURN
 
        
        
        END; FIN DEL PROGRAMA
« Última modificación: 07 de Julio de 2015, 15:42:59 por BORIScristian »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Contador por timer0 en pic16f88
« Respuesta #1 en: 07 de Julio de 2015, 16:13:17 »
Citar
Hola tengo que realizar un contador descendente con cuatro pulsadores, uno que decremente, otro que incremente, un start y un reset.
El contador debe funcionar por timer0 por segundo

Bueno no entendi que tiene que hacer EXACTAMENTE el programa, me quedo claro que tenes 4 pulsadores, que hay un boton de start y uno de reset, pero no entiendo que quisiste decir con "El contador debe funcionar por segundo"
Te pregunto unas cosas para poder intentar entender lo que queres hacer y lo que hiciste, y ver por que no anda bien.

-Teniendo un boton de start/reset imagino que debes presionar el boton y en un intervalo de tiempo FIJO deberias capturar todas las veces que se presiono, es asi ?
-Es OBLIGATORIO el timer0 ? o puede ser el timer1 que es de 16bits?
-Si se decrementa menos de 0 que deberia ocurrir? Queda en 0?
-Cual es valor maximo de pulsos del contador? Hay un rango limitado de valores? por ejemplo de 00 a 99?
-Hay un limite maximo de tiempo o el tiempo a capturar los datos es fijo ?
-Que ocurre si presionas el boton de RESET mientras esta funcionando?
- Por lo que parece estas mostrando en 3 displays, es asi? Tenes un 4511 entre el display y el PIC o el PIC esta conectado directamente al display?

Estas y todas las ocurrencias/preguntas que se te puedan ocurrir mejor decirlas ahora para saber con que estamos lidiando
« Última modificación: 07 de Julio de 2015, 16:22:07 por KILLERJC »

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re: Contador por timer0 en pic16f88
« Respuesta #2 en: 07 de Julio de 2015, 16:30:37 »
Disculpa me exprese bastante mal, no estoy acostumbrado a los foros y gracias por contestar, te explico el programa
El programa comienza mostrando "999", mediante 3 display 7segmentos (multiplexados)
tengo 4 pulsadores que serian:
1-decremento( mientras aun no esta temporizando, selecciono el tiempo de inicio, por ejemplo si quiero empezar a temporizar desde 800 presiono 199 veces este boton.
2-incremento( lo mismo que el anterior pero este si estoy en 800 lo presiono 100 veces y me deja en 900)
3-Start (este pulsador es el que da comienzo a la temporización a partir del número en que me posicione con los anteriores pulsadores)
4-Reset (si presiono este boton en cuaquier momento de la temporizacion automaticamente vuelvo a posicionarse en 999)

La temporizacion tiene que ser por timer0 cada un segundo(supongamos que estoy en 999 presiono start y luego de un segundo pasa a 998, despues de otro segundo 997 y asi en forma continua)


Respondo a tus preguntas:
1- el boton de reset y de start son dos pulsadores distintos
2-El timer0 es obligatorio por pedido del profesor
3-Cuando decrementa y queda en 0 deberia quedar en 0 hasta presionar reset
4-es de 999 a 0
5- si presiono reset durante la temporizacion  deberia volver a 999
6-si, los display estan multiplexados y mediante un 4511

(LO QUE MAS ME PREOCUPA ES SI UTILIZE BIEN EL TIMER0 PORQUE NO ESTOY ACOSTUMBRADO A USARLO, LO DEMÁS LEYENDO EL DATASHEET SI TENGO ALGUN ERROR PODRÍA SOLUCIONARLO EN CUANTO PUEDA SIMULARLO)

Muchas gracias la verdad que no sabia a que recurrir para poder terminarlo
« Última modificación: 07 de Julio de 2015, 17:33:14 por BORIScristian »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Contador por timer0 en pic16f88
« Respuesta #3 en: 07 de Julio de 2015, 20:10:05 »
Bueno ahora si entiendo, voy a decirte que puede estar mal en tu programa antes de decirte "hacelo con interrupciones" ( esto seria lo ideal ) y hacerte cambiar bastante del mismo metiendote en tal ves algo que no manejas muy bien.
Por lo visto esta bien estructurado el programa, por ahi le faltaria un poco mas de comentarios para recordar lo que haces, acostumbrate a eso, te va a salvar la vida bastantes veces.

1- Mientras el programa esta corriendo, no hay nada que evite que se pueda "incrementar" o "decrementar" la variable.
2- Los delays pueden hacer que no corra en "segundos" sino que por ahi se actualize mas lento y termines perdiendo mucha precision, por ejemplo si pones 30 segundos, tal ves pasen 35 por culpa de no hacerlo con una interrupcion al timer.

3- Dejando de lado los otros problemas encuentro algunos problemas de programacion. Aca recopilo todos los problemas de programacion

Código: ASM
  1. DECFSZ       SEG,1
  2.                 RETURN
  3.                 MOVLW      B'1001'
  4.                  MOVWF      SEG
  5.                  DECFSZ     MIN,1
  6.                  RETURN

Esa es una parte de tu codigo, hay en 2 partes que restas.. pero es algo bastante simple, tu idea es que vaya de 9 a 0, y cuando supere el 0 pase nuevamente a 9, graficamente
6 - 5 - 4 - 3 - 2 - 1 - 0 - 9 - 8

Pero ahi primero resta y luego pregunta, lo cual te queda algo asi:
6 - 5 - 4 - 3 - 2 - 1 - 9 - 8
Por que decrementaste cuando estaba en 1 eso es 0 y luego pregunta.

Una solucion bastante "simple" a esto seria decrementar y luego preguntar por si el bit 7 de ese registro SEG,7 esta en 1, si esta en 1 ponerle un 9, esto es por que cuando tu registro de 8 bits le restas 1 estando en 0x00 pasa a 0xFF

Sigamos con otro error de programacion

Código: ASM
  1. MOVLW     NUM
  2.         MOVWF     TMR0

No tan facil de ver esto, pero CBLOCK en realidad no crea "variables" es decir, para el compilador esas no son variables ni registros sino que le das un valor fijo que si lo usas en las instrucciones se reemplaza, pero observa que tenes ahi, tenes un MOVLW, eso estaria moviendo esa constante ( OJO no el contenido, sino lo que indica la direccion ) en tu programa es 0x2D (NUM es el registro ubicado en esa direccion) , en fin, creo que es un error, para mi que trataste de cargar el valor que tiene DENTRO el registro NUM, para eso deberias haber usado MOVF , y no MOVLW

Una cosa que note tambien es que te olvidas quitar el FLAG en el boton de reset, asi que usas el bit 0 del registro EMPIEZA para indicar que deberia contar pero cuadno presioans reset no lo pones a 0.

Código: ASM
  1. BTFSS   INTCON,2

Tenes que tener ojo aca, ya que el timer0 JAMAS para,
Tampoco estas limpiando el flag cuando salis, lo cual queda en 1, esto significa que apenas presiones el boton de start y este a 1 el flag del timer, va a entrar rapidisimo ahi, por que estaba puesto en 1 el flag tuyo y estarias "perdiendo" 1 segundo. Una solucion rapida seria poner en 0 el flag del timer y cargar el valor del mismo cuando presionas start

Yo pregunte por el timer1 por que al ser de 16bits permite acercarse mas al valor de 1 segundo o un multiplo del mismo, incluso se puede usar otros modulos que pueden facilitar aun mas la operacion de cargar el timer,etc etc etc. como el CCP ( Capture/Compare/PWM)

Usando el TMR0 , como lo tenes configurado con preescaler 1:2 y cargandole 226 al registro, tenes que cada "interrupcion" o se va a poner a 1 el flag cada 0.06ms o 60us
Tcy = 4 / Fosc = 4 / 4Mhz = 1us,
con preescaler 1:2 va a aumentar cada 2us
El valor que le falta para que se dispare el TMR es de 256-226 = 30 => 30*2us = 60us

Es decir que tu flag se va a poner a 1 cada 60us, esto quiere decir que si pones un delay de 30ms, se habria puseto 500 veces a 1 ese flag. o aun peor, tenes cerca de 60 instruccion de un ciclo ( los saltos ocupan 2 ) para atender ese flag.

Asi que deberias arreglar eso, deberias tener un valor mucho mas grande, el TMR0 podes elegir hasta 1:256 en preescaler, es decir se necesita 256 pulsos desde el reloj para que el timer sume 1, y ya sabes que pasaron 256us

Por ser tiempo es mas facil intentar encontrar un valor que es multiplo entero, por ejemplo si logro que en mi timer ocurra ese desborde activandome la bandera cada 0.2s seria genial, ya que cuando cuente 5 veces que ocurre eso, se que paso 1 segundo.
Como dije el TMR0 es mas complejo de hacerlo, con el TMR1 uno puede hacer hasta de 0.5s ( preescaler 1:8 y cargas el valor 3036 en el timer )

Aca pasa a ser un compromiso, como ves no es un numero "redondo" el 256, lo cual por mas que lo multipliques como quieras, vas a tener problemas ya que nunca va a dar exacto.
Por ejemplo con preescaler 1:256 tenes que cargando 61 pasan 0.04992s, asi que deberias contar unas 20 veces ese flag ( borrarlo y cargar 61 de vuelta en el TMR ) para que pase 1 segundo.


Esas son todas las que note... Realmente yo lo haria con interrupciones, y si pudiera hasta con el modulo CCP, el TMR0 va a hacer que tengas error, como ves me qeudo en 0.04992, si tomas como que eso son 0.05, cuando contes 999 vas a tener un error de tiempo de 0.08s + lo que tardas en actualizar el timer con su nuevo valor, el cual le toma 2 ciclos mas al timer, mas el error del oscilador interno por no ser de exactamente 4Mhz, mas el error de no limpiar la bandera y cargar el timer apenas ocurre el overflow eso te lleva a tener segundos de error y mas si se usan delays.

La solucion aca seria usar una interrupcion.

Para que entiendas un poco mas , para mantener un buen "tiempo" en los timers seria de cargarle el valor ahi noams que se pueda, por que ? Por que cuando el timer pone a 1 su bandera, este sigue funcionando, no se para. y si te tardas tu timer siguio sumando y tal ves tenga un valor de 0x05 , lo cual esos 5 que conto los estarias eliminando cuando le pones un nuevo valor. uno tiene la necesidad de saber cuanto tiempo paso asi que cuenta los ciclos del reloj, asi que cuando conto la cantidad que le pusimos tenemos que actualizar el timer ahi nomas para que vuelva a hacer otro tramo de tiempo mas determinado por nosotros. Espero no haberla complicado con esto.

4- Otra cosa mas que no toque, es la de los botones, lo cual puede que incremente o decrementen mas de 1
5- Posibles (aunque estoy seguro) problemas al mantener presionado el boton start mientras corre el programa

Esto es un offtopic:

Otra 2 cosas mas para pedirte y si te acostumbras mejor, tanto para vos como para mi:

Código: ASM
  1. INCF    SEG,1
  2. SUBWF   SEG,0

Eso por :

Código: ASM
  1. INCF    SEG,F
  2. SUBWF   SEG,W

Es mas entendible, F es del registro, por eso INCF, incrementar registro, como decia es solo para entenderlo mas al codigo xD.
Igual que aca:

Código: ASM
  1. BTFSS   INTCON,2

podrias haber puesto:

Código: ASM
  1. BTFSS   INTCON,TMR0IF

Todos los bits de registros especiales estan incluidos en el p16f88.inc con el mismo nombre que tienen en el datasheet, es mas facil leerlo asi, ya que TMR0IF seria TiMeR 0 Interrupt Flag
« Última modificación: 07 de Julio de 2015, 20:41:10 por KILLERJC »

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re: Contador por timer0 en pic16f88
« Respuesta #4 en: 07 de Julio de 2015, 22:33:51 »
Citar
Usando el TMR0 , como lo tenes configurado con preescaler 1:2 y cargandole 226 al registro, tenes que cada "interrupcion" o se va a poner a 1 el flag cada 0.06ms o 60us
Tcy = 4 / Fosc = 4 / 4Mhz = 1us,
con preescaler 1:2 va a aumentar cada 2us
El valor que le falta para que se dispare el TMR es de 256-226 = 30 => 30*2us = 60us

Es decir que tu flag se va a poner a 1 cada 60us, esto quiere decir que si pones un delay de 30ms, se habria puseto 500 veces a 1 ese flag. o aun peor, tenes cerca de 60 instruccion de un ciclo ( los saltos ocupan 2 ) para atender ese flag.

Esta parte no te entendi, 60us son 1 segundo?entonces no estaría bien? los delays que yo utilize son de antirrebote para los pulsadores
no me dan otra opción que usar tmr0, asi que esa parte voy a tener que dejarla en tmr
« Última modificación: 07 de Julio de 2015, 22:36:01 por BORIScristian »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Contador por timer0 en pic16f88
« Respuesta #5 en: 07 de Julio de 2015, 22:39:44 »
60us son 60 microsegundos, es decir 0.00006 segundos

Como te dije, cargandole al registro del TMR0 el valor 61 y con un preescaler de 1:256 ( OPTION_REG ) tenes el flag arriba cada 0.04992. Usa una interrupcion para el timer, cuando entre 20 veces en la interrupcion significa que paso 1 segundos y podes restar. Si no entendes te doy un ejemplo

Y hoy en dia hay paginas que te calculan todo de forma mas facil:
http://eng-serve.com/pic/pic_timer.html

Eso te da el codigo en C, pero como es XC8 es dentro de todo "facil" transportarlo a ASM, ya que se maneja cambiando los bits de los registros.

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re: Contador por timer0 en pic16f88
« Respuesta #6 en: 07 de Julio de 2015, 22:53:24 »
Te pido el ejemplo porfa, entiendo lo de cargar 61 al tmr0 y lo del prescaler deberia cambiarle el numero al option_reg nomas pero lo de usar interrupcion para el timer no te entiendo, disculpa es que no estoy acostumbrado a trabajar con interrupciones siempre hice códigos simples
me estarias sugiriendo que cree una ISR y que cuente cada ves que entre ahi?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Contador por timer0 en pic16f88
« Respuesta #7 en: 08 de Julio de 2015, 04:27:21 »
Bueno, no se si va a funcionar pero aca esta.

La interrupcion para que lo entiendas funciona asi:

Tenes varias intrucciones cualquiera sean, y ocurre una interrupcion( es decir el timer paso de 0xFF a 0x00 , activandose la bandera(flag) de interrupcion del timer0 ) luego de la instruccion 3.

Inst 1
Inst 2
Inst 3
Inst 4
Inst 5

Normalmente vos seguirias la linea y se ejecutarian 1 - 2- 3 -4 -5, pero con las interrupcion ocurre esto:

1-2-3- Atiendo interrupcion -4-5- etc

Es decir que cuando el micro se da cuenta que tiene una interrupcion guarda en algun lugar donde estaba en el programa y va a ejecutar lo que esta en el vector de interrupcion, en este caso esta ubicado en la direccion 0x04.
Ahora cuando entro a la interrupcion uso el W y el registro STATUS cambia, por que al hacer una operacion o algo se modifca alguna bandera ( Z,C,etc) entonces para que cuando vuelva siga como si nada hubiera pasado (como si se hubiera ejecutado en el orden de 1-2-3-4-5 y no hubiera interrupcion) tengo que guardar los registros STATUS y W en algun lugar, luego de eso hago lo que quiero en mi interrupcion.

Código: ASM
  1. LIST           P=16F88
  2.                 #INCLUDE   <P16F88.INC>
  3.  
  4.  
  5. ;Estas son las palabras de configuracion necesarias para este microconlador
  6.       __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC
  7.  
  8.      __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF
  9.  
  10.  
  11.  
  12. #define VALOR_TMR       61
  13.  
  14. ;dentro de esta directiva CBLOCK   se especifican las variables con las que voy a trabajar en el programa
  15.  
  16.         CBLOCK  0X20
  17.         SEG                     ; Variables que contienen los datos a mostrar
  18.         MIN
  19.         HOR
  20.         d1                      ; Registro para los delays
  21.         d2
  22.         d3
  23.         d4
  24.         FLAGS                   ; Registro para flags, solo en uso bit0 : Contando
  25.         W_TEMP                  ; Registro para guardar W en interrupcion
  26.         STATUS_TEMP             ; Registro para guardar STATUS en interrupcion
  27.         CUENTA                  ; Variable para que determina la cantidad de interrupciones a contar
  28.         ENDC
  29.  
  30.                    
  31.  
  32.         ORG     0x00            ; Vector de reset
  33.         GOTO    CONFIGURA
  34.         ORG     0x04            ; Vector de interrupcion  
  35.         GOTO    INTERRUPCION
  36.                  
  37. ;-------------------- CONFIGURACION INICIAL --------------------------------------
  38.  
  39. CONFIGURA
  40.         BANKSEL OSCCON          ; Configuracion del oscilador
  41.         MOVLW   0X60            ; RELOJ INTERNO 4MHZ
  42.         MOVWF   OSCCON
  43.  
  44.         BANKSEL TXSTA           ; Configuracion de los pines
  45.         CLRF    ANSEL           ; Todos digitales
  46.         MOVLW   B'11110000'
  47.         MOVWF   TRISA           ; PORTA = EEEE SSSS
  48.         CLRF    TRISB           ; PORTB = SSSS SSSS
  49.  
  50.         BANKSEL TXREG
  51.         MOVLW   B'00000111'     ; Configuramos timer, preescaler 1:256 , asignado a TMR0, Clock del oscilador interno, pull-ups portb individuales
  52.         MOVWF   OPTION_REG
  53.         BSF     INTCON,GIE      ; Habilito interrupciones globales
  54.                            
  55.         MOVLW   B'1001'         ; Valores iniciales
  56.         MOVWF   SEG
  57.         MOVWF   MIN
  58.         MOVWF   HOR
  59.  
  60.         MOVLW   D'21'           ; Cargo 21 que son las veces que deberia entrar a la interrupcion, en realidad son 20 veces
  61.         MOVWF   CUENTA
  62.         CLRF    FLAGS
  63.  
  64. ;----------------------------INTERRUPCION--------------------------------------
  65.  
  66. INTERRUPCION
  67.  
  68.         MOVWF   W_TEMP          ; Reguardo la informacion para que siga bien el otro programa, es decir guardo W y STATUS
  69.         SWAPF   STATUS,W        ; En W_TEMP y STATUS_TEMP , se usa SWAPF y MOVWF por que no modifican banderas del STATUS.
  70.         CLRF    STATUS
  71.         MOVWF   STATUS_TEMP
  72.  
  73.         BTFSS   INTCON,TMR0IF   ; Pregunto si fue por el TMR0
  74.         GOTO    SALIR_INT       ; De no haber sido por el TMR0 entonces salga
  75.  
  76.         BCF     INTCON,TMR0IF   ; Borro flag de interrupcion
  77.         MOVLW   VALOR_TMR       ; Cargo valor al timer
  78.         MOVWF   TMR0
  79.  
  80.         DECFSZ  CUENTA,F        ; Decremento y salto si es 0
  81.         GOTO    SALIR_INT       ; De no llegar a 0 salgo de la interrupcion
  82.  
  83.         MOVLW   D'21'           ; Se lograron las 20 entradas? eso significa que paso 20 * 0.04992s , aproximadamente 1 segundo
  84.         MOVWF   CUENTA          ; Cargo el contador para que vuelva a contar 20 veces y comienzo a restar
  85.  
  86.  
  87.                                 ; Procedo a restar
  88.         MOVLW   B'1001'         ; Cargo 9 en W
  89.         DECF    SEG,F           ; Decremento seg, si se paso de largo es decir quedo 0xFF salta
  90.         BTFSS   SEG,7
  91.         GOTO    SALIR_INT       ; Termine de restar, salgo
  92.         MOVWF   SEG             ; 9 -> SEG
  93.         DECF    MIN,F           ; Decremento MIN, si se paso de largo salta
  94.         BTFSS   MIN,7
  95.         GOTO    SALIR_INT       ; Termine de restar, salgo
  96.         MOVWF   MIN             ; 9 -> MIN
  97.         DECF    HOR             ; Decremento HOR
  98.         BTFSS   HOR,7           ; Si NO se paso de largo salta y vuelve
  99.         GOTO    SALIR_INT       ; No se paso de vuelta, asi que salgo
  100.        
  101.         MOVWF   HOR             ; 9 -> HOR
  102.         BCF     FLAGS,0         ; Si llego aca es por que son todos 999 , en resumen estaria haciendo uno de mas.
  103.         BCF     INTCON,TMR0IE   ; Asi que quito las interrupciones por que ya se completo lo que queria, y habilito nuevamente los botones START, INC y DEC
  104.  
  105. SALIR_INT
  106.  
  107.         SWAPF   STATUS_TEMP,W   ; Dejo STATUS como estaba antes de entrar a la interrupcion
  108.         MOVWF   STATUS         
  109.         SWAPF   W_TEMP,F        ; Dejo W como estaba antes de entrar a la interrupcion
  110.         SWAPF   W_TEMP,W       
  111.         RETFIE
  112.  
  113. ;--------------------------PROGRAMA PRINCIPAL----------------------------------
  114.  
  115.  
  116. INICIO
  117.         BTFSC   FLAGS,0                 ;Pregunto si esta corriendo, si esta corriendo inhabilito los botones de incrementar, decrementar y START
  118.         GOTO    INICIO2
  119.         CALL    B_INCREMENTAR    
  120.         CALL    B_DECREMENTAR
  121.         CALL    B_START
  122. INICIO2
  123.         CALL    B_RESET                 ; Mientras este corriendo solo habilita a que se presione Reset y que se muestre en los displays
  124.         CALL    MUESTRA
  125.         GOTO    INICIO
  126.  
  127.  
  128. ;--------------------------------RUTINAS---------------------------------------
  129.  
  130. B_INCREMENTAR
  131.  
  132.         BTFSC   PORTA,0         ; Compruebo boton
  133.         RETURN  
  134.         CALL    DELAY
  135.         BTFSC   PORTA,0
  136.         RETURN
  137.  
  138.         INCF    SEG,F           ; SEG = SEG + 1
  139.         MOVLW   B'1010'         ; SEG > 9 ?
  140.         SUBWF   SEG,W  
  141.         BTFSS   STATUS,Z
  142.         RETURN                  ; NO es mayor a 9, vuelve
  143.         CLRF    SEG             ; Si es mayor a 9, SEG = 0 y MIN = MIN+1
  144.         INCF    MIN,F
  145.         MOVLW   B'1010'
  146.         SUBWF   MIN,W           ; MIN >9 ?
  147.         BTFSS   STATUS,Z
  148.         RETURN                  ; NO, vuelve
  149.         CLRF    MIN             ; SI, MIN = 0 y HOR = HOR+1
  150.         INCF    HOR,F
  151.         MOVLW   B'1010'
  152.         SUBWF   HOR,W           ; HOR > 9?
  153.         BTFSC   STATUS,Z
  154.         CLRF    HOR             ; SI, HOR = 0
  155.         RETURN                  ; NO, vuelvo
  156.  
  157.  
  158. B_DECREMENTAR
  159.  
  160.         BTFSC   PORTA,1         ; Compruebo boton
  161.         RETURN
  162.         CALL    DELAY
  163.         BTFSC   PORTA,1
  164.         RETURN
  165.  
  166.         MOVLW   B'1001'         ; Cargo 9 en W
  167.         DECF    SEG,F           ; Decremento seg, si se paso de largo es decir quedo 0xFF salta
  168.         BTFSS   SEG,7
  169.         RETURN
  170.         MOVWF   SEG             ; 9 -> SEG
  171.         DECF    MIN,F           ; Decremento MIN, si se paso de largo salta
  172.         BTFSS   MIN,7
  173.         RETURN
  174.         MOVWF   MIN             ; 9 -> MIN
  175.         DECF    HOR             ; Decremento HOR
  176.         BTFSC   HOR,7           ; Si NO se paso de largo salta y vuelve
  177.         MOVWF   HOR             ; Si se paso de largo le pongo un 9 -> HOR
  178.         RETURN
  179.          
  180. B_START
  181.         BTFSC   PORTA,2         ; Compruebo boton
  182.         RETURN 
  183.         CALL    DELAY
  184.         BTFSC   PORTA,2
  185.         RETURN
  186.  
  187.                                 ; Antes de comenzar deberia asegurarme que los valores SEG,HOR y MIN sean distinto de 0, sino no tiene sentido contar 0.
  188.         MOVF    HOR,W           ; W = HOR
  189.         IORWF   MIN,W           ; W = HOR | MIN
  190.         IORWF   SEG,W           ; W = HOR | MIN | SEG  ; Si hay alguno con algun valor, esto es imposible que de 0
  191.         BTFSC   STATUS,Z        ; Son todos 0???
  192.         RETURN                  ; SI, vuelve y no arranca el programa
  193.                                 ; NO, continua y comieza a funcionar el programa               
  194.  
  195.  
  196.         BCF     INTCON,TMR0IF   ; Borro flag de interrupcion
  197.         MOVLW   VALOR_TMR       ; Cargo valor al timer
  198.         MOVWF   TMR0
  199.         BSF     INTCON,TMR0IE   ; Habilito las interrupciones del TMR0
  200.  
  201.         BSF     FLAGS,0         ; Pongo a 1 mi flag, indicando que comenzo el proceso
  202.  
  203.         RETURN
  204.        
  205. B_RESET
  206.         BTFSC   PORTA,3         ; Compruebo boton
  207.         RETURN
  208.         CALL    DELAY
  209.         BTFSC   PORTA,3
  210.         RETURN
  211.  
  212.         BCF     INTCON,TMR0IE   ; Apago la interrupcion del TMR0
  213.  
  214.         MOVLW   B'1001'         ; Vuelvo todos los valores a 9
  215.         MOVWF   SEG
  216.         MOVWF   MIN
  217.         MOVWF   HOR
  218.  
  219.         BCF     FLAGS,0         ; Pongo a 0 mi flag, indicando que esta parado
  220.  
  221.         RETURN
  222.  
  223.        
  224. MUESTRA
  225.         MOVF    SEG,W  
  226.         MOVWF   PORTB           ; Valor de unidades
  227.         BSF     PORTA,4         ; Activo catodo de unidades
  228.         CALL    ESPERO          ; Delay
  229.         BCF     PORTA,4         ; Desactivo para cambiar de dato
  230.         MOVF    MIN,W           ; Valor de decenas
  231.         MOVWF   PORTB
  232.         BSF     PORTA,5         ; Activo catodo decenas
  233.         CALL    ESPERO
  234.         BCF     PORTA,5         ; Desactivo decenas
  235.         MOVF    HOR,W
  236.         MOVWF   PORTB           ; Cargo centenas
  237.         BSF     PORTA,6         ; Activo catodo centenas
  238.         CALL    ESPERO
  239.         BCF     PORTA,6         ; Desactivo centenas
  240.         RETURN
  241.  
  242.  
  243. ; ----------------------- RUTINAS AUXILIARES - DELAYS----------------------------------------------------
  244.  
  245.        
  246. ESPERO
  247.         movlw   0x03
  248.         movwf   d1
  249.         movlw   0x18
  250.         movwf   d2
  251.         movlw   0x02
  252.         movwf   d3
  253. Delay_1
  254.         decfsz  d1, f
  255.         goto    $+2
  256.         decfsz  d2, f
  257.         goto    $+2
  258.         decfsz  d3, f
  259.         goto    Delay_1
  260.         RETURN
  261.  
  262.  
  263. DELAY
  264.         movlw   0xCF
  265.         movwf   d1
  266.         movlw   0x08
  267.         movwf   d2
  268. Delay_0
  269.         decfsz  d1, f
  270.         goto    $+2
  271.         decfsz  d2, f
  272.         goto    Delay_0
  273.         RETURN

Que cambio con respecto de tu codigo?

- Interrupcion, ahi esta explicada lo que hace. Lo que hago es como ya se completo el timer, es recargarlo y preguntar si se cumplieron las 20 vueltas, si se cumplieron entonces resto, es decir cuando pasa 1 segundo recien resto de SEG,MIN,HOR.
- Botones, cuadno se esta ejecutando el programa, no permite que se use Incrementar, Decrementar, Start de nuevo, y lo unico que permite es que se use Reset y el mostrar en los displays
- Arregle la resta en el decrementar
- Quite algunos "registros" de mas , como REG_W , REG_S entre otros que no se usaban.
- Agregue una comprobacion para que no se pueda darle START cuando estan todos en 000, ya que no tiene sentido contar asi.

Partes que NO cambie:

- Comprobacion de que se mantiene presionado el boton, es decir si se mantiene presionado seguro que va a aumentar y aumentar continuamente.
- Rutina de muestra en los displays, solo las comente
- Delays

Errores que preveo:

- Estoy mas que seguro que va a contar 1 de mas, es decir que si tengo 100 va a contar de 100 a 999, en ves de 100 a 000 y luego resetearse, con lo cual tenes 1 segundo de mas.
Esto se origina por como hice para el limite de la resta en la interrupcion, es decir en ves de restar y luego preguntar si estan todos en 0, me limite a restar y cuando se cumpla que todos se pasaron de vuelta ahi pararlo, Sino tendria que haber hecho algo parecido como el boton de start, es decir una ves decrementado todo el de la hora tambien, preguntar si estan todos en 0, si es asi entones cortar todo. Lo podia haber realizado pero no lo hice :)

- No se si se va a ver pero peude haber glitches al mostrar los diplays, es decir por un momento muy pequeño puede que no muestre correctamente los valores, en el peor caso creo que serian 2 veces el valor del delay ESPERO en tiempo.
  Esto por que si ocurre la interrupcion mientras se esta mostrando y esta dentro de unos de esos delays, y se resta. puede ocurrir que ya paso el cambio por ejemplo de las unidades, y se cambien solo decenas y centenas con el nuevo dato, quedando unidades con el viejo, cuando entre nuevamente a la rutina de mostrar en el diplay se arreglaria, ese es el unico momento, no es demasiado complejo arreglarlo si es que se vuelve muy molesto.

----------------------------------------------------------------------------------------------------------------------

Bueno Finalmente para que entiendas que TAN complicado fue lo que hicimos:

Si, modificamos el codigo, pero eso no tenia nada que ver con la interrupcion. Que hicimos por la interrupcion?

Sacamos el codigo del timer que tenias dentro de tu programa principal, y lo pusimos en la interrupcion, ademas le agregamos 2 pedazos de codigo para guardar y luego devolver sus valores originales a STATUS y W.
Y agregamos 1 o 2 lineas mas para activar las interrupciones globales y del timer.
Basicamente ESO es ponerlo en la interrupcion.

Si observas es demasiado sencillo, nomas que ahora en ves de tener que pasar por todos los botones, los displays, etc, se ejecuta apenas debe hacerlo. O mejor dicho, apenas se pone a 1 el flag TMR0IF se ejecuta y continua con el programa como si nada fuera.

----------------------------------------------------------------------------------------------------------

Y por ultimo, esto se hizo un poco largo por que intente seguir tu forma de hacerlo, es decir de tener 3 registros, cada uno con su digito.

Lo que se podria haber realizado y terminaria siendo mas corto el programa y tal ves mas facil, seria manejar 2 registros asi tener 16 bits y y utilizar un simple INCF o DECF, para cuando se quisiera mostrar, se lo pasa por un conversor binario a BCD y se lo muestra. Ese conversor entraria los 10bits en binario y tendrias como resultado 4 registros ( o 2 ) con los valores en "decimal", y haria mucho mas facil el programa, lo unico complicado seria el conversor binario-BCD que podrias sacar de internet.
« Última modificación: 08 de Julio de 2015, 04:57:04 por KILLERJC »

Desconectado BORIScristian

  • PIC10
  • *
  • Mensajes: 13
Re: Contador por timer0 en pic16f88
« Respuesta #8 en: 09 de Julio de 2015, 16:16:32 »
Muchas gracias la verdad que me ayudaste un montón y ni hablar de que casi me dejaste el código de la interrupción armado que era lo que no podía hacer, me salvaste ajjajja lo único que no entendí es lo de 
"BTFSS   SEG,7
   GOTO   SALIR_INT   ; Termine de restar, salgo
   MOVWF   SEG      ; 9 -> SEG
   DECF   MIN,F      ; Decremento MIN, si se paso de largo salta
   BTFSS   MIN,7"
Pero no te preocupes ahora  voy a releer porque  ya me lo habías explicado y sino lo busco por internet
Lo voy a correr en el ISIS  para ver como quedo funcionando, muchas gracias por tu ayuda

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Contador por timer0 en pic16f88
« Respuesta #9 en: 09 de Julio de 2015, 17:42:54 »
Eso es simple.. Como dije antes, vos usabas:

Código: ASM
  1. DECFSZ       SEG,1
  2.                 RETURN
  3.                 MOVLW      B'1001'
  4.                  MOVWF      SEG
  5.                  DECFSZ     MIN,1
  6.                  RETURN


Entonces si supones que tenes el numero 992 (0x09 0x09 0x02 - HOR,MIN,SEG), cuando presionas para decrementar va a disminuir a 991 pero cuando presiones de nuevo, va a ocurrir que va a pasar a 989.
Esto es por que si SEG es igual a 1, el DECFSZ va a decrementar y luego preguntar si es 0, entonces saltaria y le pondria un 9 a SEG, por lo cual nunca podrias tener SEG en 0 y ocurre lo que dije antes. Distinto el codigo que te pase

Código: ASM
  1. DECF    SEG,F           ; Decremento seg, si se paso de largo es decir quedo 0xFF salta
  2.         BTFSS   SEG,7
  3.         RETURN
  4.         MOVWF   SEG             ; 9 -> SEG
  5.         DECF    MIN,F           ; Decremento MIN, si se paso de largo salta
  6.         BTFSS   MIN,7
  7.         RETURN

Ahora decremento, si era 1 pasa a 0 (0x00), y pregunto por el bit 7 si esta en 1, esto por que ?, es por que si yo decremento nuevamente cuando SEG esta en 0 ( 0x00 ) pasa a valer 255 (0xFF - 1111 1111) y ahi se que se termino y deberia ser un 9.
Ahora si solo cambia cuando decremento y estaba en 0, y siguiendo el ejemplo de antes haria 992 - 991 - 990 - 989 etc