Autor Tema: conversor adc  (Leído 2939 veces)

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

Desconectado SEBARUBIOLO

  • PIC10
  • *
  • Mensajes: 10
conversor adc
« en: 01 de Septiembre de 2015, 22:01:56 »
Hola a todos.
Quisiera realizar un circuito que me permita obtener valores de dos sensores ADC, pero obteniendo 1000 lecturas por segundo de cada sensor. Para luego realizar cálculos estadísticos de errores de los datos. La idea general es hacer un capturados de varios sensores y enviarlas por usb a una pc. Hice algo similar con un 18f2550 pero solo logre obtener un máximo 10 capturas por segundos más otros cálculos. Es muy poco y cualquier error de captura altera el resultado.

Es posible realizar este tipo de capturas? Se pueden hacer desde un PIC específico? O conviene utilizar conversores independientes y comunicarlos a un master con I2C? O se debería realizar de otra forma?. Aclaro que soy un simple aficionado y puedo estar diciendo cualquier pavada. Sepan disculpar mi ignorancia.
Saludos.

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Re: conversor adc
« Respuesta #1 en: 02 de Septiembre de 2015, 15:26:30 »
Hola SEBARUBIOLO, 1000 lecturas por segundo de 2 canales ADC creo que los 16F pueden hacerlo, digo creo porque nunca lo e intentado, pero se de gente que si lo a hecho.

Ahora, hacer esas 2000 lecturas y una cantidad de cálculos complejos de manera tal que un 18F solo consiga completar 10 lectura, pues con un 16F conseguirás menos aun.

Lo único que veo posible es que el 16F realice las lecturas y las envía hacia la PC y que esta última haga los cálculos complejos.

Un saludo.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado SEBARUBIOLO

  • PIC10
  • *
  • Mensajes: 10
Re: conversor adc
« Respuesta #2 en: 02 de Septiembre de 2015, 21:52:01 »
gracias Chaly29 por tu interes y amabilidad.

Esto es lo que hice en el pic:

Código: [Seleccionar]
#include<18f2550.h>
#DEVICE ADC=10 // CAD a 10 bits, justificación a a la derecha.
#fuses HSPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,NOPBADEN
#use delay(clock=48000000) // Frecuencia máxima de trabajo.

#include "usb_cdc.h" // Descripción de funciones del USB.
#include "usb_desc_cdc.h" // Descriptores del dispositivo USB.

#define led1               PIN_B2    //está encendido el pic
#define led2               PIN_B3    //esta listo para comunicar
#define led3               PIN_B4    //titila cuando está comunicando
#define salida1            PIN_B5    //avanza el cilindro
#define salida2            PIN_B6    //retrocede el cilindro
#define req                PIN_C0    //pin solicita señal a la regla
#define dat                PIN_C1    //pin recibe dato de la regla
#define clk                PIN_C2    //pin recible reloj de la regla
#define pin_on             output_high
#define pin_off            output_low


int8 Mensaje[14];
int8 valor_adc_alta=0; // Contiene el MSB del valor del ADC.
int8 valor_adc_baja=0; // Contiene el LSB del valor del ADC.

void config_adcon2(void) {
   #asm
   movlw 0b10111110
   iorwf 0xFC0,1   
   #endasm
}

void lecturaanalogica1 (void) {

   //lectura de canal 0
   Mensaje[1]= 0;
   Mensaje[2]= 0;
   valor_adc_alta=0;
   valor_adc_baja=0;
   set_adc_channel(0);                                 // Seleccionamos el canal 0 y comenzamos a leer.
   delay_us(10);                                       // Esperamos un tiempo para estabalizar el dato leido.
   valor_adc_alta = (read_adc()>>8);                   // Enviamos la parte alta de la conversión de 10 bits.
   valor_adc_baja = (int)(read_adc());                 // Enviamos la parte baja de la conversión de 10 bits.
   //fin de lectura de canal 0
   Mensaje[1]=valor_adc_alta;
   Mensaje[2]=valor_adc_baja;
}

void lecturaanalogica2 (void) {
   //lectura de canal 1
   Mensaje[3]= 0;
   Mensaje[4]= 0;
   valor_adc_alta=0;
   valor_adc_baja=0;
   set_adc_channel(1);                                 // Seleccionamos el canal 0 y comenzamos a leer.
   delay_us(10);                                       // Esperamos un tiempo para estabalizar el dato leido.
   valor_adc_alta = (read_adc()>>8);                   // Enviamos la parte alta de la conversión de 10 bits.
   valor_adc_baja = (int)(read_adc());                 // Enviamos la parte baja de la conversión de 10 bits.
   //fin de lectura de canal 0
   Mensaje[3]=valor_adc_alta;
   Mensaje[4]=valor_adc_baja;
}

