Autor Tema: ADC externo en ciclo do while y tiempo de envio por usb  (Leído 3059 veces)

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

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
ADC externo en ciclo do while y tiempo de envio por usb
« en: 05 de Enero de 2017, 11:16:41 »
Hola, tengo una duda con el ciclo do while y un adc externo dentro del ciclo. el adc tiene fsample de 200khz, pero las muestras que me llegan a labview es cada 8ms sin poner retardo en el ciclo do while ni en labview, osea en un 1s conte 125 muestra.
esta bien? creo que tomo fs del  envio y no del adc cuando tengo los datos en labview.

Desde ya gracias..

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #1 en: 05 de Enero de 2017, 12:46:52 »
Podrias dar mas datos? sobre que ADC estamos hablando?

La otra es que si es externo, lo mejor es que uses interrupciones para tomar las medidas. Aunque imagino que vos se las tenes que pedir.

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #2 en: 05 de Enero de 2017, 16:22:26 »
Podrias dar mas datos? sobre que ADC estamos hablando?

La otra es que si es externo, lo mejor es que uses interrupciones para tomar las medidas. Aunque imagino que vos se las tenes que pedir.

Hola, el adc es ads7841 es de 12bits por SPI utlilizo esto:
configuracion:
setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_XMIT_L_TO_H|SPI_CLK_DIV_16);

tomar datos:
                        output_low(CS);
                         spi_write(220);/* canal 3*/
                        flujoh=spi_read(0);
                         flujol=spi_read(0);
                         output_high(CS);
                        flujoh = flujoh & 0x7F;
                            flujo16bits=make16(flujoh,flujol);//convertimos a un registro de 16Bits
                         flujo16bits=flujo16bits>>3;
                        enviar[1]=flujo16bits;

eso en el ciclo do while y lo envio por usb del tipo bulk que esta configurado asi:

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#DEFINE USB_HID_DEVICE  TRUE
#define USB_EP1_TX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for IN bulk/interrupt transfers
#define USB_EP1_TX_SIZE    8
#define USB_EP1_RX_ENABLE  USB_ENABLE_INTERRUPT   //turn on EP1 for OUT bulk/interrupt transfers
#define USB_EP1_RX_SIZE    8
#include <pic18_usb.h>//Funciones de bajo nivel(hardware) para la serie PIC 18Fxx5x que serviran en usb.c
#include <usb_desc_hid.h>//Aqui es donde van las descripciones de este dispositivo (como lo reconocera windows)

para el envio:
 usb_put_packet(1, enviar, 8, USB_DTS_TOGGLE);


Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #3 en: 05 de Enero de 2017, 17:51:10 »
El ADC soporta una conversion de hasta 200KHz pero eso no significa que te este dando esa cantidad.

Si quisiera tomar datos de un ADC porque debo hacer un muestreo, utilizaria un timer que me fije una base de tiempo, de esa forma cada X tiempo estaria mi muestra.
Esto en una interrupcion, dentro de esa interrupcion procedo a decirle que el SPI envie el inicio de conversion.

Luego en la interrupcion del SPI, la primer entrada la omito (que es la que entra cuando envio el dato desde el timer ), la 2da lo guardo en una variable temporal, y luego la siguiente la guardo en un buffer. Todo esto en la interrupcion del SPI y sin demoras.

Con esto ya tenemos que los datos que se tomaron son correctos y en el tiempo correcto.
La parte del USB, que lo maneje el main, cuando ya tiene cierta cantidad de datos, proceda a enviarlos. Lo mejor creo que va a ser es usar algun tipo de buffer circular para este caso, o 2 buffers.

Lo mas seguro que te esta bloqueando es el tiempo que necesita el USB hasta que ser atendido y enviar los datos, tambien puede ser  mucha cabecera para enviar solo una lectura y finalmente tambien puede ser la velocidad del SPI.
De la forma que digo logras que por mas que se tarde el USB en enviar sigas tomando los valores de forma correcta. Si no llega a enviar todos los datos de forma correcta, entonces deberias aumentar el tamaño del buffer, o por ultimo tratar de bajar la velocidad de muestreo.

Tambien depende de frecuencia de oscilador tenga tu PIC, Ya que el ADC soporta CLK de hasta 3.33Mhz (a 5V), pero no tenes demasiadas opciones para elegir.

« Última modificación: 05 de Enero de 2017, 18:18:41 por KILLERJC »

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #4 en: 05 de Enero de 2017, 21:32:31 »
El cristal es de 20 MHz, es un pic 18f4550,
Cómo lo haría con interrupciones osea el código cómo guia?, uso el picc compiler.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #5 en: 05 de Enero de 2017, 22:13:03 »
Como te lo explique antes....

