Autor Tema: Error Cálculo Frecuencia  (Leído 4781 veces)

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

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Error Cálculo Frecuencia
« en: 29 de Septiembre de 2013, 16:54:04 »
Queridos Amigos de Todopic.
Leo bastante a menudo vuestro foro para las cosillas del PIC16f84a que utilizo para aprender.
Estoy realizando un frecuencimetro y viendo un post en el que contestaba Suky recomendaba a otro usuario no usar el preescaler así que me dije pues sin preescaler que es mejor.
He utilizado dos variante del programa una usando las interrupciones y viendo que a partir de los 10000 Hz  el error era brutal decidí mirar el frecuencimetro de 50 mhz que anda por ahí para basarme en el pero quitandole el preescaler. Os pongo el bucle que utilizo para calcular.
Código: [Seleccionar]
reiniciar
bcf PORTA,3 ;Cierro la entrada de frecuencia
clrf PULSOS
clrf TMR0
movlw .20
movwf CONTE_F
emp bsf PORTA,3 ;Permito que entre la frecuencia
LoopE
movlw .250
movwf CONTI_F
goto Comprueba1
LoopI
nop
nop
nop
nop
nop
nop
Comprueba1
movf TMR0,W ; Muevo TMR0 a W
subwf V_TMR0,F  ;
btfss STATUS,Z ;
goto Comprueba2
nop
goto Asigna
Comprueba2
btfsc STATUS,C ;Compruebo que si TMR0 ...
incf PULSOS,F ; ... ha dado una vuelta incremento pulsos
Asigna
movwf V_TMR0 ; Guardo el valor de TMR0 para comprobar en la sig iteracion
nop
nop
nop
decfsz CONTI_F ; Decremento el contador Interno
goto LoopI ; Mientras no termine sigo.
decfsz CONTE_F ; Decremento el contador Externo
goto LoopE
fina bcf PORTA,3 ;Termino de contar y cierro la entrada de frecuencia

nop

Bucle             
        goto reiniciar

Desactive completamente el preescaler en el OPTION_REG. El tiempo de muestreo son 0.1 s.
Hago un análisis con MPLAB poniendole un clock que empieza en la etiqueta emp y termina en fina cual es mi sorpresa que si multiplico el valor de pulsos por 256 y le resto 1 y le sumo el valor de V_TMR0 la frecuencia se pasa muchísimo de lo que debería ser tranquilamente 200 hz o mas con un periodo de 100 us al 50% de duty :5].
Despues hago un analisis en el de 50mhz original diciendo yo lo hago mal y los contadores también se pasan de lo que debería ser por lo tanto al convertir hace alguna operación para que la frecuencia sea correcta. Haber si me podéis ayudar y darme alguna idea de por que c*** al realizar los calculos no da lo que debería

Un Saludo  :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #1 en: 29 de Septiembre de 2013, 22:27:10 »
Hola,

hay varios factores a tener en cuenta. Primero, por qué detectas las "vueltas" del Timer de esa manera? Es muchísimo más sencillo y seguro utilizar el flag INTCON,T0IF (se pone en alto al desbordar el Timer0 automáticamente, es tu deber una vez utilizado ponerlo a cero para poder detectar el próximo desbordamiento).

Segundo, sabías que escribir el registro TMR0 inhible la cuenta durante unos ciclos (creo que eran dos, pero hace rato que no miro en detalle esa parte del datasheet)?

Tercero, por favor publicá el link donde Suky comenta lo del prescaler para poder ver los motivos que da y si son aplicables a tu caso.

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #2 en: 30 de Septiembre de 2013, 09:23:55 »
Hola BrunoF, gracias por contestar :)

La verdad la primera versión del programa que utilice hacía lo que dices tu, esperaba a que se desbordara el TMR0 y en la interrupción aumentaba el contador PULSOS. Esto lo hacia también sin preescaler y el tiempo de muestreo era de 250ms. Pero al hacer los cálculos: Nº de vueltas * 256 + lo que quedase en TMR0 se pasa en muchisimos Hz a partir de los 10000 Hz. Viendo que esto no funcionaba :? dije a lo mejor no lo hago bien y usé el Frecuencimetro 50 mhz mirando su forma de contar, que es el bucle que he puesto yo  pero sin la parte de contar los ciclos restantes del preescaler. Adjunto el código fuente de ese proyecto

