TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: josearrow en 04 de Marzo de 2007, 16:36:55

Título: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 04 de Marzo de 2007, 16:36:55
Hola,

Estoy intentando que una interrupcion salte cuando se gire el timer1.
El contador si va contando, porque lo veo en el simulador, pero cuando se gira el TMR1H, no va a la interrupcion.
Estoy usando un pic16f88 y cristal externo de 16Mhz.

;*****************************************************************************
; Program start
;*****************************************************************************
                        ORG     0          ; RESET vector location
RESET                   goto    START
;*****************************************************************************
; Interrupt vector
;*****************************************************************************
                        ORG     4              ; interrupt vector location
;*****************************************************************************
; Interrupt Routine.
;*****************************************************************************
Interrupt               movwf   intWsave
                        movf    STATUS,W
                        movwf   intStatusSave
                        bcf     PIR1,TMR1IF      ; Clear the timer interrupt
                        incf    tmr1h,F            ; and advance high counter.
                        movf    intStatusSave,W
                        movwf   STATUS
                        swapf   intWsave,F
                        swapf   intWsave,W
                        retfie
;*****************************************************************************

;*****************************************************************************
; Program start
;*****************************************************************************
START                   clrf    STATUS           ; Clear Status
                        clrf    INTCON           ; Disable interrupts
                        clrf    PCLATH           ; Keep in lower KByte
                        clrf    PORTA            ; Clear ports
                        clrf    PORTB

                     bsf     STATUS,RP0       ;Select bank 1
                     clrf   ANSEL           ;All pins are Digital
                 ;   bsf       OSCCON,6        ;Set oscilator to 4Mhz
                 ;   bsf       OSCCON,5
                     movlw   H'07'
                     movwf   CMCON           ;Turn off comparators
                     movlw   B'00010000'      ; i/o port value
                        movwf   TRISA
                        movlw   B'00000001'      ; i/o port value
                        movwf   TRISB
                        movlw   B'10000101'      ; pullup off, prescaler=64,
                        movwf   OPTION_REG       ; Set the OPTION register
                        bcf     STATUS, RP0      ; Select bank 0
                        movlw   b'00100001'     ;Prescaler=1:4(1us)  TMR1=ON
                        movwf   T1CON           ;configura T1CON

                        bsf     PIR1,TMR1IF    ; unmask the timer0 interrupt
                        bsf     PIE1,TMR1IE       ; and enable interrupt.

                        clrf    tmr1h            ; clear high timer
                        clrf    TMR1             ; clear timer
                       
LOOP                    btfsc   INP
                        goto    LOOP             ; Wait for pulse Low
waitHigh                btfss   INP              ;
                        goto    waitHigh         ; Wait for pulse high
.....
....
...

Hay algo que se me olvida...
Espero que me podais ayudar.
Gracias.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 04 de Marzo de 2007, 17:00:01
El problema es que tenes que habilitar las interrupciones globales!
Agrega bsf INTCON,GIE.
Eso habilita todas las interrupciones configuradas.

Ojo con esto:

bsf     PIR1,TMR1IF    ; unmask the timer0 interrupt

Yo no lo pondria ahi, excepto que quieras forzar que se produzca por primera vez la interrupcion del timer sin esperar tiempo.

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 04 de Marzo de 2007, 17:19:01
Gracias bruno!!.

Tambien he añadido, el periferico, PEIE:

                        movlw   b'00100001'     ;Prescaler=1:4(1us)  TMR1=ON
                        movwf   T1CON           ;configura T1CON
                        bsf     INTCON,GIE
                        bsf     INTCON,PEIE
                        bsf     STATUS, RP0      ; Select bank 1
                        bsf     PIR1,TMR1IF    ; unmask the timer1 interrupt
                        bsf     PIE1,TMR1IE       ; and enable interrupt.
                        bcf     STATUS, RP0      ; Select bank 0
Ahora funciona. Donde lo pondrias?
Gracias.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 04 de Marzo de 2007, 17:52:12
josearrow verificá que el PIE y el PIR no estan en la misma página en el pic que estas usando.


Deberás setear el RP0 del status antes de acceder al PIE y luego borrarlo para volver a la página 0.

Saludos
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 04 de Marzo de 2007, 19:33:53
Maunix ahí te paso otro problemita. Segui su consejo.

Yo no lo pondría en ningun lado al bsf PIR1,TMR1IF.
El PIC se encarga de setearlo automaticamente cuando se desborda el contador alto del TIMER1 y eso es lo que produce la interrupcion del TIMER1 si el INTCON,GIE esta seteado tambien. Lo que no hace el PIC es limpiarlo automaticamente. Por eso debes limpiarlo manualmente (fijate que tenes puesto bcf PIR1,TMR1IF)

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 05 de Marzo de 2007, 10:42:21
Hola,