¿Cuando entra a una interrupcion un timer? Cuando rebalsa

¿Cuando entra a la interrupcion el SPI? Cuando termina de enviar/recibir.

Estos datos mas lo que te dije antes deberias poder hacer aunque sea el codigo.

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #6 en: 06 de Enero de 2017, 09:36:00 »
Ok, muchas gracias por la ayuda.

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #7 en: 09 de Enero de 2017, 16:01:20 »
#int_timer1
void timer1(){

                         output_low(CS);
                         spi_write(220);/* canal 3*/
                         flujoh=spi_read(0);
                         flujol=spi_read(0);
                         output_high(CS);
                         flujoh = flujoh & 0x7F;
                         flujo16bits=make16(flujoh,flujol);//convertimos a un registro de 16Bits
                         flujo16bits=flujo16bits>>3;
                         Datos=flujo16bits;
                         i++;
 
SET_TIMER1(65035);
}

Esta la idea para obtener los datos en el timer1 para una fs de 6Khz y cargarlo en un vetor Datos y despues en el main enviarlo por usb. No se si esta bien.
En el vector datos cual es el maximo de valores que puedo cargar con esa fs?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #8 en: 09 de Enero de 2017, 16:57:21 »
Vamos a ver..

Lo primero que deberias hacer es calcular cuanto tarda tu SPI en enviar y recibir. Vamos a hacer los calculos con numeros sencillos, tenes que enviar 1 dato y luego recibir 2, por lo tanto son 3 veces las que vas a enviar/recibir,  Supongamos (los valores que doy no son reales son para el ejemplo) que esto tarda 1ms cada uno de los datos. es decir 3ms en total.

Si tuviera esos valores, la interrupcion del timer deberia ser de 4ms o mas siendo realista, supongamos cada 5ms el timer entra a la interrupcion.
Ya con esto definimos el tiempo minimo del timer.

Dije que teniamos que usar la interrupcion del SPI tambien.
El timer es quien me da el comienzo de toda la trama:

Código: C
  1. #int_timer1
  2. void timer1(){
  3.         SET_TIMER1(40000);
  4.         output_low(CS);
  5.         spi_write(220);/* canal 3*/
  6.         estado = 0;
  7. }

Cuando termina de transmitir, procede a entrar a la interrupcion del SPI ( Voy a poner directivas que no existen!!! Por que no se el nombre ).
En este caso segun el valor de estado procedo a poner el dato en un lugar o no.

Código: C
  1. #int_SPI
  2. void spi()
  3. {
  4.         switch(estado)
  5.         {
  6.         case 0:
  7.                 spi_write(0);                           // escribo 0
  8.                 estado++;                               // Aumento de estado
  9.                 break;                                  // salgo
  10.         case 1:
  11.                 flujoh = spi_read() & 0x7F;             // Tomo el primer valor
  12.                 spi_write(0);                           // Envio otro 0 para recibir lo demas
  13.                 estado++;                               // Aumento de estado
  14.                 break;                                  // Salgo
  15.         case 2:
  16.                 flujol = spi_read();                    // Tomo el segundo valor
  17.                 ouput_high(CS);                         // Finalmente apago el CS
  18.                 flujo16bits = make16(flujoh,flujol);    // Creo la variable de 16 bits
  19.                 flujo16bits >>= 3;                      // Divido por 8
  20.                 estado++;                               // Aumento de estado
  21.                 break;                                  // Salgo
  22.         default:                                       
  23.                 break;                                  // En caso que estado no sea ninguno de los anteriores
  24.         }
  25. }

Ahora ese flujo16bits deberia almacenarlo en un buffer ( array ) para que luego el USB proceda a enviarlo a todo. Nomas que este array ademas del mismo tenes que tener un indice para saber que elementos fueron enviados o no, en si un buffer circular seria lo ideal, asi este codigo procede a poner datos y el codigo del USB procede a enviarlos.

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #9 en: 10 de Enero de 2017, 11:52:01 »
Ah ok gracias..

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #10 en: 11 de Enero de 2017, 09:51:37 »
Simule tu codigo pero no volvia a high CS(SS en la simulacion), entonces saque la variable estado del timer1 (esta declarado como global con cero) y despue en el case 2 cambie estado++ por estado=0 y ahi la simulacion dio esto(adjunto imagen):



« Última modificación: 11 de Enero de 2017, 09:54:47 por hernanutn »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #11 en: 11 de Enero de 2017, 11:09:27 »
Simule tu codigo pero no volvia a high CS(SS en la simulacion), entonces saque la variable estado del timer1 (esta declarado como global con cero) y despue en el case 2 cambie estado++ por estado=0 y ahi la simulacion dio esto(adjunto imagen):