Lo de los dos ciclos de inhibición no lo sabía. De todas formas el clrf de TMR0 lo puedo subir dos instrucciones antes que no variaría el resultado.

Lo de utilizar el preescaler a 1:1 lo ley http://www.todopic.com.ar/foros/index.php?topic=28156.0 en una respuesta creo que la 5ª o así. Ademas supuse que al utilizar 1:1  los cálculos son mas fáciles ya que me ahorro tener que contar los ciclos restantes del preescaler.

Un saludo  :-/

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #3 en: 30 de Septiembre de 2013, 11:14:58 »
Hola de nuevo  :)
Aqui pongo ahora el codigo de la primera versión con la interrupción. Este en 100Khz me da un error de 628 Hz mas. La formula igual que antes Pulsos*256+V_TMR0, esto lo hago de calculadora con los registros y obtengo esos 628Hz de mas.

Código: ASM
  1. ;====================================================================
  2. ; Main.asm file generated by New Project wizard
  3. ;
  4. ; Created:   sáb sep 14 2013
  5. ; Processor: PIC16F84A
  6. ; Compiler:  MPASM (Proteus)
  7. ;====================================================================
  8.  
  9. ;====================================================================
  10. ; DEFINITIONS
  11. ;====================================================================
  12.  
  13. #include p16f84a.inc                ; Include register definition file
  14. #include lib_lcd.inc                ; Incluyo la libreria lcd
  15. #include delay.inc
  16.  
  17.  
  18.  
  19.  
  20.  
  21. ;====================================================================
  22. ; Opciones
  23. ;====================================================================
  24. __config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF
  25.  
  26. ;====================================================================
  27. ; VARIABLES
  28. ;====================================================================
  29. PULSOS equ 0x11
  30. V_TMR0 equ 0x12
  31.  
  32. ;Define
  33.  
  34. ;====================================================================
  35. ; RESET and INTERRUPT VECTORS
  36. ;====================================================================
  37.  
  38.       ; Reset Vector
  39. RST   code  0x0
  40.       goto  Start
  41.  
  42. ISR             org 0x4
  43.                 incf PULSOS,F
  44.                 bcf INTCON,2
  45.                 retfie
  46. PGM   code
  47. FRECUENCIA             
  48.                
  49.                 ;Operaciones
  50.  
  51.  
  52.  
  53.                 return
  54.  
  55.  
  56.  
  57. Start
  58.         ;Incializamos el LCD
  59.                 call initlcd
  60.     ;Incializamos las interrupciones
  61.                 bsf STATUS,5 ; Paso al banco 1
  62.                 movlw b'11101000'
  63.                 movwf OPTION_REG ; Configuro el registro de opciones Preescaler a 000
  64.                 movlw b'10000'
  65.                 movwf TRISA
  66.                 bcf STATUS,5 ; Vuelvo al banco 0
  67.  
  68.  
  69.             LCD_PUTC 'F'
  70.                 LCD_PUTC 'R'
  71.                 LCD_PUTC 'E'
  72.                 LCD_PUTC 'C'
  73.                 LCD_PUTC 'U'
  74.                 LCD_PUTC 'E'
  75.                 LCD_PUTC 'N'
  76.                 LCD_PUTC 'C'
  77.                 LCD_PUTC 'I'
  78.                 LCD_PUTC 'M'
  79.                 LCD_PUTC 'E'
  80.                 LCD_PUTC 'T'
  81.                 LCD_PUTC 'R'
  82.                 LCD_PUTC 'O'
  83.  
  84.         bcf PORTA,3 ;Cierro la entrada de frecuencia
  85.                 bsf INTCON,7 ; Activo las interrupciones globales
  86.         bsf INTCON,5 ; Activo la interrupcion del TMR0 por desbordamiento
  87.  
  88. reiniciar
  89.                
  90.         clrf TMR0
  91.                 clrf PULSOS
  92. open        bsf PORTA,3 ;Abro la entrada de frecuencia
  93.         call retardo_250ms
  94. close        bcf PORTA,3 ;Cierro la entrada de frecuencia
  95.         movf TMR0,W ; Muevo al registro W
  96.         movwf V_TMR0 ; Almaceno el valor que hay en TMR0
  97.         goto reiniciar
  98.  
  99.  
  100.  
  101.  
  102. ;====================================================================
  103.       END

