Autor Tema: Hola tengo un problema con TIMER 0 tengo que hacer un contador al 255  (Leído 2010 veces)

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

Desconectado vero250996

  • PIC10
  • *
  • Mensajes: 4
Hola que tal buenas noches me dejaron hacer un contador con timer 0 cada vez que el timer se desborde generara un uno y asi sucesivamente hasta tener el 255 y reiniciar  pero al probar mi contador solo se queda en 2 y no hace nada mas por favor si me puedieran ayudar seria de gran ayuda gracias la escla es 1:64
__CONFIG  _CP_OFF&_WDT_OFF&_XT_OSC

LIST P=16F877A
INCLUDE <p16F877A.inc>

TMR0       EQU 01H
STATUS     EQU 03H
PORTA      EQU 05H
PORTB      EQU 06H
TRISA      EQU 85H
TRISB      EQU 86H
INTCON     EQU 0BH
OPTION_REG EQU 81H
MONO       EQU 0X21
NIRVANA    EQU 0X22
ORG 0;Inicio en la posicion 0 del programa
GOTO INICIO
ORG 0X04;VECTOR QUE DA INICIO A LA INTERRUPCION
GOTO INTERRUPCION
INICIO
BCF STATUS,6
BSF STATUS,5
MOVLW 0XF0; SALIDAD
MOVWF TRISB
MOVLW B'10100000'
MOVWF INTCON
MOVLW B'11000101'; valor de la preescala 1:64
MOVWF OPTION_REG
BCF STATUS,6
BCF STATUS,5


MOVLW D'56' ;SE INICIALIZA EN 56 PARA QUE CUENTE 200 VECES
MOVWF TMR0  ;CAMBIO DE BANCO

MOVLW D'32'
MOVWF MONO  ;CARGAMOS EL VALOR DE MULTIPLICACION
;EL CONTEO SE HACE EN LA INTERRUPCION CUAND SE GENEREN LOS 400 MILISEGUNDOS

JA
MOVLW NIRVANA
MOVWF PORTB

INTERRUPCION

MOVLW D'56' ;SE CARGA EL VALOR 56 A TMR0 PARA QUE VUELVA
MOVWF TMR0
INCFSZ MONO,1; DECREMENTAMOS 1 DATO

GOTO MOMBY ; LIMPIA BANDERA
GOTO MONO2

MOMBY

BCF INTCON,2
RETFIE

MONO2
MOVLW D'32'
MOVWF MONO
DECFSZ NIRVANA,1
MOVLW D'255'
SUBWF NIRVANA,0
   BTFSS STATUS,2
   GOTO MOMBY
   GOTO LIMPIAR

LIMPIAR
   CLRF NIRVANA
   GOTO MOMBY
 END
« Última modificación: 14 de Marzo de 2016, 02:06:06 por vero250996 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Hola tengo un problema con TIMER 0 tengo que hacer un contador al 255
« Respuesta #1 en: 14 de Marzo de 2016, 02:37:10 »
Tenes unos cuantos problemas.. Pero primero voy a ir por un par de consejos y luego por los problemas. Vos los aceptaras o no a los consejos, eso depende de cada uno, solo te los digo para facilitarte la vida.

1- Esto no es necesario:

Código: ASM
  1. TMR0       EQU 01H
  2. STATUS     EQU 03H
  3. PORTA      EQU 05H
  4. PORTB      EQU 06H
  5. TRISA      EQU 85H
  6. TRISB      EQU 86H
  7. INTCON     EQU 0BH
  8. OPTION_REG EQU 81H

Lo tenes todo definido en el p16F877A.inc que agregas, es decir lo unico que esta haciendo alli es ocupar espacio.

2-

Código: ASM
  1. INCLUDE <p16F877A.inc>

Aunque esta soportado eso, es preferible y asi lo recomienda microchip que se use #include , con el # adelante.

3-

Código: ASM
  1. BCF STATUS,6
  2. BSF STATUS,5