Si, lo puse así.

                        bcf     STATUS, RP0      ; Select bank 0
                       
                        movlw   b'00100001'      ;Prescaler=1:4(1us) TMR1=ON
                        movwf   T1CON            ;config T1CON
                        bsf     INTCON,GIE
                        bsf     INTCON,PEIE
                        bsf     STATUS, RP0      ; Select bank 1
                        bsf     PIR1,TMR1IF      ; unmask the timer0 interrupt
                        bsf     PIE1,TMR1IE      ; and enable interrupt.
                        bcf     STATUS, RP0      ; Select bank 0
                       

                        clrf    tmr1h            ; clear high timer
                        clrf    TMR1L            ; clear timer
                        clrf    TMR1H            ; clear timer

Lo que no se, es si esta en el mismo banco el pie1 y pir1.
sabeis?. El pic es un 16f88
SAludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 05 de Marzo de 2007, 11:14:19
En el datasheet figura cada registro, direccion de memoria y banco.

Todos los registros desde 0x00 a 0x7F banco 0
Todos los registros desde 0x80 a 0xFF banco 1
...

Sino podes poner antes de trabajar con un registro BANKSEL lo que asegura que el mpasm cambie al banco correcto.

Ej:

bcf     STATUS, RP0      ; Select bank 0
                       
                        movlw   b'00100001'      ;Prescaler=1:4(1us) TMR1=ON
                        movwf   T1CON            ;config T1CON
                        bsf     INTCON,GIE
                        bsf     INTCON,PEIE
                        bsf     STATUS, RP0      ; Select bank 1
                        BANKSEL PIR1
                        bsf     PIR1,TMR1IF      ; unmask the timer0 interrupt
                        BANKSEL PIE1
                        bsf     PIE1,TMR1IE      ; and enable interrupt.
                        bcf     STATUS, RP0      ; Select bank 0


Ojo! Es lindo usarlo, pero recorda que el BANKSEL afecta los bits RP0 y RP1 por lo que hay que tener extremo cuidado, ademas que genera mas codigo del que muchas veces se necesita.

Sigo insistiendo en que saques esta linea:                         bsf     PIR1,TMR1IF

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 05 de Marzo de 2007, 12:51:47
Gracias Bruno,

Entonces lo dejo así, para más facilidad. Lo he probado con el simulador, y parece que va bien. Antes se ponia el pir1 a '1' cuando habia acarreo, ahora no se mueve, parece que funciona igualmente.
Otra cosa, para desactivar el timer0, tengo que quitar la linea del option_reg simplemente o hace falta tenerlo ahi ya sea por la configuracion de los pullups o algo similar??.

Saludos.               


                       START                   clrf    STATUS           ; Clear Status
                        clrf    INTCON           ; Disable interrupts
                        clrf    PCLATH           ; Keep in lower KByte
                        clrf    PORTA            ; Clear ports
                        clrf    PORTB

                        bsf     STATUS,RP0       ; Select bank 1
                        clrf   ANSEL           ; All pins are Digital
                        movlw   H'07'
                        movwf   CMCON           ; Turn off comparators
                        movlw   B'00010000'      ; i/o port value
                        movwf   TRISA
                        movlw   B'00000001'      ; i/o port value
                        movwf   TRISB
                        movlw   B'10000001'      ; pullup off, prescaler=4,
                        movwf   OPTION_REG       ; Set the OPTION register
                        bcf     STATUS, RP0      ; Select bank 0
                       
                        movlw   b'00100001'      ; Prescaler=1:4(1us) TMR1=ON
                        movwf   T1CON            ; config T1CON
                        bsf     INTCON,GIE
                        bsf     INTCON,PEIE
                     ;  bsf     PIR1,TMR1IF      ; unmask the timer1 interrupt (bank0)
                        bsf     STATUS, RP0      ; Select bank 1
                        bsf     PIE1,TMR1IE      ; and enable interrupt.
                        bcf     STATUS, RP0      ; Select bank 0

firstLow                btfsc   INP              ; Wait for first ignition
                        goto    firstLow         ; pulse before starting
firstHigh               btfss   INP              ; the retard checking.
                        goto    firstHigh                       

                        clrf    tmr1h            ; clear high timer
                        clrf    TMR1L            ; clear timer
                        clrf    TMR1H            ; clear timer

                       
LOOP                    btfsc   INP
                        goto    LOOP             ; Wait for Ignition Low
waitHigh                btfss   INP              ;
                        goto    waitHigh         ; Wait for Ignition high
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 05 de Marzo de 2007, 16:16:34
El timer0 no tiene deshabilitador.  Lo puedes activar como "contador" si quieres que no te moleste pero contará los pulsos que le ingresen por el pin habilitado a tal fin en tu pic y esto tampoco no te lo recomiendo.

Si necesitas 'detener' el timer, entonces el timer0 no es tu elección, deberas elegir otro timer.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 05 de Marzo de 2007, 18:56:46
Hola Mauricio,

Es que el timer0, no lo uso para nada, no es por ningun motivo. Estoy usando el timer1, además con la interrupcion tengo 24bits, asi que no me hace falta para nada el timer0. A mi no me importa que esté contando, per decía de desactivarlo ya que no lo uso.

He estado intentando dejar el timerl a un valor fijo  y que solo cuente 100 conteos y salte el alto. Poniendo 156 en el timer1L, asi cuenta 100 veces, con 1:4  prescaler y 16Mhz de crystal. Tengo 100us en cada incremento del timer1H. Pero no soy capaz de encontrar una forma eficiente.