Un Saludo   :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #4 en: 30 de Septiembre de 2013, 14:40:06 »
Hola,

el consejo que da Suky es correcto para un frecuencímetro, ya que en estos uC, al no haber acceso por software al prescaler, el error en la medición puede ser mayor. Lo mejor es usar prescaler 1:1.  Tené en cuenta que más allá de los 262KHz, con el tiempo de medición actual de 250mS, se te va a desbordar la variable PULSOS y te va a dar mal el cálculo de frecuencia.

Consejo:

una vez que incluíste el header del PIC (en este caso p16f84a.inc) podés usar:

INTCON,T0IF en lugar de INTCON,2
STATUS,RP0 en lugar de STATUS,5
INTCON,GIE en lugar de INTCON,7

etc.

Podés mirar el nombre de cada registro y bit abriendo con un notepad el archivo header correspondiente (en este caso el p16f84a.inc).

Asumo por lo que veo en el código que en el circuito eléctrico externo el pin T0CKI(RA4) está sometido a una compuerta AND junto con el pin RA3, logrando controlar el ingreso de pulsos?

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #5 en: 30 de Septiembre de 2013, 16:39:44 »
Hola  :-)

Gracias por el consejo  ;-) La verdad es que según me dé pongo los nombres de los flags o pongo el número. En parte para después al hacer el debug saber de memoria a que pin de cada registro corresponde el flag correspondiente

Los cálculos los he realizado entre los 1000 Hz y los 100000 Hz. Tenía pensado para aumentar el alcance reducir el tiempo de muestreo. Y si fuera necesario usar preescaler.
El problema es que sin preescaler los cálculos no son correctos ya ni me pongo con él porque puede ser una odisea sin final. Lo que no entiendo es que si cuento los pulsos de la frecuencia directamente como es que después al aplicar la formula no da un valor cercano a la frecuencia real. Me falto decir que los 250 ms son 250008 ciclos del pic medidos con MPLAB. Pero con esos 8 ciclos de error en la franja de 100 Khz no puede dar un error de 200 Hz.

Sip. Con el RA3 se activa el paso de la frecuencia con puertas NAND como el circuito del pdf de la respuesta de mas arriba.

Un Saludo  :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #6 en: 30 de Septiembre de 2013, 17:06:20 »
El error más grande en la freq. medida viene porque la demora no está durando 250008 ciclos. Está equivocado el cálculo.

Además: el dispositivo que está generando la frecuencia es fiable? Proviene de un generador de señales? Qué % de error máximo asegura el fabricante @ 100KHz? La señal es cuadrada y el duty es del 50%?

A esa frecuencia de captura, el uC no debería tener errores notables, siempre y cuando la señal entrante sea buena.

Saludos.
« Última modificación: 30 de Septiembre de 2013, 17:11:19 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #7 en: 30 de Septiembre de 2013, 19:04:08 »
Hola de nuevo. Espero no molestar mucho, pero es que en mis ratos libres me dedico a indagar  :D

