TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado 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.
-
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.
-
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.
-
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
-
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.
-
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.
-
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.
-
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
-
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.
-
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.
-
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
-
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.
-
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
-
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.
-
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
-
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.
-
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:
...
-
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.
-
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!
-
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. :-/
-
De nada! Ahora deslumbranos con el invento.
Saludos.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
¿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?
-
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.
-
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
-
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.
-
La verdad josé, he leído y releído tu post 4 veces y no entiendo tu problema :?
-
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.
-
Ya lo solucioné usando el timer1 como contador para hacer delay. Funciona bien Gracias.