START               clrf    STATUS           ; Clear Status
                        clrf    INTCON           ; Disable interrupts
                        clrf    PCLATH           ; Keep in lower KByte
                        clrf    PORTA            ; Clear ports
                        clrf    PORTB

                        bsf     STATUS,RP0       ; Select bank 1
                        clrf   ANSEL           ; All pins are Digital
                        movlw   H'07'
                        movwf   CMCON           ; Turn off comparators
                        movlw   B'00010000'      ; i/o port value
                        movwf   TRISA
                        movlw   B'00000001'      ; i/o port value
                        movwf   TRISB
                   ;     movlw   B'10000001'      ; pullup off, prescaler=4,
                   ;     movwf   OPTION_REG       ; Set the OPTION register
                        bcf     STATUS, RP0      ; Select bank 0
                       
                        movlw   b'00100001'      ; Prescaler=1:4(1us) TMR1=ON
                        movwf   T1CON            ; config T1CON
                        bsf     INTCON,GIE
                        bsf     INTCON,PEIE
                     ;  bsf     PIR1,TMR1IF      ; unmask the timer1 interrupt (bank0)
                        bsf     STATUS, RP0      ; Select bank 1
                        bsf     PIE1,TMR1IE      ; and enable interrupt.
                        bcf     STATUS, RP0      ; Select bank 0

                        clrf    tmr1h            ; clear high timer
                        clrf    TMR1L            ; clear timer
                        clrf    TMR1H            ; clear timer                   
                        ;
                        ;       100uS loop time
                        ;       16MHz clock / 4 = 4MHz instruction cycle - 0,25us
                        ;       prescaler set to divide by 4
                        ;       preset TMR1 = 256, when = 0  =  100uS
                        ;       156 to 255 = 100 x 0,25us x 4(prescaler) = 100 us
                        ;
                        movlw .156   ; fixed timer1 to 156
                        movwf TMR1L               
                   
LOOP                    btfsc   INP
                        goto    LOOP             ; Wait for pulse Low
waitHigh                btfss   INP              ;
                        goto    waitHigh         ; Wait for pulse high

El problema es que la primera vez lo fijo bien, pero una vez en el loop, cuando espera pulso low, si desborda una vez ya empieza en 0, y no en 156, yo quiero que siempre cuente desde 156 a 256, para ir incrementando el TIMER1H en incrementos de 100us. Supongo que habría que poner tanto a la hora de esperar el low como el high, un btfss para ver si el timerl = 0 y si es igual a 0 fijar a 156 para que siga contando a partir de ese valor...
Espero que me podais dar alguna idea, quizas hay alguna forma tipica de hacer esto, yo soy bastante novato aún...
Por cierto, como ves, he quitado las lineas del option_reg y asi el timer0 no hacia nada, y el programa parecía ir bien, así que no se si lo dejo o lo quito, por lo que me has comentado antes... Yo el timer0 no lo quiero para nada.

Gracias por la ayuda.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 05 de Marzo de 2007, 23:32:12
Lo que pasa es que estas queriendo usar un timer para lo cual no fue concebido.  Si quieres hacer eso de que cada 100 useg se incremente otra variable, te sugiero SI entonces uses el TIMER0 con un prescaler en caso de ser necesario (digamos si cambias el clock por ejemplo).

No le veo mayor sentido al uso que le quieres dar al timer1 de esa forma.

Una forma ideal desatendida de contar N microsegundos es usar el PR2 del Timer2.  Cuando el timer2 llega a la cuenta PR2, se enciende el flag TMR2IF y ahí puedes hacer lo que quieras, además el TIMER2 se pone a 0 solo.  Para bases de tiempo, es ideal.

Saludos
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 06 de Marzo de 2007, 10:43:33
Hola,

El caso es que el programa estaba hecho para 4Mhz, y con prescaler de 64.
El problema es que yo quiero usar una interrupcion para poder escribir directamente mediante rs232 en la flash.
Este programa cuenta frencuencia, que va desde 2hz a 265hz, y segun los conteos que haga, mirará en una posicion de una tabla y hará ese retardo, prescrito en la tabla. Lo que quiero hacer es poder mandar tablas directamente desde el pc, sin tener que enviar el programa completo.
El 16f88 tiene la posibilidad de escribir en la flash. El programa funcionaba con 4Mhz y 64 prescaler, siendo cada instruccion de 1us. Para implementar esto, me recomendaron que aumentara el oscilador a 16Mhz, y que si el prescaler era entre 4 y 8 sería ok! para poder hacer esto mejor.
Por ello al usar 16Mhz y 1:4 prescaler, tengo 1us incrementos por el contador, si no fijara el contador para que de saltos de 100us o 50us, un valor aceptable, la tabla sería infinita, ya que desde 2hz a 265hz habría infinidad de conteos intermedios...
Por ello la idea es ajustar de alguna forma el contador para que tenga saltos de 100us, con lo que me salen 160 valores en la tabla, creo recordar....
El problema es que al ajustar el timer1 a que el low cuento 100 veces y salte el timerH, solo tendría 256 x 100us cada conteo, que no me da para 2hz, por eso usé la interrupcion, asi si es posible.
Si uso el timer2, tengo el problema de que al ser de 8bits, aún usando una interrupcion, sería de 16bits y no me da para 2hz, de ahi a usar el timer1 ampliado a 24bits. PEro claro tengo q poder ajustar para que cada incremento del high sea de 100us...