He vuelto a hacer un simulación mirando lo que me pusiste del cálculo en MPLAB y el retardo de 250ms son en realidad 251.32ms :oops: que entonces serían 251320 ciclos. ¿Será por eso por lo que no es correcto??? Edito: El MPLAB me toma el pelo :(. Mismo retardo con stimulus diferentes unas veces me da 250.59ms y otras veces los 251.32 ms. Que alguien me lo explique. Si el retardo no ha variado como es que varía el tiempo del stopwach. Los breakpoints los tengo en el mismo sitio para comprobar.
Reedito otra vez. Utilizando en un programa únicamente el retardo para ver sus tiempos MPLAB me dice que son 250007 ciclos y 250.007000 mS.
Ahora si que tengo el cerebro frito. Nota los primero cálculos en MPLAB X, los últimos cálculos en MPLAB v8.92. ¿Influye que si por ejemplo para en la interrupción 200 veces son 200 us de retraso multiplicado por 2 ya que primero incremento y después pongo la bandera a 0?¿Habría que contar también los 2 us del retfie al volver? A lo mejor ya estoy suponiendo demás :shock: pero eso explicaría porque el MPLAB en el retardo me da diferentes medidas a cuando ejecuto el bucle sin interrupciones. En ese caso ¿¿como hago para evitar ese exceso??

El dispositivo no esta implementado físicamente. Hasta que no vea que funciona bien el algoritmo de contar en el MPLAB no lo paso a la PCB. Uso stimulus con un periodo en alto por ejemplo de 5us y 5us de bajo. De esta manera el ciclo esta al 50 %

Un Saludo  :-/
« Última modificación: 30 de Septiembre de 2013, 19:41:43 por Citron23 »

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #8 en: 30 de Septiembre de 2013, 19:44:24 »
Pues si quieres te lo explico.

Lo que sucede es que no estás teniendo en cuenta, que cuando se produce la interrupción por desbordamiento del Timer0, el algoritmo de "demora" se interrumpe y se atiende la interrupción (congelando la cuenta de tiempo) y se reanuda sólo una vez que se ha salido de la interrupción. Por eso es también es completamente lógico que a distintos estímulos, distinta frecuencia resultante (y tiempos de demora medidos). Si no inyectas estímulo alguno, seguro obtienes esos 250008 ciclos, pese a que no sería fiel a lo que pasaría cuando le toque medir una frecuencia.

Podríamos concluír, entonces, que por cada 256 incrementos del timer, la demora se retrasa en unos cuantos ciclos, debido al tiempo que se tarda en atender y ejecutar el código asociado a la interrupción.

He que entonces, la interrupción afecta el tiempo que tarda en ejecutarse la demora.

¿Solución?

Deberás utilizar otro timer para llevar la cuenta de la demora si quieres que la interrupción no la afecte.

Saludos.

"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #9 en: 30 de Septiembre de 2013, 20:01:46 »
Gracias BrunoF. Me estas ayudando un montón ((:-))

Vale ya entendí lo que me explicaste. El problema es que el 16f84a solo tiene el TMR0 que yo sepa. ¿Entonces como puedo hacer???


Un Saludo Y Buenas Noches desde España :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #10 en: 30 de Septiembre de 2013, 21:32:54 »
Bueno, en tu caso, donde hay sólo un Timer, las cosas se ponen complicadas. Sinceramente te recomendaría que migraras a otro microcontrolador similar pero que posea mayor cantidad de Timers y los periféricos que necesitas. Hay infinidad en la familia 16F que cumplen con estos requisitos.

Si es por el mero desafío o aprendizaje, hay tantas formas de abordar el problema como ingenio y conocimientos se tengan, tanto continuando usando las interrupciones, como no usándolas. Sin embargo, todas involucran un estricto control de los ciclos de ejecución y de un pre-cálculo de los posibles procesos que pudiesen ocurrir durante la ejecución mísma.

Por ejemplo, nada impide que tengas el mísmo algorítmo de antes, sólo que el algoritmo de demora deberá tener en cuenta ciertos factores.

Supongamos que queremos determinar la frecuencia basados en un tiempo de 100ms(en lugar de 250ms):

Para ello, el algoritmo de demora podría utilizar una dos variables de 8 bits trabajando como una de 16 bits(nuestro contador de ciclos / 2).
Lo pre-cargaríamos entonces con un valor poco menor a 100000 / 2 (0xC350). E implementaríamos un bucle sencillo que iría descontando a partir de allí:


El error de cálculo del algoritmo se deberá al error introducido por el cristal externo y por la señal de entrada.

Se podría mejorar el bucle en un par de instrucciones, pero puede que ya sea demasiado fanatismo hacerlo, así que no lo hice.

Código: [Seleccionar]
;====================================================================
; Main.asm file generated by New Project wizard
;
; Created:   sáb sep 14 2013
; Processor: PIC16F84A
; Compiler:  MPASM (Proteus)
;====================================================================
 
;====================================================================
; DEFINITIONS
;====================================================================
 
#include p16f84a.inc                ; Include register definition file
  ;#include lib_lcd.inc                ; Incluyo la libreria lcd
 
;====================================================================
; Opciones
;====================================================================
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF
 
;====================================================================
; VARIABLES
;====================================================================
PULSOS equ 0x11
V_TMR0 equ 0x12
delayl equ 0x13
delayh equ 0x14
aux equ 0x15

;Define

#DEFINE IN_OUT_DELAY .9 ;ciclos de demora introducidos por el call, return, cierre de NAND deben ser tenidos en cuenta)
#DEFINE CYCLES (.50000 - IN_OUT_DELAY)

;====================================================================
; RESET and INTERRUPT VECTORS
;====================================================================
 
     ; Reset Vector
RST code 0x0
goto Start
 
ISR org 0x4
incf PULSOS,F
retfie

PGM code
FRECUENCIA
;Operaciones
return
 
errorlevel -302
 
Start
;Incializamos el LCD
;call initlcd
;Incializamos las interrupciones
bsf STATUS,RP0 ; Paso al banco 1
movlw b'11101000'
movwf OPTION_REG ; Configuro el registro de opciones Preescaler a 000
movlw b'10000'
movwf TRISA
bcf STATUS,RP0 ; Vuelvo al banco 0
 
 
;LCD_PUTC 'F'
;LCD_PUTC 'R'
;LCD_PUTC 'E'
;LCD_PUTC 'C'
;LCD_PUTC 'U'
;LCD_PUTC 'E'
;LCD_PUTC 'N'
;LCD_PUTC 'C'
;LCD_PUTC 'I'
;LCD_PUTC 'M'
;LCD_PUTC 'E'
;LCD_PUTC 'T'
;LCD_PUTC 'R'
;LCD_PUTC 'O'
 
bcf PORTA,3 ; Cierro la entrada de frecuencia
;bsf INTCON,7 ; Activo las interrupciones globales
;bsf INTCON,5 ; Activo la interrupcion del TMR0 por desbordamiento
 
reiniciar
clrf PULSOS
movlw HIGH CYCLES
movwf delayh
movlw LOW CYCLES
movwf delayl
clrf TMR0
bcf INTCON,T0IF
open
bsf PORTA,3 ; Abro la entrada de frecuencia
call retardo_100ms
close
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
nop
bcf PORTA,3 ; Cierro la entrada de frecuencia

btfsc INTCON,T0IF ;caso extraño, pero puede ocurrir
incf PULSOS,F

movf TMR0,W ; Muevo al registro W
movwf V_TMR0 ; Almaceno el valor que hay en TMR0
goto reiniciar

;====================================================================
; Subrutinas
;====================================================================

retardo_100ms
movf INTCON,W
movwf aux

movlw .8 ;demora básica bucle

btfsc aux,T0IF
incf PULSOS,F

btfsc aux,T0IF
bcf INTCON,T0IF ;limpiar flag de interr.

nop ; para hacer par la cantidad de instrucciones del bucle

subwf delayl,F
btfsc STATUS,C
goto noCarry

movlw .1
subwf delayh,F

btfsc STATUS,C
goto retardo_100ms

return

noCarry ;compensar ciclos hasta llegar a 16 (8 x 2)
goto $+1 ; 2 ciclos
goto retardo_100ms ; 2 ciclos


;====================================================================
END

Saludos.
« Última modificación: 01 de Octubre de 2013, 14:44:39 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #11 en: 01 de Octubre de 2013, 08:31:32 »
Hola BrunoF, gracias por el código. :-)