Podes usar BANKSEL para moverte entre bancos , luego el compilador genera el codigo ( esos BSF y BCF por si solo y reemplaza los BANKSEL ), ejemplo para ir al banco 1 donde esta el TRISA, haces:

Código: ASM
  1. BANKSEL TRISA

O si seguis prefiriendo usar los BSF/BCF, el mismo .inc posee el nombre de los bits de cada registro, por lo que podes hacer:

Código: ASM
  1. BCF STATUS, RP1
  2. BSF STATUS, RP0

Hay muchas cosas mas definidas en el .inc, como W , F, los bits de status, Z,C,DC,etc, logrando 2 cosas, que tu codigo sea mas facil de leer, y no tener que recordar que bit era la Z de status por ejemplo.

4-

Trata de ponerle nombres que describan para que son los registros,

Código: ASM
  1. MONO       EQU 0X21
  2. NIRVANA    EQU 0X22

MONO y NIRVANA no dicen nada, por mas que te guste su musica. Lo mismo va para las etiquetas MONO2, MOMBY

5- Si necesitas definir varios registros y no queres estar poniendo cada uno de las direcciones, podes usar CBLOCK/ENDC y solo va incrementandose, solo tenes que dar el valor de comienzo

Código: ASM
  1. CBLOCK 0x20
  2.         W_TEMP          ;0x20
  3.         STATUS_TEMP     ;0x21
  4.         PCLATH_TEMP     ;0x22
  5.         MONO            ;0x23
  6.         NIRVANA         ;0x24
  7.         ENDC

En los comentarios puse las direcciones que se les asignaria a cada uno al hacer eso, si quisiera que comenzaran desde el 0x30, cambiaria el valor que esta al lado del CBLOCK.

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

Problemas:

1- El primer problema que veo y el mas llamativo es que no hay una distincion clara de lo que es la interrupcion y la rutina principal, pensalo como si la interrupcion es un programa aparte, no tiene ninguna relacion con el programa principal, no hay CALLs al programa principal, ni GOTO, es decir no se mezclan para nada.
Luego aparte de la interrupcion tenes tu programa principal que deberia ser un loop infinito.

2- Al no conocer el funcionamiento de la interrupcion, veo que no estas guardando STATUS,W y PCLATH cuando entras a la interrupcion. Busca en el datasheet del micro por W_TEMP y ahi seguro que tenes el codigo para guardar estos registros cuando entras a la interrupcion y como reponerlos luego. Dentro de esas instrucciones irian recien tu programa de la interrupcion.

Arregla eso, y luego vamos a ir avanzando en el programa, de nada sirve que te de el programa realizado, a pesar que pueda ser simple.
« Última modificación: 14 de Marzo de 2016, 02:40:17 por KILLERJC »

Desconectado vero250996

  • PIC10
  • *
  • Mensajes: 4
Re:Hola tengo un problema con TIMER 0 tengo que hacer un contador al 255
« Respuesta #2 en: 14 de Marzo de 2016, 02:47:27 »
Muchas gracias tengo bastantes problemas con esto pero la profesora nos dio un programa similar a este y si funciono pero el W_TEMP para que es? por favor

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Hola tengo un problema con TIMER 0 tengo que hacer un contador al 255
« Respuesta #3 en: 14 de Marzo de 2016, 03:41:38 »
Bueno, exactamente no se que les dio su profesora, vos llegaste con el problema de crear una interrupcion del timer0 e ir sumando una variable 1 en 1, y eso es lo que intentamos hacer. No hay distintas formas de hacerlo por interrupcion, hay normalmente 1 sola. Lo que voy a decirte ahora es exactamente sobre INTERRUPCION. Lo que seguro tu profesora llamo interrupcion es leer el flag del modulo, que no es lo mismo.

Lo que yo te digo no es por capricho, es el funcionamiento del microcontrolador. Este seria un formato de programa en ASM, y que lo vas a ver por todos lados:

Código: ASM
  1. ; Fuses/ Config
  2.  
  3.  ;Include
  4.  
  5.  ;Aca nombras los registros necesarios
  6.  
  7.  ;Vectores
  8.         ORG 0x00
  9.         GOTO INICIO
  10.         ORG 0x04
  11.         GOTO INTERRUPCION
  12.  
  13. INICIO:
  14.         ; Aca setup de los modulos: puertos/timers/etc
  15.  
  16.         ; Inicializas los registros que sean necesario hacerlos
  17.  
  18. PRINCIPAL:
  19.  
  20.         ; Programa Principal
  21.         GOTO    PRINCIPAL  ;Principal caracteristica que es un loop infinito es decir esta siempre encerrado
  22.  
  23.  
  24. INTERRUPCION
  25.         ; Aca guardo contexto, es decir W,STATUS,PCLATH para que al final de la interrupcion los vuelva a cargar
  26.  
  27.         ; Aca es el codigo de la interrupcio
  28.  
  29.         ; Vuelvo a dejar W, STATUS y PCLATH como estaban antes de entrar a la interrupcion
  30.         RETFIE

Observaras que si seguis la linea del programa jamas llegaria a "interrupcion", y se quedaria haciendo solo lo de Principal. Y esto es lo que hace el micro, es decir se queda haciendo lo de principal una y otra ves hasta que ocurre una interrupcion.

Cuando ocurre una interrupcion, El PC ( Program Counter) es decir lo que apunta la instruccion a ejecutar pasa a valor 0x04, y es ahi donde entra a la interrupcion realiza esta y luego sale, pero sale y vuelve donde estaba el programa. Suponete algo bastante simple.. Voy a hacer un programa que es erroneo para que veas cual es el error y por que te estoy pidiendo lo que te pido.

Voy a obviar cosas como el setup de modulos para hacerlo lo mas simple posible y vamos a suponer que es un timer el que lo manda a la interupcion ( habilitado/configurado y todo) solo que no lo pongo para llegar rapido al asunto. Este es el programa:

Código: ASM
  1. ORG 0x00
  2.         GOTO INICIO
  3.         ORG 0x04
  4.         GOTO INTERRUPCION
  5.  
  6. INICIO:
  7.  
  8.  
  9.         BCF     STATUS, Z
  10.  
  11. PRINCIPAL:
  12.         BTFSC   STATUS, Z
  13.         BSF     PORTB, 0
  14.         GOTO    PRINCIPAL
  15.  
  16.  
  17. INTERRUPCION
  18.         BSF     STATUS, Z
  19.         RETFIE

Un programa bien realizado ( guardar W,STATUS,etc en la interrupcion) nunca se pondria RB0 a 1. Pero aca si.  Vamos a ir paso por paso para ver que esta pasando.

Comienza el programa, se configuran todos los modulos, se activan las interrupciones, pongo la bandera Z en 0, Y entra en principal, lo cual va a estar preguntando si la bandera es 0 o no, Si es 0 salta, asi que va a estar saltando siempre. Es decir se ecutaria el BTFSC, "salta" es decir el PC se carga con la direccion de memoria donde esta el GOTO, Se ejecuta el GOTO poniendo en el PC la direccion de memoria del BTFSC y se queda alli.

Ahora esta la interrupcion. Supongamos que el GOTO esta en la direccion de memoria 0x100, y es la proxima instruccion a ejecutar por lo cual el PC tiene el valor 0x100, ocurre una interrupcion y el micro guarda esa direccion ( 0x100 ) en un STACK, una pila. (Parecido a lo que ocurre con un CALL) Y pone en el PC la direccion del vector de interrupcion 0x04, Es decir que pasa a ejcutar ese GOTO Interrupcion. Continuando la ejecucion se ejecuta el BSF STATUS,Z y pone a 1 Z, finalmente el RETFIE.

El RETFIE es como un RETURN, pero que ademas pone el bit GIE ( interrupcion global ) en 1, es decir vuelve a habilitar las interrupciones. Lo que hace este RETURN/RETFIE es sacar la ultima direccion de la pila ( 0x100 ) y volverla a poner en el PC.