void lecturaregladigital(void) {   
   
   int8 i = 0; int8 j = 0; int8 k = 0; //variable aux para obtener el valor de la regla
   int8 datoObtenido[14];
   Mensaje[5]=0;
   Mensaje[6]=0;
   Mensaje[7]=0;
   Mensaje[8]=0;
   Mensaje[9]=0;
   Mensaje[10]=0;
   Mensaje[11]=0;
   Mensaje[12]=0;
   Mensaje[13]=0;
   datoObtenido[] = 0;
   pin_on(req);
      for (i=0; i<13; i++){
         k=0;
         for (j=0; j<4; j++){
            while (!input(clk)) {};
            while (input(clk)) {};
            if (input(dat)==0) bit_clear(k,j);
            if (input(dat)==1) bit_set(k,j);
         }
      datoObtenido[i] = k;
      }
   Mensaje[5]=datoObtenido[5]; //valor metro
   Mensaje[6]=datoObtenido[6]; //valor decimetro
   Mensaje[7]=datoObtenido[7]; //valor centimetro
   Mensaje[8]=datoObtenido[8]; //valor milimetro
   Mensaje[9]=datoObtenido[9]; //valor decimal
   Mensaje[10]=datoObtenido[10]; //valor centecimal
   Mensaje[11]=datoObtenido[11]; //decimal
   Mensaje[12]=datoObtenido[12]; //unidad
   Mensaje[13]=datoObtenido[4]; //singo
//fin de lectura de la regla digital
}


void main(void) {
   unsigned char datoIN;   // Dato que llega por la USART
   // definiciones del pic:
   set_tris_b(0x00);
   delay_cycles(5);
   pin_off(led1);                           
   pin_off(led2);
   pin_off(led3);
   pin_off(salida1);
   pin_off(salida2);
   setup_adc_ports(AN0_TO_AN1);        // Configura canales usados por el ADC.
   setup_adc(ADC_CLOCK_DIV_64);        // Asigna la velocidad: reloj\64.
   config_ADCON2();                    // Configuramos el ADCON2.
   // inicio de puerto usb:
   usb_cdc_init();  // Configura el puerto
   usb_init();  // Inicializamos el stack USB.
   usb_task();
   while (!usb_cdc_connected()) {}; // espera a detectar una transmisión de la PC (Set_Line_Coding).
   do{
      usb_task();
      if (usb_enumerated()){  // Espera a que el dispositivo sea enumerado por el host.
        if(usb_cdc_kbhit()){ // En espera de nuevos caracteres en el buffer de recepción.
          datoIN=usb_cdc_getc();   // Lee lo que llego al buffer
          //datoIN debe como un byte, cada bit representa las siguientes funciones
          //bit 7 = Solicita lectura analógica 2
          //bit 6 = Solicita lectura analogica 1
          //bit 5 = Solicita lectura de regla
          //bit 4 = Enciente salida 2
          //bit 3 = Enciende salida 1
          //bit 2 = Enciende led 3
          //bit 1 = Enciende led 2
          //bit 0 = Enciende led 1
          if (!bit_test(datoIN,0)){
            pin_off(led1);
          }
          if (bit_test(datoIN,0)){
            pin_on(led1);
          }
          if (!bit_test(datoIN,1)){
            pin_off(led2);
          }
          if (bit_test(datoIN,1)){
            pin_on(led2);
          }
          if (!bit_test(datoIN,2)){
            pin_off(led3);
          }
          if (bit_test(datoIN,2)){
            pin_on(led3);
          }
          if (!bit_test(datoIN,3)){
            pin_off(salida1);
          }
          if (bit_test(datoIN,3)){
            pin_on(salida1);
          }
          if (!bit_test(datoIN,4)){
            pin_off(salida2);
          }
          if (bit_test(datoIN,4)){
            pin_on(salida2);
          }
          if (bit_test(datoIN,5)==1){
            lecturaregladigital();
          }
          if (bit_test(datoIN,6)==1){
            lecturaanalogica1();
          }
          if (bit_test(datoIN,7)==1){
            lecturaanalogica2();
          }
          printf(usb_cdc_putc, "%Xa%Xb%Xc%Xd%U%U%U%U%U%U%U%U%Uq", Mensaje[1], Mensaje[2], Mensaje[3],
          Mensaje[4], Mensaje[5], Mensaje[6], Mensaje[7], Mensaje[8], Mensaje[9],
          Mensaje[10], Mensaje[11], Mensaje[12], Mensaje[13]);
        }
      }
   }while (TRUE); // bucle infinito.
}