La verdad es que ahora ya por aprovechar el PIC y así también aprendo.

A ver si me puedes explicar unas cosas que no entiendo.
Citar
Para ello, el algoritmo de demora podría utilizar una dos variables de 8 bits trabajando como una de 16 bits(nuestro contador de ciclos / 2).
Lo pre-cargaríamos entonces con un valor poco menor a 100000 / 2 (0xC350). E implementaríamos un bucle sencillo que iría descontando a partir de allí:
Esto no lo entiendo. Se que el 100000 son los ms pero no entiendo porque cargar la mitad.   ¿No sería el contador de ciclos *2? Tengo un cacao mental ahora mismo.

El retardo desde que se abre la entrada de señal hasta que se cierra ahora son 99.999 ms que esta perfecto, pero cuando hago el debug y miro los registros con periodo 10us ~ 100000 Hz me da 87590 Hz. ¿f=Pulsos*256+V_TMR0?
Los 8 ciclos de demora no serían 6?? 2 de call 2 de return 1 bcf PORTA,3 y 1 bsf PORTA,3

Otra duda en el retardo_100ms si el ciclo dura 14 porque se resta de 7 en 7 en cada iteración, eso no lo acabo de entender

Un Saludo y Gracias :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #12 en: 01 de Octubre de 2013, 14:53:56 »
Hola,