El problema no estaba en el codigo... el problema estaba en el tiempo del timer. ¿ Probaste darle un tiempo mayor de interrupcion al timer ? Excedete con el tiempo ( si tenias cada 1ms ponele 5ms de interrupcion, a esto me refiero con excederte) y usa el codigo que te pase. Fijate si CS ahora vuelve a 1. Por eso lo primero que escribi antes del codigo fue:

Citar
Lo primero que deberias hacer es calcular cuanto tarda tu SPI en enviar y recibir...................Ya con esto definimos el tiempo minimo del timer.

Los problemas que pienso que tenias con el codigo es lo siguiente:

Timer - envia el primer dato
SPI - termina y envia otro dato ( 0 ) (estado = 0)
SPI - termina, envia (0) y recibe lo anterior ( estado = 1)
Posiblemente aca tenias otra interrupcion del timer ( antes de la del SPI ). poniendo estado = 0 , e inhabilitando a que entre en estado = 2 que es quien pone CS en alto.
No solo eso sino que ademas el spi_write estoy mas que seguro que espera hasta que el SPI este libre, por lo cual va a estar atrapado en la interrupcion del timer hasta que se libere.
Si esto ocurre tambien se perderia el otro valor y nunca se actualizaria flujo16bits.

Es la unica forma que se me ocurra que puede ocurrir esto. Otra no hay, para mi el tiempo era muy poco, asi como lo arreglaste, el tiempo del timer simplemente no tiene sentido, es mas seria mejor quitarlo. Ya que el tiempo entre muestras ahora estaria dado no por el timer, sino por lo que tarda en enviarse todo lo del SPI. Y que para saberlo a ciencia cierta, deberias medir desde que se pone a 0 CS hasta que se pone a 0 de vuelta.
« Última modificación: 11 de Enero de 2017, 11:19:55 por KILLERJC »

Desconectado hernanutn

  • PIC16
  • ***
  • Mensajes: 117
Re:ADC externo en ciclo do while y tiempo de envio por usb
« Respuesta #12 en: 11 de Enero de 2017, 12:20:53 »
use este codigo con un timer de 1ms:
Código: [Seleccionar]
#include <18f4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL5,CPUDIV1
#use delay(clock=48000000)
#use standard_io(B)
#define CS PIN_B2
int16 contador=0;
int8 estado=0;
int8 flujol,flujoh;
int16 flujo16bits=0;
#int_timer1
void timer1(){
      SET_TIMER1(62532);
       
        output_low(CS);
        spi_write(220);/* canal 3*/
       estado = 0;
       

}
#int_SSP
void  SSP() {
 switch(estado)
        {
        case 0:
                spi_write(0);                           // escribo 0
                estado++;                               // Aumento de estado
                break;                                  // salgo
        case 1:
                flujoh = spi_read() & 0x7F;             // Tomo el primer valor
                spi_write(0);                           // Envio otro 0 para recibir lo demas
                estado++;                               // Aumento de estado
                break;                                  // Salgo
        case 2:
                flujol = spi_read();                    // Tomo el segundo valor
                output_high(CS);                         // Finalmente apago el CS
                flujo16bits = make16(flujoh,flujol);    // Creo la variable de 16 bits
                flujo16bits >>= 3;                      // Divido por 8
                estado++;                               // Aumento de estado
                break;                                  // Salgo
        default:                                       
                break;                                  // En caso que estado no sea ninguno de los anteriores
        }
}

             


void main(){


setup_timer_1(T1_INTERNAL |T1_DIV_By_4 );
SET_TIMER1(62532);
enable_interrupts(INT_TIMER1); // Habilitamos la interrupción que deseamos
enable_interrupts(GLOBAL); //Habilita int. general
set_tris_b(0x29);                                        /*configuro el puerto B para que el RB0,RB3 y RB5 como entrada*/
setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_XMIT_L_TO_H|SPI_CLK_DIV_16);       /* SPI_CLK_DIV_16  SPI_XMIT_L_TO_H */ 
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);

 /* output_low(CS);
  spi_write(0xbb);// canal 2
  flujoh=spi_read(0);
  flujol=spi_read(0);
  output_high(CS);*/

while(TRUE);

                 
}

y obtuve esto en la simulacion (imagen timer1_1):


Y con esta parte del codigo para ver el tiempo del spi (imagen timer1_2):
Código: [Seleccionar]
output_low(CS);
  spi_write(0xbb);// canal 2
  flujoh=spi_read(0);
  flujol=spi_read(0);
  output_high(CS);


Igual  queria ver los tiempo en la simulacion y despue implementarlo.


 

anything