En la pc tenía una solicitud de datos cada 0.1 seg. Si lo bajo tiraba errores en los datos entregados. No se porque puede ser.

¿se optimizar la programación?

Desconectado Chaly29

  • Moderador Global
  • DsPIC33
  • *****
  • Mensajes: 4315
Re: conversor adc
« Respuesta #3 en: 02 de Septiembre de 2015, 22:46:39 »
Hola SEBARUBIOLO, me mataste, porque no se nada de programación en "C", solo en .asm.

Si quieres pasamos el post completo al sub foro de programación en C, donde alguien más idóneo sepa responderte.

Un saludo.

Atte. CARLOS.

La teoría es cuando se sabe todo y nada funciona. La práctica es cuando todo funciona y nadie sabe por qué.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: conversor adc
« Respuesta #4 en: 03 de Septiembre de 2015, 02:30:47 »
usb_cdc_putc(c)
Citar
The same as putc(), sends a character. It actually puts a character into the transmit
buffer, and if the transmit buffer is full will wait indefinitely until there is space for the
character.
usb_cdc_putc_fast(c)
Citar
The same as usb_cdc_putc(), but will not wait indefinitely until there is space for the
character in the transmit buffer. In that situation the character is lost.

Lo mas seguro que sea por tu printf.. suponiendo que solo pruebes con lecturas de ADC nomas, si tenes todo entonces esto es bloqueante:


Código: [Seleccionar]
      for (i=0; i<13; i++){
         k=0;
         for (j=0; j<4; j++){
            while (!input(clk)) {};
            while (input(clk)) {};

el

read_adc()

es bloqueante. basicamente se queda ahi esperando hasta que se tenga el resultado. Tampoco entiendo por que lo lees 2 veces, si tenes tu ADC configurado como 10/12bit deberia darte el resultado de 10/12bits, sino estas haciendo 2 lecturas, uniendo la parte alta y la parte baja.


Yo no uso CCS, asi no que puedo decirte mucho, pero mirando el manual de CCS y tu codigo es lo unico que se me puede ocurrir.

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: conversor adc
« Respuesta #5 en: 03 de Septiembre de 2015, 07:49:34 »
es bastante logico que no obtengas esa velocidad, demasiado codigo y poco optimizado, ya solo enviar mediante printf tiene mucho retardo.

Para la velocidad que quieres necesitas hacer un codigo mas eficiente, enviar por tramas y no con un printf mandando todo asi, otra cosa a destacar es que pones constantemente Mensaje
  • =0; no es necesario hacer esto, si despues cambias el valor pues pierde tiempo poniendolo a 0 y luego poniendolo a valor.


La lectura de la regla tambien retrasa mucho el codigo, si su velocidad es lenta pues tendrias que esperar a que se leyese y luego seguir, por lo cual perderia ahi tiempo. Por el formato parece un SPI asi que podrias usar el metodo por hardware asi las lecturas no quitan ciclos.

Desconectado SEBARUBIOLO

  • PIC10
  • *
  • Mensajes: 10
Re: conversor adc
« Respuesta #6 en: 03 de Septiembre de 2015, 21:22:37 »
Voy a seguir sus consejos.
1.   sacar los mensajes (los tenía porque pensé que quedaba elvalor anterior y no me servía).
2.  Enviar datos mediante Puts y no con prints.
3.   Respecto al read_adc lo almaceno en dos variables int8. Tengo que ver si hay alguna variable de 10 bits, ¿ ó hay una variable especial para guardar el dato? ¿ó se podrá hacer de otra forma?
4.    Y el código:

Código: [Seleccionar]
for (i=0; i<13; i++){
         k=0;
         for (j=0; j<4; j++){
            while (!input(clk)) {};
            while (input(clk)) {};
es para obtener el valor de un calibre con protocolo digimess. Es la única manera que encontré de obtener su información. No sé que otra forma puedo hacerlo.
Segun lo que leí de las especificaciones de mitutoyo puedo decir que cada CLK son 200 useg. Si mi cálculo es correcto 13 i x 4 j = 52 CLK = 10400 useg = 10.4 miliseg. Creo..... jeje....

Igual tengo bastante para corregir. Voy a rehacer el código y les comento lo que sucede.  :-/ :-/ :-/
Muchas gracias.  :mrgreen:

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: conversor adc
« Respuesta #7 en: 04 de Septiembre de 2015, 02:09:27 »
Citar
  Respecto al read_adc lo almaceno en dos variables int8. Tengo que ver si hay alguna variable de 10 bits, ¿ ó hay una variable especial para guardar el dato? ¿ó se podrá hacer de otra forma?

int16
un entero de 16 bits.
Entonces haces

variable = read_adc();

Y la lectura del ADC se guarda en variable , los 10 bits directamente. esto va a hacer que solamente ejecutes una conversion en ves de 2 como estabas haciendo, logrando que vaya mas rapido.
Si aun asi queres que vaya MAS rapido, y que la lectura del adc no te detenga el programa, vas a tener que usar interrupciones para el ADC tambien.

Citar
es para obtener el valor de un calibre con protocolo digimess. Es la única manera que encontré de obtener su información. No sé que otra forma puedo hacerlo.
Segun lo que leí de las especificaciones de mitutoyo puedo decir que cada CLK son 200 useg. Si mi cálculo es correcto 13 i x 4 j = 52 CLK = 10400 useg = 10.4 miliseg. Creo..... jeje....

Si pero es estar esperando el dato lo cual es mucho tiempo. Y seguro que ese tiempo es minimo lo cual no siempre ira a maxima velocidad. Si tenes un SPI lo haces por igual, en el SPI entra un CLK y el dato, vos seleccionas en que flanco toma el dato y cuando llega a los 8 bits ( 1 byte ) se produce una interrupcion la cual podes tomar el dato, sin que el micro haga nada. Si aun asi queres hacerlo en el programa principal preguntas por la bandera de la interrupcion.

Código: [Seleccionar]
void config_adcon2(void) {
   #asm
   movlw 0b10111110
   iorwf 0xFC0,1   
   #endasm
}

Recien me doy cuenta que estas modificando un registro con ASM, pero que no tuviste en cuenta el banco. Ademas eso deberia poder modificarlo con los valores desde CCS, yo no se cuales son por que como diej no uso CCS.

Tambien mira como se puede reducir la funcion lecturaanalogica2()

obviamente
int16 Mensaje[14];
antes
 
Código: C
  1. void lecturaanalogica2 (void) {
  2.    set_adc_channel(1);                                 // Seleccionamos el canal 0 y comenzamos a leer.
  3.    delay_us(10);                                       // Esperamos un tiempo para estabalizar el dato leido.
  4.    Mensaje[3] = read_adc();                   // Enviamos la parte alta de la conversión de 10 bits.
  5.    //fin de lectura de canal 1
  6. }

Igual este:
Código: C
  1. void lecturaregladigital(void) {  
  2.    int8 i=0, j=0; //variable aux para obtener el valor de la regla
  3.    pin_on(req);
  4.       for (i=0; i<13; i++){
  5.          for (j=0; j<4; j++){
  6.             while (!input(clk)) {};
  7.             while (input(clk)) {};
  8.             if(i>=5) {
  9.                    if (input(dat)==0) bit_clear(Mensaje[i],j);
  10.                    else bit_set(Mensaje[i],j);
  11.              }
  12.       }
  13. //fin de lectura de la regla digital
  14. }

En fin, todo esto no evita que se pierda tiempo :/

Desconectado SEBARUBIOLO

  • PIC10
  • *
  • Mensajes: 10
Re: conversor adc
« Respuesta #8 en: 06 de Septiembre de 2015, 19:03:02 »
Bueno, esto es lo que quedó:

Código: [Seleccionar]
#include<18f2550.h>
#DEVICE ADC=10 // CAD a 10 bits, justificación a a la derecha.
#fuses HSPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,NOPBADEN
#use delay(clock=48000000) // Frecuencia máxima de trabajo.

#include "usb_cdc.h" // Descripción de funciones del USB.
#include "usb_desc_cdc.h" // Descriptores del dispositivo USB.

#define led1               PIN_B2    //está encendido el pic
#define led2               PIN_B3    //esta listo para comunicar
#define led3               PIN_B4    //titila cuando está comunicando
#define salida1            PIN_B5    //avanza el cilindro
#define salida2            PIN_B6    //retrocede el cilindro
#define req                PIN_C0    //pin solicita señal a la regla
#define dat                PIN_C1    //pin recibe dato de la regla
#define clk                PIN_C2    //pin recibe reloj de la regla
#define pin_on             output_high
#define pin_off            output_low


//variables para obtener el valor de la regla
int8 datoObtenido[14];
int8 i=0;
int8 j=0;
int8 k=0;
//variables plara obtener el valor de los sensores
int16 valor_ADC0=0;
int16 valor_ADC1=0;

void lecturaanalogica1 (void) {
   //lectura de canal 0
   set_adc_channel(0);                                 // Seleccionamos el canal 0 y comenzamos a leer.
   delay_us(10);                                       // Esperamos un tiempo para estabalizar el dato leido.
   valor_ADC0 = read_adc();                           // Guarda el valor en una variable               
   //fin de lectura de canal 0
}

void lecturaanalogica2 (void) {
   //lectura de canal 1
   set_adc_channel(1);                                 // Seleccionamos el canal 0 y comenzamos a leer.
   delay_us(10);                                       // Esperamos un tiempo para estabalizar el dato leido.
   valor_ADC1 = read_adc();                           // Guarda el valor en una variable
   //fin de lectura de canal 0
}

void lecturaregladigital(void) {   
   i=0;
   j=0;
   k=0;
   pin_on(req);
      for (i=0; i<13; i++){
         for (j=0; j<4; j++){
            while (!input(clk)) {};
            while (input(clk)) {};
            if (input(dat)==0) bit_clear(k,j);
            if (input(dat)==1) bit_set(k,j);
         }
      datoObtenido[i] = k;
      }
//fin de lectura de la regla digital
}

void main(void) {
   unsigned char datoIN;   // Dato que llega por la USART
   // definiciones del pic:
   set_tris_b(0x00);
   delay_cycles(5);
   pin_off(led1);                           
   pin_off(led2);
   pin_off(led3);
   pin_off(salida1);
   pin_off(salida2);
   setup_adc_ports(AN0_TO_AN1);        // Configura canales usados por el ADC.
   setup_adc(ADC_CLOCK_DIV_64);        // Asigna la velocidad: relog\64.
   // inicio de puerto usb:
   usb_cdc_init();  // Configura el puerto
   usb_init();  // Inicializamos el stack USB.
   usb_task();
   while (!usb_cdc_connected()) {}; // espera a detectar una transmisión de la PC (Set_Line_Coding).
   do{
      usb_task();
      if (usb_enumerated()){  // Espera a que el dispositivo sea enumerado por el host.
        if(usb_cdc_kbhit()){ // En espera de nuevos caracteres en el buffer de recepción.
          //pin_off(led1);
          //pin_off(led2);
          //pin_off(led3);
          datoIN=usb_cdc_getc();   // Lee lo que llego al buffer
          //datoIN debe como un byte, cada bit representa las siguientes funciones
          //bit 7 = Solicita lectura analógica 2
          //bit 6 = Solicita lectura analogica 1
          //bit 5 = Solicita lectura de regla
          //bit 4 = Enciente salida 2
          //bit 3 = Enciende salida 1
          //bit 2 = Enciende led 3
          //bit 1 = Enciende led 2
          //bit 0 = Enciende led 1
          if (!bit_test(datoIN,0)){
            pin_off(led1);
          }
          if (bit_test(datoIN,0)){
            pin_on(led1);
          }
          if (!bit_test(datoIN,1)){
            pin_off(led2);
          }
          if (bit_test(datoIN,1)){
            pin_on(led2);
          }
          if (!bit_test(datoIN,2)){
            pin_off(led3);
          }
          if (bit_test(datoIN,2)){
            pin_on(led3);
          }
          if (!bit_test(datoIN,3)){
            pin_off(salida1);
          }
          if (bit_test(datoIN,3)){
            pin_on(salida1);
          }
          if (!bit_test(datoIN,4)){
            pin_off(salida2);
          }
          if (bit_test(datoIN,4)){
            pin_on(salida2);
          }
          if (bit_test(datoIN,5)==1){
            lecturaregladigital();
            usb_cdc_putc(datoObtenido[]);
          }
          if (bit_test(datoIN,6)==1){
            lecturaanalogica1();
            usb_cdc_putc(valor_ADC0); //no se que va a pasar con esto
          }
          if (bit_test(datoIN,7)==1){
            lecturaanalogica2();
            usb_cdc_putc(valor_ADC1);
          }
        }
      }
   }while (TRUE);
}

pero me quedan unas dudas con usb_cdc_putc(int8)

usb_cdc_putc(datoObtenido[]); ¿se puede enviar una matriz de datos?
usb_cdc_putc(valor_ADC1); ¿se puede enviar un int8?

el compilador no muestra ni advertencias ni errores. tengo que armar el modelo y probar a ver si funciona


 

anything