A ver si me podeis aconsejar que hacer...
Gracias por todo.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 06 de Marzo de 2007, 11:43:26
Mi consejo es que uses el Timer2 con el PR2 y que uses una variable de 16 bits como contador extra y te "olvidas" del timer2, solo sabrás que cada 100useg se te encenderá el TMR2IF (y aquí ya decides tu si usas o no interrupción).

Esa variable de 16 bits te da para 65535 x 100usec = 6,5 seg , osea más que suficiente.

Saludos
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 06 de Marzo de 2007, 12:03:27
Gracias,

Ok, si es posible hacer eso por mi perfecto.
El caso es que no sabia que se podia hacer un contador de 16bits con una variable de 16bits...

El tema de la interrupción, yo creia que es necesaria para una vez que se acarrea un contador de 8bits, se aumente una variable en 1, asi cada vez... pero ni sabia que hay variables de 16bits... Si es así, por mi se quita la interrupcion porque mejor sin ella, no crees?.

Si es posible, y abusando de tu amabilidad, me gustaría que me explicaras más profundamente lo que tengo que ir haciendo, o algun ejemplo que haga algo parecido con este timer2. Yo soy un poco novato.

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 06 de Marzo de 2007, 12:41:25
El caso es que no sabia que se podia hacer un contador de 16bits con una variable de 16bits...

El tema de la interrupción, yo creia que es necesaria para una vez que se acarrea un contador de 8bits, se aumente una variable en 1, asi cada vez... pero ni sabia que hay variables de 16bits... Si es así, por mi se quita la interrupcion porque mejor sin ella, no crees?.
En assembler puedes hacer variables del tamaño que tu quieras, de hecho tienes el máximo control sobre tu microcontrolador.

De hecho para hacer variables de 16 bits, 24 bits o demás, solo te preocupas porque tengas tantos bytes como necesites.  Hasta si quieres le puedes poner el mismo nombre.

Ej:


MIVAR16 equ 0x20
MIVAR24 equ 0x22
MIVAR8   equ 0x25


MIVAR16 ocupará de 0x20 a 0x21
MIVAR24 ocupará 0x22, 0x23 y 0x24
MIVAR8 ocupará 0x25

Luego tu por software debes decidir como armar la variable, es decir qué byte dentro de la variable es el más significativo y cual el menos significativo.  Yo suelo usar el LittleEndian que es que el byte que ocupa la posición de memoria más baja es el menos significativo. Es el formato más común usado en las PCs porque es el que usa intel.

Entonces para acceder al byte menos significativo o LOW de MIVAR16 haces


     movlw    .120              ;un dato cualquiera
    movwf    MIVAR16+0


Para acceder al byte HIGH haces


    movlw  .25          ;un dato cualquiera
    movwf    MIVAR16+1


Idem con el de 24 bits


Si es posible, y abusando de tu amabilidad, me gustaría que me explicaras más profundamente lo que tengo que ir haciendo, o algun ejemplo que haga algo parecido con este timer2. Yo soy un poco novato.

Por supuesto, es bastante simple


    bcf         STATUS,RP0
    movlw       b'01111011'             ;Postscaler 1:16
    movwf       T2CON                   ;Prescaler  1:16

    bsf         STATUS,RP0
    movlw       0x64
    movwf       PR2
    bcf         STATUS,RP0

    bsf         T2CON,TMR2ON



Tu puedes cambiar la configuración de T2CON (revisa el datasheet) para ajustar los prescalers como quieras.

Cuando TMR2 sea igual a 100dec o 64hex , el TMR2IF se encenderá.

Saludos
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 06 de Marzo de 2007, 16:23:04
Gracias Mauricio por las explicaciones, pero claro definir esas variables no es lo no veía, es de como hacer los incrementos en el low cada vez que el timer 2 gire, y como hacer en el high para incrementar en 1, cada vez que el low gire...

Yo no entiendo mucho, pero creo que para esto uso la interrupcion, como me dijiste de quitarla, como podría ir incrementado cada variable?.

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 06 de Marzo de 2007, 17:04:32
Gracias Mauricio por las explicaciones, pero claro definir esas variables no es lo no veía, es de como hacer los incrementos en el low cada vez que el timer 2 gire, y como hacer en el high para incrementar en 1, cada vez que el low gire...

Yo no entiendo mucho, pero creo que para esto uso la interrupcion, como me dijiste de quitarla, como podría ir incrementado cada variable?.

Yo no te dije de quitar la interrupción. te dije que puedes usarla o no, es a tu gusto.  Lo que sí te dije es que no uses el timer1 de esa forma. 

Para hacer los incrementos en la variable de 16 bits, haces algo así.  Cuando se enciende el TMR2IF tu lo pudes detectar directamente haciendo un loop o bien lo haces con una interrupción habilitada.  Entonces al habilitarse haces lo siguiente:


    bcf     PIR1,TMR2IF
    incf    MIVAR16+0,f
    btfss   STATUS,C
    goto    _CONTINUA
    incf    MIVAR16+1,f