Genial, Volvimos a nuestra rutina principal, se ejecuta el GOTO principal y llegamos al BTFSC, pero ups, esta ves Z esta en 1, lo cual NO DEBERIA. y pondria RB0 en 1.

Entonces como solucionas esto?, ocurre si guardas todos los bits de STATUS al entrar la interrupcion, haces lo que quieras dentro de la interrupcion donde se van a modificar todos o algunos, y luego cuando vas a salir de la interrupcion recuperas eso que guardaste dejando el STATUS como estaba ANTES de entrar a la interrupcion.

Por que se hace esto ? Se lo hace por que la interrupcion puede ocurrir en cualquier lado.

Que tal si hago mi rutina principal asi?:

Código: ASM
  1. PRINCIPAL:
  2.         BCF     STATUS, Z
  3.         BTFSC   STATUS, Z
  4.         BSF     PORTB, 0
  5.         GOTO    PRINCIPAL

Existe la posibilidad que luego de ejecutarse el BCF, se produzca una interrupcion y aun asi se ponga en 1 RB0.

Lo mismo ocurre con W, pero puede ser aun mas "devastador". Suponete algo asi:

Código: ASM
  1. MOVLW   0x10
  2.         ADDWF   VARIABLE1

Vos pensaras que siempre ocurriria que Variable1 se le van a sumar 0x10, pero si entra a la interrupcion luego de ejecutarse el MOVLW, y al salir de la interrupcion tenes un W en 0x50, le estarias sumando 0x50 y no 0x10.

Por eso mismo se realiza lo que te decia.

Otra de las cosas si te fijas en el "formato" que te di es que no hay una conexion entre el programa de la interrupcion y el programa principal que se ejecuta siempre. Es decir no se llaman entre uno u otro. Son como 2 programas apartes.

Tenes que entender que esto funciona de esta forma:

Se va a estar ejecutando el programa principal continuamente, lo unico que puede sacarlo de ese estado es una interrupcion, lo cual va a ejecutar otro codigo aparte, y luego va a volver a la rutina principal.

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

Lo que decia que tu profesor puede haber llamado interrupcion es simplemente leer el flag del modulo, lo cual no es una interrupcion pero que algunos por desconocimiento le dicen asi. Y el programa se simplifica

Código: ASM
  1. ORG 0x00
  2.         GOTO INICIO
  3.         ORG 0x04
  4.         RETURN
  5.  
  6. INICIO:
  7.  
  8.         ;Configuro modulos
  9.  
  10. PRINCIPAL:
  11.  
  12.         BTFSS   INTCON, TMR0IF  ;Pregunto por el flag del Timer0, si esta en 1 desbordo
  13.         GOTO    PRINCIPAL
  14.         MOVLW   0x00                    ;Cargo el TIMER0
  15.         MOVWF   TMR0
  16.         BCF     INTCON, TMR0IF  ; Limpio flag del TIMER0, asi se cuando rebalso
  17.  
  18.         ;Aca hago lo que tengo que hacer
  19.  
  20.         GOTO    PRINCIPAL       ; Vuelvo al comienzo esperando por que el TMR0 desborde nuevamente

Observaras que en el vector de interrupcion puse un RETURN, esto es una proteccion por si activas sin querer la interrupcion. En este caso solamente estoy leyendo el flag del TIMER0, que se activa cuando desborda. Ese flag se pone a 1 por mas que no esten activadas las interrupciones.

Lo unico que hace el activar la interrupcion es dar paso a ese 1 al nucleo de microcontrolador para que vaya a 0x04, nada mas. Si esta desactivada la interrpucion se bloquea ese camino, pero el flag se sigue poniendo a 1.

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

Para finalizar todo esto esta en el datasheet explicado, esto y mucho mas. Me refiero al comportamiento del micro ante las instrucciones y eventos como las interrupciones.
« Última modificación: 14 de Marzo de 2016, 03:50:42 por KILLERJC »