el problema era un error mío en el código, eso me pasa por no simularlo. He corregido el código del post anterior con uno nuevo que debería funcionar. Sucedía un caso especial en el que la bandera T0IF se seteaba justo después de realizarse el checkeo de la mísma y el incremento consecuente de la variable PULSOS, produciendo que se limpiara el flag pero se omitiera el incremento de PULSOS. Es bastante complejo verlo, tal vez si lo simulas y pones un breakpoint en incf PULSOS,F podrías ver que a veces tarda dos desbordamientos del Timer en incrementarse, lo que hace evidente el fallo.

Cuento 50000 en lugar de 100000 sencillamente porque 100000 no entra en una variable de 16bits, y no quería tener que utilizar una de 24/32 bits para poder contar hasta 100000. Cuento 50000, pero en lugar de contar ciclos cuento ciclos * 2. Es decir que dos ciclos de ejecución descuentan una unidad de la cuenta regresiva. Por eso vas a ver que la cantidad de ciclos del bucle debe ser par (sino se produciría un desfasaje de ciclos que sería significativo en 100000 ciclos de ejecución y haría que den mal los cálculos) y también verás que los valores que se cargan para descontar, equivalen a la mitad de los ciclos  reales. Ej:
   movlw   .8

indicaría que el bucle demorará 16 ciclos en completarse, cualquiera sea la curso interno que tome. Se puede tornar bastante complejo lograr que todas las ramas del bucle demoren en cualquier caso la mísma cantidad de ciclos, aunque no necesariamente deben demorar lo mísmo. Yo hice que demoraran lo mísmo porque se podía y resultaba más corto el algoritmo. Claro que cada ramal puede demorar distinto tiempo, siempre y cuando al final del bucle descuente las unidad que ha tomado ejecutarse del contador total.

Lo he simulado y da clavado 10000 ciclos. El cálculo de frecuencia es f= (PULSOS * 256 + V_TMR0) / tiempoBase[ s ].
En el ejemplo dado:
f = (39 * 256 + 16) / 0.1s = 100kHz

Los ciclos de demora al entrar/salir no los tengas mucho en cuenta. Fijate que están excedidos para que el algoritmo de una vuelta menos, asegurandome un pequeño tiempo adicional hasta lograr los 100mS, y permitiendome rellenarlo a gusto para lograr con precisión el corte a los 100000 ciclos de ejecución.

Saludos.
« Última modificación: 01 de Octubre de 2013, 15:07:20 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado Citron23

  • PIC10
  • *
  • Mensajes: 13