_CONTINUA:
   ...

Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 07 de Marzo de 2007, 07:07:50
Gracias Mauricio,

El timer2 ya esta trabajando.
El problema es la interrupcion, no soy capaz de hacer que cuando la variable tmr2hL = 0 incremente en 1 el valor de la variable tmr2hH. Si pongo btfss si es 0 salta y si es 1 tambien, y si pongo btfsc, no salta ni siendo 0 ni siendo 1.

Alguna forma de que solo salte la siguiente instruccion si es 0 el valor de la variable tmer2hL.
Te pongo la interrupción

Interrupt           movwf   intWsave
                        movf    STATUS,W
                        movwf   intStatusSave
                        bcf     PIR1,TMR2IF       ; Clear the timer2 interrupt
                        incf    tmr2hL,F          ; and advance high counter LOW.
                        btfss   STATUS,C
                        goto    jump
                        incf    tmr2hH,F          ; and advance high counter HIGH.
jump                 movf    intStatusSave,W
                        movwf   STATUS
                        swapf   intWsave,F
                        swapf   intWsave,W
                        retfie

La configuracion del timer2 la dejé asi, creo que no me dejé nada, funciona bien en teoría en el simulador, cuando llega a 100 conteos se resetea el TMR2, pasa a la interrupcion aumenta el tmr2hL y sigue contando... pero una vez se resetea el tmr2hL no soy capaz que se vaya incrementando el tmr2hH.

Creo que no se me escapa nada te dejo aqui :

START               clrf    STATUS           ; Clear Status
                        clrf    INTCON           ; Disable interrupts
                        clrf    PCLATH           ; Keep in lower KByte
                        clrf    PORTA            ; Clear ports
                        clrf    PORTB

                        bsf     STATUS,RP0       ; Select bank 1
                        clrf   ANSEL           ; All pins are Digital
                        movlw   H'07'
                        movwf   CMCON           ; Turn off comparators
                        movlw   B'00010000'      ; i/o port value
                        movwf   TRISA
                        movlw   B'00000001'      ; i/o port value
                        movwf   TRISB
                        movlw   B'10000101'      ; pullup off, prescaler=64,
                        movwf   OPTION_REG       ; Set the OPTION register
                        bcf     STATUS, RP0      ; Select bank 0
                       
                        movlw   b'00000101'      ; Prescaler=1:4(1us) TMR2=ON
                        movwf   T2CON            ; config T2CON
                        bsf     INTCON,GIE       ; Enable Global Interrupt
                        bsf     INTCON,PEIE      ; and peripheral
                        bsf     STATUS, RP0      ; Select bank 1
                        bsf     PIR1,TMR2IF      ; unmask the timer2 interrupt
                        bsf     PIE1,TMR2IE      ; and enable interrupt.
                        movlw   0x64             ; Fix PR2 to 100 counts
                        movwf   PR2              ; So TMR2 count until 100us
                        bcf     STATUS, RP0      ; Select bank 0

Gracias por la ayuda.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 07 de Marzo de 2007, 12:37:13
El problema es la interrupcion, no soy capaz de hacer que cuando la variable tmr2hL = 0 incremente en 1 el valor de la variable tmr2hH. Si pongo btfss si es 0 salta y si es 1 tambien, y si pongo btfsc, no salta ni siendo 0 ni siendo 1.

Alguna forma de que solo salte la siguiente instruccion si es 0 el valor de la variable tmer2hL.
                        incfsz    tmr2hL,F          ; and advance high counter LOW.
                        goto    jump
                        incf    tmr2hH,F          ; and advance high counter HIGH.
jump                 movf    intStatusSave,W
                        movwf   STATUS
                        swapf   intWsave,F
                        swapf   intWsave,W
                        retfie

P.D. Perdona que no te ayude mas, pero me quedé atrasado en el hilo y leer 15 posts...ufff!
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 07 de Marzo de 2007, 13:03:37
Bruno,

Ahora si funciona correctamente!!, muchas gracias, me ayudasteis mucho, y he aprendido bastante con el simulador.
Ahora tengo que cuadrar los límites de corte, para esto no habrá problema, y el tema de las tablas, que si me surge algo ya lo comentaré.
Muchas gracias a ti y a Mauricio. :-/
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 07 de Marzo de 2007, 13:21:09
De nada! Ahora deslumbranos con el invento.
Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 07 de Marzo de 2007, 15:56:36
Hola, estoy intentando hacer un retardo fijo, segun el valor del contador.

De forma que :

(valor contador) *( tiempo instruccion*tiempo queda interacion)/ us conteo contador = 0,06*contador
Sería valor contador *0,25us*4/100us, esto es 0,25 de instruccion del pic*4 porque esta interacion de retardo gasta 4 instrucciones.
ASi 1/100 = 0,01 *k *valor del contador. Por ello tengo que multiplicar, ese k debe ser k=6.

fixed35              bcf    03,0
                        rlf    perl,F
                        rlf    perh,F
                        incf    perl,F          ; Less than 3509 rpm
                        incf    perh,F
