TODOPIC
Microcontroladores PIC => Lenguaje Basic para microcontroladores PIC => Mensaje iniciado por: RALF2 en 16 de Marzo de 2008, 21:01:55
-
Que tal amigos!
Necesito realizar una rutina para muestrear una señal DC utilizando el adc del pic16f877 a 20Mhz el problema es que ese muestreo debe ser hecho en tiempos lo mas exactos posibles. :(
Que recurso del micro me podria servir para esto?
SAludos
-
Hola! pues yo usaría un timer, me parece lo más indicado, su función es contar tiempo o eventos.
En la interrupción de un timer hacé que lea al valor del adc
Cada cuánto necesitas muestrear la señal???
-
Que tal menta!
Bueno la idea es tomar una muestra cada cierto tiempo por ejemplo cada 100us pero para ello el pic debe chequear primero un pin del pic y cuando esta pase a bajo "0" la rutina debe tomar digamos 10 muestras cada 100us y almacenarlas en la memoria del pic.
pero no hallo la forma de cargar el timer para que haga eso :?
-
Bueno, yo no uso proton, uso C pero más o menos, lo que haría yo es:
Configurás el timer. En pic c es Setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 ); no sé como es en protón.
El pin ese en cuestión lo pondría en un pin con interrupción, por ejemplo INT_EXT que se puede configurar en el flanco descendente
En la interrupción esta lo que se hace es setear el contador del timer y habilitar la interrución:
{
set_timer1(65536-X);
Enable_interrupts(INT_TIMER1);
}
En tu caso con un cristal de 20 Mhz tienes un clock interno de 5Mhz, con lo cual el tiempo mínimo es de 1/5M = 0.2us
Esto quiere decir que si el tiempo entre muestras lo deseas de 10us se deben contar 10us/0.2us = 50 pulsos de clock interno te quedaría
{
set_adc_channel( 0 ); // poner desde antes el seteo de canal así no interfiere en los tiempos
a=0; // iniciar en 0 un contador
set_timer1(65536-50);
Enable_interrupts(INT_TIMER1);
}
###############################
Ahora, qué poner el la interrupción del timer, pues
{
set_timer1(65536-X); // primero que nada reconfiguro el timer
registro[a]=read_adc(); // tomo la muestra
a=a+1; // incremento el contador de número de muestra
if (a==9)
Disable_interrupts(INT_TIMER1); // si se tomaron ya 10 muestras desactivo la interrupción
}
NOTA: me parece que para un trabajo más fino se debería considerar el tiempo de salto a la interrupción, si es como creo debe ser de un ciclo interno, entonces en lugar de poner X se debe poner (X-1), es decir 49 para el ejemplo de los 10us...
Espero que te sea útil.
-
Hola pana, lo tienes todo aquí http://www.todopic.com.ar/foros/index.php?topic=14917.0
El Basic no es el mismo que utilizas pero la forma de hacerlo tiene que ser muy parecida.
- Comprobacion del pin mediante un simple bucle o usando interrupciones externas si fuera necesario.
- Activar una base de tiempos de 100uSeg (compensada si fuera necesario).
- Hacer la lectura y almacenamiento en un array (memoria Ram que es más rápida).
- Control del numero de lecturas mediante un contador.
- Almacenamiento de los datos en la memoria no volátil del Pic si la tiene o transferencia de los datos al exterior directamente.
- Vuelta al principio.
-
Gracias menta por tu comntario, tienes razon en cuanto se pierde algo de tiempo cuando se salta a la rutina de interrupcion el problema es que como el programa esta hecho en basic no se sabe exactamente cuanto dura cada instruccion y eso trae problemas :shock:
Dogflux buen material referente al timer lo voy analizar con calma, pero me parese que posee el mismo problema con los tiempos, por alli me recomendaron que utilizara una rutina en asm incrustada en el codigo basic, para asi poder controlar los tiempos exactos que dura cada instruccion y asi poder obtener una base de tiempo lo mas exacta posible, aunque resulta deberas problematico.
Lo otro que pienso seria utilizar un clock a 40Mhz de forma tal que los pequeños tiempos que se pierden cuando se pasa de una instruccion a otra en basic no afecten mucho la base de tiempo y de esa manera se pueda utilizar las interrupciones por el tmr0, e.t.c
Nunca pense que necesitaria tiempos tan exactos, a menos que este equivocado en mi apresiacion :(
-
En general todos los entornos de trabajo suelen llevar herramientas
que permiten calcular los tiempos que tardan las rutinas con mayor
o menor dificultad. De todas formas uno de los ejemplos del enlace
anterior es una rutinita que usa un timer para calcular los tiempos
que tardan en ejecutarse las rutinas Basic.
-
Ralf, solo un comentario pasajero, además de los calculos realizados, tendras que medir el tiempo que consume las lineas correspondiente al funcionamiento de la pantalla glcd.
es decir, primero escribes las lineas correspondiente al bucle de la conversión,
muestrear:
...
...
...
' aquí va las lineas de otros procesos
...
...
volver a muestrear
ese tiempo añadido a las otras lineas es el tiempo que durará un muestreo real. Uno con los calculos puede hacer aproximaciones, dudo mucho que sea un valor real, sin mencionar el hecho de trabajar en un lenguaje de alto nivel.
-
Que tal amigos!
Palitroquez tienes toda la razon por eso es que tengo trancado el serrucho :mrgreen:
El problema es que las rutinas en basic duran un tiempo que no sabemos cuantos es por lo que seria un poco dificil hacerlo de esta manera, se me ocurre es utilizar una rutina en asembler utilizando el modulo CCP2 en modo de disparo especial, de forma tal que cada cierto tiempo me dispare el adc del pic; ese tiempo el cual puede ser programado por uno seria la base de tiempo del sistema. :mrgreen:
Lo otro seria elaborar una rutina para que cuando la señal pase por cero (2.5Volt), con pendiente positiva por ejemplo, comiense a almacenar los datos del adc, de no ser asi el adc tomaria muestras a partir de cualquier punto de la señla y eso no es lo que sequiere.
Que les parese?
-
Se me ocurre que podrías hacer en basic el programa prescindiendo de la evaluación de ese terardo que te lleva llamar a la subrutina de interrupción. Viste que en los fragmentos de código que te puese en C, usé una variable a que se encargaba de contar hasta 10 las muestras, bueno podrías hacer que esa variable en lugar de contar hasta 10 contara hasta 1.000.000 con una variable de 32 bits poniendo if (a==1000000) en lugar de if (a==9) lo que dure esta comparación estimo que no te afecta, pues está dentro de la subrutina y luego de la reiniciación del set_timer1(65536-X); así que no te afecta siempre y cuando la subrutina termine de ejecutarse antes que se desborde nuevamente el contador.
que logras con eso... bueno puedes hacer 2 cosas:
si debugueas tu programa con proteus puedes ver los tiempos desde que se habilita la interrupción hasta que se deshabilita. Ese tiempo debería ser 10us * 1Mciclos = 10 segundos. Suponete que en el proteus midas que pasaron 10.200000 segundos sabes que el retardo es de 200ms en 1Mmuestras ==> 0.2us que este caso sería el de 1 sólo ciclo de retardo, en caso de que sean más cilos los resultados serían de 10.4, 10.6 ... etc y esos son los ciclos que le deberías restar al 50.
O hacer lo mismo, pero sin el proteus, usando otro timer que se dispare simultáneamente que cuente un tiempo de digamos 0.2 segundos y que al interrumpir se fije en que valor está la variable "a" y la guarde, de ese modo se esperaría que "a" esté próximo a 20000 (ya que 20k * 10us = 0.2seg) si a=19600 aprox es que se demoró 1 ciclo si es 19200 serán 2 y así...
-
También puedes setear un pin de un puerto cuando termine la conversión, y luego con el osciloscopio mides el tiempo.
-
Hola. Me tomé el trabajo de pasar el código que he propuesto y correrlo y no me funcionaba con un tiempo de 10us así que puse uno de 100us y en lugar de contar hasta 1M contaba hasta 100000 y el resultado fue de 10.86 seg (8.6% de error por demora) pero ese valor equivale a 43ciclos y me parece un poco mucho... voy a probar con el método2...
Con el segundo obtuve el siguiente resultado: en 0,1 seg. se tomaron en promedio 976,33 muestras (pues lo ejecuté varias veces consecutivas 0 => 0.1 => 0.2 => 0.3 ...)
Esto implica que se tardó por muestra 0,1/976,33= 102,42us.
En este caso, que a mi entender es mucho más confiable q el primero, son como 12 ciclos de reloj de retardo...
Adjunto el código.
-
Gracias menta y palitroquez por su interes en mi proyecto, se los agradezco!
Mira menta voy a chequear tu codigo y te comento lo que veo.
A mi se me ocurre otra forma leyendo un programa que vi en proton sobre el CCP.
Como saben el pic16f877 posee un modulo CCP2 (del cual ya hice referencia antes), que puede ser configurado en modo de disparo especial, de forma tal que periodicamente active el ADC del pic para que realice una conversion cada intervalo de tiempo :mrgreen: pues ese intervalo seria lo que yo quiero obtener :-/
Fijense en lo siguiente: supongace que se necesita tomar una muestra cada 0.1ms (100us) de la señal de entrada y almacenar esta en la memoria, todo esto debe realizarse exactamente dentro de un margen de 100us ni mas ni menos. Vean que eso es lo que quiero, por lo tanto el tiempo que tardo entre adquirir el valor (cargar el condensador del s/h), el tiempo de conversion que es de 25us aproximadamente y el tiempo que tardo en almacenar el dato, y cualquier otro tiempo añadido, todo eso debe hacerse dentro de los criticos 100us, de no ser asi tendria un error en la base de tiempo del osciloscopio como comenta palitroquez :?
Que es lo que quiero hacer con todo esto.
ahora bien como el modulo ccp2 del pic me permite realizar conversiones a intervalos de tiempo programables por el usuario podria ser una solucion.
menta si tienes practica con el ccp2 prueba, si esta dentro de tus posibilidades, yo lo hare apenas me pueda desocupar en el trabajo y asi podemos comparar resultados :mrgreen:
Ahora bien si las rutinas en basic son muy largas (cuando se transforman en asembler) entonces todol o referente al ccp2, adc y el almacenaje de os datos abra que hacerlo forzosamente en asembler, no hay otra :shock:
-
Hola ralf, también me encuentro en una situación similar a la tuya, requiero tomar muestras cada 100uS, y dentro del poco tiempo que me queda, hacer mil cosas mas. La verdad es que creo que no alcanzará hacer todo aquello dentro de 100uS.
Estaba pensando, en concentrarme en los otros procesos, no importa cuando se tarden y de alguna manera ir acumulando los datos que vaya obteniendo del ADC y después que tenga unos cuantos (dependiendo por supuesto del tiempo que lleve en las otras cosas) irlo vaciando.
hace tiempo pregunté ese problema que tenemos : Ejecutar procesos dentro o fuera de un muestreo (http://www.todopic.com.ar/foros/index.php?topic=15856.msg101800#msg101800)
PD: voy a revisar eso de CCP que mencionas
-
Que tal palitroquez!
mira la rutina del ccp2 ya esta lista funciona al pelo :mrgreen:
Lo que hay que hacer es que cada vez que se genere una interrupcion en el ccp2 saltes a la rutina de interrupcion, almacenes el dato en memoria y luego salgas raudo y veloz :D
o sin utilizar interrupciones puedes esperar a que el ccp2if pase a uno, almacenas el dato en memoria y cuando llegue al numero de muestras que deseas los mandas a la glcd o la pc segun sea el caso, que te parese :mrgreen:
-
felicidades ralf, estoy deseando verlo terminado... :-)
-
Ralf corrigeme si me equivoco, en tu caso tu usaras ¿el muestreo por rafagas?
en ese caso viene bien usar el CCP (mas que todo por la presición del tiempo). En mi caso creo que no me ayudaría mucho, porque una vez que comience el muestreo, no debe ser detenido, ya que la aplicación es captura de datos en tiempo real.
-
Que tal amigos!
Dogflux muchas gracias por tu comentario estoy trabajando duro en eso y cada dia estoy mas cerca!
palitroquez amigo si utilizas el modulo ccp2 en modo de disparo especial tal como lo he comentado no tienes problemas porque tu puedes configurarlo para que cada cierto tiempo (en nuestro caso 100us) te active el conversor adc sin que para ello tengas que hacer nada, en otras palabras puedes hacer cualquier cosa mientras el adc trabaja solo :mrgreen: :-/
Y no tiene que reactivarlo cada vez que llega al tiempo prefijado :mrgreen: el se queda mandando a activar el adc de forma continua hasta que tu le digas que se pare!
Cuando el ccp2 llega al tiempo figado (100Us, en nuestro caso) el ccp2if se pondra a 1, y si le habilitaste el ccp2ie (poniendolo a 1) se generara una interrupcion, esto se podria utilizar para saber que ya se alcanzo los 100us, pero como a nosotros no nos interesa mucho saber cuando se alcanzo ese tiempo sino mas bien saber el valor que tiene el adc, podrias activar la interrupcion del adc para que cuando pasen los 100us y un tiempo despues (100us + tiempo de conersion del adc) tengamos el valor que nos da el adc luego lo almacenamos en memoria y salimos de la interrupcion, esa podria ser una forma!
Es de suma importancia los tiempos :shock: por ejemplo suponte que entramos en la interrupcion y luego en ella nos ponemos hacer un retardo de 50us y luego visualizamos el dato en la del adc en la lcd y pa colmo utilizamos un cristal de 4Mhz :( tendriamos un desastre porque al realizar todas esa intrucciones de seguro nos pasariamos de los 100us y los datos que obtendriamos no serian correctos :shock:
Bueno espero que se entienda lo que digo :D
Estoy trabajando ahora en lo de la detecccion del flanco de subida de la señal, esto para que cuando la señal pase por cero (2.5v) con pendiente positiva se active la rutina de almacenamiento de los datos del adc, sino se hace esto se generaria un problema se sincronizacion de la señal a muestrear.
Nota: se supone para empezar que la señal es senoidal porque si es continua no funcionara este metodo :shock:
Saludos
Saludos
-
Me parece magnifico ese modulo ccp, ya tengo algunas aplicaciones pensadas.... :D
Puedes usar un amplif. operacional en configuracion trigger schmitt que serviria para detectar el flanco.
Iria bien tanto para alterna como para continua incluso te permitiria variar el punto de disparo. Pero como
ya te dije en otra ocasion puede que esto se consiga hacer tambien con los comparadores internos del pic.
-
Buena idea dogflux!
Yo tengo hecho un trigger externo con operacionales, lo he simulado con el proteus y su funcionamiento se ve bien, por lo que podria ser una buena idea para probar :mrgreen: ahora bien lo de los comparadores internos que posee el pic le hechare un vistazo a ver que tal!
Estoy esperando por unas glcd que compre para asi poder realizar las pruebas en fisico y asi poder postear como va quedando!
Saludos