Re: Error Cálculo Frecuencia
« Respuesta #13 en: 02 de Octubre de 2013, 09:02:50 »
Hola BrunoF.

Buenísimo el código ((:-)) como dicen en otros foros, marchando unas cervezas  ;-)

La idea del contador de 50000 me parece buenísima así se puede ajustar el retardo mucho mejor que haciendo bucles anidados que para ajustarlos uno a la exactitud se acaba volviendo loco.
Vale ¿entonces como das una vuelta que son 16 ciclos descuentas 8 y así consigues que con esos 50000 en realidad sean 100000?

Ya solo me queda la duda de estas dos lineas de código
Código: ASM
  1. #DEFINE IN_OUT_DELAY    .9              ;ciclos de demora introducidos por el call, return, cierre de NAND deben ser tenidos en cuenta)
  2. #DEFINE CYCLES                  (.50000 - IN_OUT_DELAY)
He visto que el IN_OUT_DELAY siempre es 1 más que lo que descuentas de CYCLES en el retardo a que se debe eso?? y porque lo inicializas ya con esos 9 de menos??

Ya otra cosa aprovechando. Si quisiera hacer un ajuste así pero usando interrupción, como puedo calcular el tiempo que añade la interrupción al retardo o no se puede?
Es que ahora me ha picado el gusanillo para intentar hacerlo yo en la interrupción.

Un Saludo y Gracias :-/

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Error Cálculo Frecuencia
« Respuesta #14 en: 02 de Octubre de 2013, 11:30:05 »
Hola BrunoF.

Buenísimo el código ((:-)) como dicen en otros foros, marchando unas cervezas  ;-)

La idea del contador de 50000 me parece buenísima así se puede ajustar el retardo mucho mejor que haciendo bucles anidados que para ajustarlos uno a la exactitud se acaba volviendo loco.
Vale ¿entonces como das una vuelta que son 16 ciclos descuentas 8 y así consigues que con esos 50000 en realidad sean 100000?

Así es, para mi una unidad de cuenta regresiva equivale a dos ciclos de ejecución. Es por eso que para mantener las cuentas fáciles y sin error, debo acomodar todas las demoras a valores pares, múltiplos de dos. Si la vuelta demorase 21 ciclos, lo mejor sería agregar un "nop" y llevarla a 22, para poder decrementar 11 unidades por vuelta. Efectivamente 50000 unidades de demora equivalen a 100000 ciclos.

Ya solo me queda la duda de estas dos lineas de código
Código: ASM
  1. #DEFINE IN_OUT_DELAY    .9              ;ciclos de demora introducidos por el call, return, cierre de NAND deben ser tenidos en cuenta)
  2. #DEFINE CYCLES                  (.50000 - IN_OUT_DELAY)
He visto que el IN_OUT_DELAY siempre es 1 más que lo que descuentas de CYCLES en el retardo a que se debe eso?? y porque lo inicializas ya con esos 9 de menos??

Si, es mínimamente siempre una unidad más al valor máximo del bucle (aunque nada impide que sea mayor que eso el número elegido), ya que al hacerlo, me aseguro que el algoritmo de demora, como he comentado previamente, realice una iteración menos a la que debería, generandome un puñado de ciclos adicionales de sobra, que me permiten ajustar finamente la demora final para cumplir con precisión los 100k ciclos de ejecución.

Ya otra cosa aprovechando. Si quisiera hacer un ajuste así pero usando interrupción, como puedo calcular el tiempo que añade la interrupción al retardo o no se puede?
Es que ahora me ha picado el gusanillo para intentar hacerlo yo en la interrupción.

El tiempo que añade la interrupción del Timer se puede pre-calcular y agregar a la demora. El problema es que tener dos demoras distintas del bucle de demora, hace que no se pueda preveer la duración de la última vuelta y podrías tener un error en la cantidad de tiempo total contado de demora.

Usando la interrupción, una posible solución al problema:

Código: [Seleccionar]
;====================================================================
; Main.asm file generated by New Project wizard
;
; Created:   sáb sep 14 2013
; Processor: PIC16F84A
; Compiler:  MPASM (Proteus)
;====================================================================
 