bucle2                  nop
                        decfsz  perl,F
                        goto    bucle2
                        decfsz  perh,F
                        goto    bucle2

La idea es retardar el valor de tiempo que recoge el contador * por un valor fijo, porque quiero que haga como si dijeramos un 80% del valor del contador de retardo.

Ese bucle gasta 4 instruccion cada interaccion, las tres primeras lineas se que hacen k=2, vamos que multiplica el valor del contador x 2, lo que quiero es de la misma forma que sea *6 y no *2.

No entiendo muy bien lo que hace bcf 3,0

Si me podeis explicar que hace esa linea y aconsejarme como poder hacer eso.
Gracias.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 07 de Marzo de 2007, 21:39:19
No entiendo muy bien lo que hace bcf 3,0
Si me podeis explicar que hace esa linea y aconsejarme como poder hacer eso.
Gracias.

Para comprender lo que hace el bcf 3,0 o bien más conocido como bcf STATUS,C deberías mirar esto:

http://www.todopic.com.ar/foros/index.php?topic=14812.msg91151#msg91151

perl y perh están funcionando como un registro de 16 bits(es decir, cada uno aporta 8 bits. perl los 8 mas bajos, perh los 8 mas altos).
Si te fijas, lo que hacen las rlf ahí es multiplicar el registro entero(perh perl) por 2.

Con respeto a lo otro, no sé qué querés hacer. ¿0,06? ¿De dónde sale eso? ¿De 60s/100? Tal vez si explicaras lo que estás haciendo y un poco mas globalmente lo que necesitás nos ubicaríamos más fácil.

Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 08 de Marzo de 2007, 06:39:11
Hola Bruno,

bcf 3,0 pone a 0 el bit status para que sea *2 exactamente y luego con el rlf rota hacia la izquierda y *2, muy buen post!! está muy bien explicado gracias!!!.
Yo lo que quiero es multiplicar por 6. Asi que si lo pongo 2 veces estaré multiplicando *4, y si pongo otro más ya sería 8, como podría hacerlo por 6?. Yo suponia que se puede hacer repitiendo el rlf, pero no se si habría una forma más rápida de hacer esto en menos líneas...

La idea es simple, es querer hacer un retardo fijo, mirando el valor del contador total perl y perh, multiplicando por un valor fijo, con lo cual, sea cual sea el valor del contador en relacion a grados sería siempre el mismo retardo. Si en 360º tarda X tiempo (valor de contadores), para 20º menos, 21.6º/360º= 0.06. Asi que es multiplicar 0,06 * el valor del contador.
Se saca de tiempo en hacer la interaccion 1us (4 instrucciones de reloj* us en hacer una instruccion, 4*0.25=1).
1*k*valor contador/incremento contador (100us). Así 1/100*k*valor contador. 0,001*k*contador.
k=6, 0,006*contador. Ya tendría ese valor, solo me hace falta multiplicar *6 para que haga ese retardo fijo, siempre a los mismos grados será, sea cual sea el valor del contador... Espero que ahora me entiendas.

Asi que supongo que poniendo:

fixed35              bcf    03,0
                        rlf    perl,F           ;
                        rlf    perh,F          ; *2
                        rlf    perl,F           ;
                        rlf    perh,F          ;*4
                        rlf    perl,F           ;
                        rlf    perh,F          ;*8

                        incf    perl,F          ; Less than 3509 rpm
                        incf    perh,F
bucle2                  nop
                        decfsz  perl,F
                        goto    bucle2
                        decfsz  perh,F
                        goto    bucle2

El problema es que yo quiero *6, y no se si hay alguna forma de hacerlo en menos intrucciones. *4 retardaría 14.4º, y *8 retardaría (0.01*8)*360= 28.8º demasiados.
Ahora me quedó muy claro como funciona el rlf, y no sabia que bcf 03,0 era referente a status,C

Gracias.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 08 de Marzo de 2007, 12:24:01
El problema es que yo quiero *6, y no se si hay alguna forma de hacerlo en menos intrucciones. *4 retardaría 14.4º, y *8 retardaría (0.01*8)*360= 28.8º demasiados.

¿Menos instrucciones?

Para multiplicar por 6, lo mas simple es recurrir a registros temporales para almacenar el dato.
Podemos decir que: registro*6 = (registro+registro)*3=(registro+registro+registro)*2=registro*2+registro*4

Como "no sé" multiplicar fácilmente ni por 6 ni por 3, me quedo con alguna de las 2 últimas igualdades porque sé sumar y multiplicar por 2. Finalmente selecciono la última porque es más rápido multiplicar por 2 a un registro que sumarlo a si mísmo.

Entonces podemos hacer asi:

                        bcf         STATUS,C  ;registro * 2
                        rlf          perl,F
                        rlf          perh,F

                        movf     perl,W        ;guardo entonces registro * 2 temporalmente
                        movwf   Templ
                        movf     perh,W
                        movwf   Temph

                        bcf        STATUS,C ;registro * 4
                        rlf         perl,F
                        rlf         perh,F               
                         
                        movf     Templ,W ;registro * 2 + registro * 4
                        addwf    perl,F
                        btfsc      STATUS,C
                        incf        perh,F
                        movf      Temph,W
                        addwf     perh,F