;====================================================================
; DEFINITIONS
;====================================================================
 
#include p16f84a.inc                ; Include register definition file
  ;#include lib_lcd.inc                ; Incluyo la libreria lcd
 
;====================================================================
; Opciones
;====================================================================
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF
 
;====================================================================
; VARIABLES
;====================================================================
PULSOS equ 0x11
V_TMR0 equ 0x12
delayl equ 0x13
delayh equ 0x14
aux equ 0x15
aux2 equ 0x16

;Define

#DEFINE IN_OUT_DELAY .13 ;ciclos de demora introducidos por el call, return, cierre de NAND deben ser tenidos en cuenta)
#DEFINE CYCLES (.50000 - IN_OUT_DELAY)

;====================================================================
; RESET and INTERRUPT VECTORS
;====================================================================
 
     ; Reset Vector
RST code 0x0
goto Start
 
ISR org 0x4
bcf INTCON,T0IF
incf PULSOS,F
bsf aux,T0IF ;indicar que ha ocurrrido desbordamiento
nop                                   ;ajuste
retfie

PGM code
FRECUENCIA
;Operaciones
return
 
errorlevel -302
 
Start
;Incializamos el LCD
;call initlcd
;Incializamos las interrupciones
bsf STATUS,RP0 ; Paso al banco 1
movlw b'11101000'
movwf OPTION_REG ; Configuro el registro de opciones Preescaler a 000
movlw b'10000'
movwf TRISA
bcf STATUS,RP0 ; Vuelvo al banco 0
 
 
;LCD_PUTC 'F'
;LCD_PUTC 'R'
;LCD_PUTC 'E'
;LCD_PUTC 'C'
;LCD_PUTC 'U'
;LCD_PUTC 'E'
;LCD_PUTC 'N'
;LCD_PUTC 'C'
;LCD_PUTC 'I'
;LCD_PUTC 'M'
;LCD_PUTC 'E'
;LCD_PUTC 'T'
;LCD_PUTC 'R'
;LCD_PUTC 'O'
 
bcf PORTA,3 ; Cierro la entrada de frecuencia
bsf INTCON,GIE ; Activo las interrupciones globales
bsf INTCON,T0IE ; Activo la interrupcion del TMR0 por desbordamiento
 
reiniciar
clrf PULSOS
movlw HIGH CYCLES
movwf delayh
movlw LOW CYCLES
movwf delayl
clrf TMR0
clrf aux
bcf INTCON,T0IF
open
bsf PORTA,3 ; Abro la entrada de frecuencia
call retardo_100ms
close
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
bcf PORTA,3 ; Cierro la entrada de frecuencia

btfsc INTCON,T0IF ;caso extraño, pero puede ocurrir
incf PULSOS,F

movf TMR0,W ; Muevo al registro W
movwf V_TMR0 ; Almaceno el valor que hay en TMR0
goto reiniciar

;====================================================================
; Subrutinas
;====================================================================

retardo_100ms
movf aux,W ;realizar cache de variable
movwf aux2

movlw .12 ;demora básica bucle

btfss aux2,T0IF
goto noInterr ;si no se ejecutó ISR, generar ciclos de demora adicionales

check1:
btfsc aux2,T0IF
bcf aux,T0IF ;limpiar flag de interr.

nop ; para hacer par la cantidad de instrucciones del bucle

subwf delayl,F
btfsc STATUS,C
goto noCarry

movlw .1
subwf delayh,F

btfsc STATUS,C
goto retardo_100ms

return

noCarry ;compensar ciclos hasta llegar a 16 (8 x 2)
goto $+1 ; 2 ciclos
goto retardo_100ms ; 2 ciclos

noInterr
goto $+1 ; 2 ciclos
goto $+1 ; 2 ciclos
nop ; 1 ciclo
goto check1 ; 2 ciclos


;====================================================================
END
« Última modificación: 02 de Octubre de 2013, 11:32:39 por BrunoF »
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.