El problema con esta rutinaes que arrastra un error LINEAL por tardar más tiempo en calcular el valor del registro.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 08 de Marzo de 2007, 19:27:13
Hola Bruno,

Gracias por el consejo, he estado pensando con estos consejos y creo que la mejor forma es hacer esto.
Añado dos nop al loop the retardo, con lo cual cada interacción serían 6 instrucciones, 6*0,25 = 1,5/100 *k(k=4) = 0,06.
Asi quedaría:

fixed35              bcf    03,0
                        rlf    perl,F           ;
                        rlf    perh,F          ; *2
                        rlf    perl,F           ;
                        rlf    perh,F          ;*4
                        incf    perl,F         ; Less than 3509 rpm
                        incf    perh,F
bucle2               nop
                        nop
                        nop
                        decfsz  perl,F
                        goto    bucle2
                        decfsz  perh,F
                        goto    bucle2

Referente al error lineal, podría contar el número de instrucciones que pasan desde que salta el loop the conteo, y restarle al valor final, que te parece?.

Gracias, un saludo.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: BrunoF en 08 de Marzo de 2007, 19:42:27
Hola

Ojo que cuando haces dos rotaciones seguidas, antes de cada rotacion debes asegurarte que STATUS,C valga 0 para que no "ensucie" la multiplicacion!.

fixed35              bcf    03,0
                        rlf    perl,F           ;
                        rlf    perh,F          ; *2
                         bcf    03,0
                        rlf    perl,F           ;
                        rlf    perh,F          ;*4

Es la unica forma de garantizar que la multiplicacion sea por 2 exacto.
Me parece bien la idea, pero no entiendo como pensas lograr "restarselo al valor final".

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 09 de Marzo de 2007, 13:31:01
Bruno,

Si, tienes razón, faltaba limpiar el status, para asegurarnos que al girarlo no sea multiplicado por 2 perfectamente.
Referente al ajuste del error lineal, tienes toda la razón, no es posible, pero realmente he estado viendo el error máximo y es totalmente aceptable, asi que no hay problema.

Ahora estoy liado con las tablas. Y hay un problema. He estado leyendo de como usar el PCL y el PCLATH. Y más o menos lo entiendo, pero hay un problemilla. Ahora los valores que voy a usar no me caben en 1byte, necesitan ser de 2bytes, ya que podrian ser valores del orden de 1500 o 2000. Son 136 lineas cada tabla. Espero que me puedas decir, como hacerlo más o menos, con valores asi, no he visto nada.

En mi codigo, cargo la posición de la tabla en el toffset, llamo por un goto a la tabla, coge el valor de la posicion y lo paso a una variable. Este codigo funcionaba bien en f84A, ahora con el f88 y más crystal, con todos los ajustes ya no me cabe en un byte. Antes era así.

movwf   toffset          ; store offset
.
.
goto      igno

ign0      call    ignition0               ; read from table 0
.
.
ORG     0x100                            ; This table is locate in code page 1!!!!
ignition0                      ; Used as address lable to look-up table
    movlw   HIGH ignition0           ; This table is in Page 1
    movwf   PCLATH                    ; of the memory so set latch!
    movfw   toffset                       ; Get table offset, max 212
    addwf   PCL,F                    ; Add offset to PCL to jump into table
    RETLW   0x4B      ; 75 
    RETLW   0x4C      ; 76 
    RETLW   0x4D      ; 77
    RETLW   0x4F      ; 79
    RETLW   0x50      ; 80 
    RETLW   0x51      ; 81 
    RETLW   0x51      ; 81 
    RETLW   0x51      ; 81 
    RETLW   0x51      ; 81 
    RETLW   0x4F      ; 79 
    RETLW   0x4D      ; 77 
    RETLW   0x4A      ; 74 
    RETLW   0x47      ; 71 

Si sabes algun ejemplo o algun link donde expliquen de hacerlo para valores que ocupen 2bytes.
Gracias.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 13 de Marzo de 2007, 19:46:15
¿Cuando hablas de valores que ocupan 1 byte o 2, te refieres a que la tabla tendrá más de 1000 valores o a que los valores de la tabla debieran ser números de 2 bytes?

Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 14 de Marzo de 2007, 18:27:20
Mauricio,

Ya lo solventé. Eran tablas de 136 valores.  Y los valores pues llegan hasta D'2000' más o menos. Lo que he hecho es usar 2 tablas una con valorL y otra con valorH. Así que ahora uso el mismo offset para ver el valor en cada parte del low y high...

El problema que tengo es que al fijar el PR2 hasta 100. Y usar 2 variables en una interrupcion para tener un contador de 16bits con incrementos de 100us, cuando el programa entra en el loop de retardo( el programa usa el contador para sacar la freq de los pulsos y segun el contador entra en una tabla, coge el valor y retarda ese valor), pues al entrar en el loop the retardar el valor de la tabla, pues usando decfsz, drececiendo el valor hasta 0, pues si el valor es de 1000, pues habrá por lo menos 9 interrupciones, en las cuales se gastan 4us, y claro cuando vuelve al loop de retardo, pues en realidad  retarda esos 1000 + el valor gastado por la interrupcion. ASi que esto es bastante jodido de cuadrar...

Lo unico que se me ocurre es usar un contador para hacer el retardo, ya que es independiente uno del otro, si sabeis otra forma de poder hacerlo ya me contais.

Gracias por la ayuda.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 15 de Marzo de 2007, 00:57:48
Si entendí bien, tienes preocupación de que por cada ciclo de 100useg se te pasen 3 o 4 de más por las comparaciónes.   Si estoy en lo cierto y esta es tu preocupación, usar el PR2 a un valor fijo hace que el TMR2 vuelve a 0 solo independientemente de si atendiste o no a la interrupción.  Tus temporizaciónes serán exactas.  Esas instrucciones de más de las que hablas solo estarán en la última vuelta.

Si tienes que hacer 10 ciclos, solo estarán en el 10mo ciclo.

Saludos
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 16 de Marzo de 2007, 05:35:22
No no,

El problema es que mi programa llega un momento en que hace un delay, del tiempo que haya cogido de la tabla. Y como el timer2 solo cuenta hasta 100, que son 100us, y cada vez que llega salta la interrupcion para incrementar las variables de conteo de 16bits, pues cuando esta haciendo el delay y el valor es alto 1000 por ejemplo, pues salta varias veces la interrupcion, porque mientras hace ese delay el contador sigue contando y cada vez que salta la interrupcion, pues pierde un tiempo en el que no esta haciendo el delay, cuando vuelve a la instruccion de delay, sigue... Y por tanto retarda el valor de la tabla + las veces q haya saltado la interrupcion * el tiempo que gasta cada interrupcion. Y esto es dificil de controlar...
Asi que habrá que usar un timer para hacer el retardo.

Saludos.
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: maunix en 16 de Marzo de 2007, 12:53:41
La verdad josé, he leído y releído tu post 4 veces y no entiendo tu problema  :?
Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 16 de Marzo de 2007, 19:20:07
Voy a intentar explicarlo otra vez.

Mi programa lo que hace es leer el pin3 y el contador hace conteos para saber la frecuencia de esos pulsos. Una vez sabe la frecuencia entre dos pulsos, que seran X conteos. Con ese valor entra en una tabla, saca un valor a retardar y se inicia un bucle de retardo, cuando retarda ese tiempo de la tabla sale, y empieza otra vez con el valor del siguente pulso...

Bien, el problema viene, una vez que uso crystal 16Mhz, con prescaler 1:4. Y querer que el contador haga incrementos de 100us, ya que sino la tabla sería inmensa!. Bien, esto lo consigo fijando el PR2 a 100, y usando el timer2, hace 100 conteos y acarrea, esos 100 conteos son 100us Bien, ahora para tener un contador de esos incrementos de 100us, uso una interrupcion en la cual, me guardará el valor de acarreos del timer2 de 8bits, usando una segunda variable consigo poder contar 16bits dentro de la misma interrupcion, por tanto, una vez que cuenta 100, el programa abandona lo que esté haciendo y salta la interrupcion, incrementa la variable,... asi siempre.

Mi problema está en que cuando acaba de contar entre dos pulsos, digamos que tenemos variableLow = 50 y variableHigh=1. Entonces entra en una tabla con esos valores, el numero de conteos es el valor de entrada. Bien coge el valor de esa posicion, que será el valor a retardar para esa frecuencia ok?, bien... Ahora solo nos queda hacer un bucle para retardar el valor de la tabla para esa frecuencia. Antes de hacerlo le resto el tiempo gastado en hacer todos los calculos, y empiezo el retardo asi:

doRetard                incf    retardoL,F      ; Fit to delay value of table.
                             incf    retardoH,F      ; to do the calculates                                         
bucle                     nop                     ; each iteration 1us
                            decfsz  retardoL,F
                            goto    bucle
                            decfsz  retardoH,F
                            goto    bucle
Bien, este sistema funciona correctamente, va a ir decreciendo el valor de las variables hasta 0. Pero que pasa??, que en el momento que está haciendo este retardo el contador sigue contando, porque esta contando el siguiente pulso. Y como salta cada 100 conteos timer2, pues cada vez que salte el programa abandonará todo y se ira a la interrupcion para incrementar las variables (que me hacen de contador), el contador contando no me afecta para este bucle de retardo, pero la interrupción SI!!, ya que se olvida de el retardo, y se va a incrementar las variables, gasta 4us y vuelve donde lo dejó --> AL BUCLE este!!, y que pasa? pues que al final retardará el valor de la tabla + el numero de interrupciones *4 ok??.
Espero que lo entendieras ahora. Y esto no hay forma de ajustarlo. Por eso de pensar en usar otro timer para hacer el retardo, ya que es independiente...

Espero que puedas verlo ahora claramente.
Ahora estoy viendo la forma de usar otro timer (el 0 o el 1), para hacer esta tarea...

Saludos.

Título: Re: Ayuda con interrupcion para el timer1!!.
Publicado por: josearrow en 18 de Marzo de 2007, 14:10:28
Ya lo solucioné usando el timer1 como contador para hacer delay. Funciona bien Gracias.