Aumentar la frecuencia de muestreo (Solucionado)

Hola de nuevo, recién hago la prueba de cambiar el factor de división del prescaler lo llevé a 64 y luego a 32 pero hay algo que no me cierra, esto es una copia del archivo que me guarda el realterm
microseg lectura
61486888 26
61488576 25
61490264 26
61491944 25
61493640 26
61495320 26
61497000 26
61498696 26
La diferencia entre lectura y lectura son 1680 microsegundos, sigo estando en la misma, no hay lecturas intermedias o al menos no se guardan, serán demasiados datos que pasan al puerto serie? para cualquier curva por lo menos necesito tres lecturas
El codigo quedó asi
/*
Barrera de luz
*/
// to the pins used:

const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
int sensorValue = 0; // value read from the pot
//int outputValue = 0; // value output to the PWM (analog out)
unsigned long time;

void setup() {
pinMode(13, OUTPUT);
ADCSRA|= (1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);
// initialize serial communications at 9600 bps:
Serial.begin(115200);
}

void loop() {
digitalWrite(13, HIGH);
// read the analog in value:
sensorValue = analogRead(analogInPin);
// print the results to the serial monitor:
//Serial.print("Time: ");
time = micros();
Serial.print(time);
Serial.print(" ");
Serial.println(sensorValue);

}

El problema es el puerto serie.... ahora mismo estoy haciendo pruebas con cosas parecidas.... ]:smiley:
Las rutinas de Arduino son muy lentas. Existen librerías por la red, que consiguen 1 Mbps y más!! (google).

No te aseguro que el programa este perfectamento, ya que esta un poco verde (en vez de guardar micros que son 4 bytes (unsigned long), se podría calcular la frecuencia de muestreo, y ya sabrías el tiempo entre dato y dato, pero asi compruebo que todo cuadra).
Es la adquisición de la red eléctrica= 50 Hz (T=20ms) (proveniente de un trafo y adaptada). Lo conecto a la entrada analógica 5.

#define mysize 200

unsigned long mytime[mysize];
byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
  
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0        - 0       - 0        ->2
  //0        - 0       - 1        ->2
  //0        - 1       - 0        ->4
  //0        - 1       - 1        ->8
  //1        - 0       - 0        ->16
  //1        - 0       - 1        ->32
  //1        - 1       - 0        ->64
  //1        - 1       - 1        ->128
  ADCSRA|= (1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0);  //Prescaler=32
  
  //Free running mode
  ADCSRB|=(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);
  
  //Entrada A5
  ADMUX|=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}


void loop()
{

  for (int i=0; i<mysize;i++)
  {
     mytime[i]=micros();
     mydata[i]=analogReadFast(); 
     delayMicroseconds(500); 
  }
  
  Serial.println("Nuevo");
  for (int i=0; i<mysize;i++)
  {
    Serial.print(mytime[i]);
    Serial.print(" ");
    Serial.println(mydata[i],DEC); 
  }
  
}

int analogReadFast()
{
	ADCSRA|=(1<<ADSC);
	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Lo que hago es copiar del texto "Nuevo" al siguiente "Nuevo" capturado por la consola, y lo pego en una hoja de cálculo. Sólo estoy usando 8 bits de resolución.
Como ves me he creado un buffer para guardar los datos y luego los dibujo. He puesto un pequeño delay, porque era demasiada frecuencia de muestreo!!!

Habría que hacer la prueba, usando analogRead que trae Arduino...

Salu2

Igor R.

Ese delay me limita a 2ms, se puede quitar? intento medir eventos del orden de los microsegundos.

He encontrado un gazapo en mi código.... Ahora si funciona como debería! La configuración de los registros con |= no fue buena idea..... :smiley:

#define mysize 600

unsigned long tStart;
unsigned long tEnd;
byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
  
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0        - 0       - 0        ->2
  //0        - 0       - 1        ->2
  //0        - 1       - 0        ->4
  //0        - 1       - 1        ->8
  //1        - 0       - 0        ->16
  //1        - 0       - 1        ->32
  //1        - 1       - 0        ->64
  //1        - 1       - 1        ->128
  //Configure to Prescaler=32
  bitWrite(ADCSRA,ADPS2,1);
  bitWrite(ADCSRA,ADPS1,0);
  bitWrite(ADCSRA,ADPS0,1);
  
  //Entrada A5
  ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}


void loop()
{

  tStart=micros();
  for (int i=0; i<mysize;i++)
  {
     mydata[i]=analogReadFast(); 
  }
  tEnd=micros();
  
  Serial.println("NEW ACQUISITION");
  Serial.print("tStart=");
  Serial.println(tStart);
  Serial.print("tEnd=");
  Serial.println(tEnd); 
  Serial.print("nPoints=");
  Serial.println(mysize);
  
  for (int i=0; i<mysize;i++)
  {
    Serial.println(mydata[i],DEC); 
  }
  
}

int analogReadFast()
{
	ADCSRA|=(1<<ADSC);
	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Ahora son 35.6 kHz!! Es decir, 28 us por sample!! El módulo del ADC con el prescaler=32 está trabajando 500 kHz y estoy utilizando 8 bits.

:wink:

Enhorabuena !!

Me encanta cuando se llega a base de quebraderos de cabeza a soluciones asi, en este caso una precisión de muestreo muy superior a la inicial
por ahora esto no me sirve pero estoy seguro que en el futuro le podre dar uso.

al playground ??? :wink:

Por supuesto que al playground!! Arduino Playground - FAQ
Ahora hay que investigar unas rutinas mejor optimizadas para conseguir 1Mbps por el puerto serie para poder mostrar los datos a "tiempo real".

:grin:

A la pelotita!! con guitarra es otra cosa, apenas llego lo pruebo, eso si me sirve!!!

¿Puedes probar ha importar los datos adquiridos en KST y hacer un "Power Spectrum" de los datos adquiridos de la guitarra? Te debería salir la frecuencia de la nota tocada...
Como puedes ver el programita envia el tiempo de inicio,de fin de la adquisición (en microsegundos) y el número de puntos. Por lo que de ahí puedes sacar la frecuencia de muestreo para el cálculo de la FFT.
Adjunto lo que se obtiene de la adquisición de la señal de la red.... los 50 Hz, claro!! :smiley: (En concreto el pico es 51.9 Hz, cuando lo hago con Matlab es 50.21 Hz,aunque no he entrado en detalle sobre las opciones de configuración que te deja el KST ...)

Estoy renegando, parece que no estoy sabiendo como ver los datos, al principio me marca el tiempo de inicio y fin y todos los datos que vió en ese tiempo en una columna.
Je je me esperaba dos columnas, aca tengo que ingresar el intervalo de tiempo en kst, ya he logrado ver algo pasando un alambre finito frente al sensor a la mayor velocidad que pude, aunque todavía no tengo claro algunas cuestiones, el archivo que me graba esta en intervalos de 600 puntos y 16800 microsegundos 28 microseg por sample, luego otro intervalo igual, no estoy seguro que lee el kst2 cuando pasa de un
período a otro.
Hay algún tutorial de kst2 en español?
Igor, muchas gracias por llevarme el apunte, soy un renovato y sin embargo gastas tu tiempo en contestar y explicar, muchas gracias, creo que estas lejos para mandarte un vino, mejor me lo tomo a tu salud :slight_smile:

La verdad que no hay mucha info del KST.... o por lo menos desconozco de algún sitio.

Te explico yo lo que hago para este caso concreto:

  1. Lo primero es que no alimento el KST directamente con los datos del puerto serie.
  2. Copio de la propia consola serie que viene con el IDE de Arduino de "New Acquisition" hasta el siguiente "New".
  3. Lo pego en una hoja de cálculo y la guardo en formato *.csv. Para generar el .csv, quito en la hoja de cálculo la parte de tstart, tend, número de puntos, etc. (es decir, me quedo sólo los datos adquiridos). Lo que hago es tener dos hojas en la hoja de cálculo, una para copiar tal cual y otra para crear el .csv.
    ¿por qué hago ésto? Porque me he creado las cuentas para que automáticamente calcule la frecuencia de muestreo sabiendo tstart,tend y el número de puntos. Ya que para mi aplicación le meto un delayMicroseconds() en el for para poder tener más datos. No necesito ir a la máxima velocidad, ya que estoy muestreando una onda de 50 Hz.
    También uso la propia hoja de cálculo para graficar los datos. Para calcular la columna de tiempo, pues el primer dato será 0, el segundo fs, el tercero 3
    fs,el cuarto 4
    fs..... siendo fs (frecuencia sample). La hoja de cálculo hace todo este trabajo por mi....
  4. Importo los datos del fichero *.csv con KST.

¿tiene sentido ésto? Eso sí, cuando lo consigas quiero ver una entrada en tu blog que expliques todo el proceso,así sirve para los demás.... :smiley:
Tengo curiosidad por ver la nota de tu guitarra con la FFT.....je,je,je

:wink:

Estoy flipando con este hilo, que pasada. :astonished: Si juntais todo lo que comentas y lo pones en Playground como Manual o como Proyecto porque tela la cantidad de información que hay en este hilo.

Yo estaba jugando con el cálculo de cruce por cero y de mirar de controlar un tiristor.... y Cesar me está liando!!! :smiley:
He terminado haciendo estudio frecuencial!!
Pero ahora podré usar el propio Arduino de osciloscopio para ver lo que hace el dichoso tiristor....

:wink:

:slight_smile: me gusta encontrarme con gente con las mismas inquietudes, desde que tengo eta placa (un mes mas o menos) no he dormido de corrido...
Igor ya veré como me arreglo con los datos en caso de un solo pico como es el caso de la flecha, aumentaré el numero de lecturas de 600 a un numero mayor es distinto con una secuencia como en el caso de los 50 hz.
Lo del osciloscopio es algo que vi por ahí y me interesa, de hecho he comprado un LCD en ebay de los de color que vienen ya preparados para arduino http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=130559552758&ssPageName=ADME:L:OC:US:1123 aún no llega
La prueba de la guitarra te la debo hasta la semana que viene, hoy a mediodia viajo hasta el domingo asi que quedaré stand by.

Hola,

Ya que estoy, he seguido haciendo pruebas. Ahora manda todo el rato por el puerto serie (Cuidado que usos los registros de Arduino con ATMega 328 o 168).
Lo envia el byte tal cual, sin pasarlo a ASCII, de esta forma sólo tengo que enviar 2 bytes (uno es el dato adquirido y otro el separador [Nueva linea] ). He seguido dejando el formato del for (aunque ahora es bucle infinito), por si se quiere modificar para validar la frecuencia. Me sale una frecuencia de 5882 Hz enviando a 115200 a tiempo real... lo cual no está nada mal!!
Lo malo, que ahora hay que hacerse un pequeño soft para ir mostrando a tiempo real,ya que no mando en ASCII. Aunque yo uso LibreOffice para convertir de ascii a número.
Con Ubuntu, lo que he hecho es:

  1. Usar Cute Com para grabar en un archivo, le doy extensión .c para que me lo abra el gEdit.
  2. Abro el fichero grabado con el gEdit (vereis que salen símbolos raros). Selecciono todo y copio.
  3. Abro el LibreOffice y pego los datos (es una columna).
  4. Me creo otra columna, la cual convierte esos carácteres ASCII que he pegado a número. Para ello uso la función UNICODE.
  5. Me creo la columna tiempo, que empieza desde cero y a va aumentando cada 0.1699933333 ms (ya que la fs=5.882 Khz)
  6. Gráfico en el propio LibreOffice o exportas en *.csv para KST.
  7. Si se exporta a KST, cuando hago el "Power Spectrum" de los datos, la frecuencia es 5882.5836307306 Hz. Con esto me sale el pico a 50.27 Hz, por lo que parece que todo tiene sentido.... :smiley:
#define mysize 1200

unsigned long tStart;
unsigned long tEnd;
byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
  
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0        - 0       - 0        ->2
  //0        - 0       - 1        ->2
  //0        - 1       - 0        ->4
  //0        - 1       - 1        ->8
  //1        - 0       - 0        ->16
  //1        - 0       - 1        ->32
  //1        - 1       - 0        ->64
  //1        - 1       - 1        ->128
  //Configure to Prescaler=32
  bitWrite(ADCSRA,ADPS2,1);
  bitWrite(ADCSRA,ADPS1,0);
  bitWrite(ADCSRA,ADPS0,1);
  
  //Entrada A5
  ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}


void loop()
{

  tStart=micros();
  for (;;)
  {
    while (!(UCSR0A & (1 << UDRE0)));
    UDR0 = analogReadFast();
    
    while (!(UCSR0A & (1 << UDRE0)));
    UDR0 = 10;
  }
  tEnd=micros();
  
  Serial.println("NEW ACQUISITION");
  Serial.print("tStart=");
  Serial.println(tStart);
  Serial.print("tEnd=");
  Serial.println(tEnd); 
  Serial.print("nPoints=");
  Serial.println(mysize);  
}

int analogReadFast()
{
	ADCSRA|=(1<<ADSC);
	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Ahora ya no hay límite de datos!!!

Captura del LibreOffice (columna en amarillo datos de entrada):

Captura del KST:

Hay librerías optimizadas para hacer conexión serie a 1 Mbps con Arduino. Yo aquí lo que he hecho es copiar y pegar lo que se usa en la función Serial.Write del core.

¿Alguien tiene un generador de ondas para probar diferentes ondas/frecuencias?

Espero que sirva!

Salu2

Igor R.

Hola,

Sin tener mucha idea de Python, pero he creado un pequeño script que lee del puerto serie y convierte de ASCII al número equivalente (Unicode) los datos recibidos por el Arduino:

#! /usr/bin/env python

import serial


ser = serial.Serial('/dev/ttyUSB0', 115200);
while 1:
    n=ser.read();
    n=ord(n);
    print n;

Ahora ya no se necesita enviar otro byte para separar datos, así que tenemos una frecuencia de 11761.938367443 Hz !! (lo pongo con tanto decimal para introducirlo en KST en el apartado de frecuencia de muestreo).

Es decir:

//#define mysize 1200

unsigned long tStart;
unsigned long tEnd;
//byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
  
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0        - 0       - 0        ->2
  //0        - 0       - 1        ->2
  //0        - 1       - 0        ->4
  //0        - 1       - 1        ->8
  //1        - 0       - 0        ->16
  //1        - 0       - 1        ->32
  //1        - 1       - 0        ->64
  //1        - 1       - 1        ->128
  //Configure to Prescaler=32
  bitWrite(ADCSRA,ADPS2,1);
  bitWrite(ADCSRA,ADPS1,0);
  bitWrite(ADCSRA,ADPS0,1);
  
  //Entrada A5
  ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}


void loop()
{

  tStart=micros();
  
  //for (int i=0;i<mysize;i++)
  //frec=11761.938367443
  for (;;)
  {
    while (!(UCSR0A & (1 << UDRE0)));
    UDR0 = analogReadFast();
  }
  tEnd=micros();
  
  Serial.println("NEW ACQUISITION");
  Serial.print("tStart=");
  Serial.println(tStart);
  Serial.print("tEnd=");
  Serial.println(tEnd); 
  Serial.print("nPoints=");
  Serial.println(mysize);  
}

int analogReadFast()
{
	ADCSRA|=(1<<ADSC);
	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Ahora ya se gráfica a tiempo real con KST!!!

El script de Python se graba, por ejemplo, en un fichero llamado adquisicion
Le damos permisos de ejecución e iniciamos de forma ./adquisicion >> mifichero.csv

Ahora sólo con importar dicho fichero con KST y tendremos dibujando a tiempo real a 11.7 kHz!!!
Se puede ir viendo las fluctuaciones de la frecuencia de red (el pico es a 49.94 Hz) !! A continuación una captura de 6583841 datos!!! (la gráfica superior tiene zoom para que se aprecie mejor porque tiene un montonazo de datos.....)

Ahora si!!

:wink:

Vaya nivelaco que hay en el foro. Igor te lo he dicho alguna vez pero te lo digo otra vez eres un crack.
CesarCarlos muy interesante tu pagina, buen trabajo.

Saludos.

:slight_smile: :slight_smile: sos terriblemente obsesivo Igor y una masa en programación, felicitaciones, en este momento ando de viaje, hasta el domingo no llego a mi pueblo grrrrr!!!! me salgo de la vaina por probar.
Gracias flico por lo que me toca.

No es para tanto, flico! :wink:
Cesar,como molan las expresiones argentinas!! :smiley:

No me he podido aguantar y he conectado otro Arduino a mi nuevo Osciloscopio+PSD.... El segundo Arduino está generando una onda cuadrada con la orden analogWrite (la frecuencia de este PWM es de aprox 490 Hz). http://www.arduino.cc/en/Reference/AnalogWrite

¿A qué no sabeis que me ha salido?

Además, en la tercera gráfica se pueden observar los diferentes armónicos (es una señal cuadrada).

No te pienses que todas las dudas del foro las sigo así, ehhh!!! Ha coincidido que tengo unos días libres, y estaba jugando con algo relacionado....

:smiley:

chapó ...

Yo uso el siguiente código para hacer lecturas ultra-rápidas, son 19.04us entre lecturas.

Básicamente uso un array de 3500 int (por temas de memoria) con el preescaler a 16. Enviando algo por el serial el programa toma las 3500 lecturas en menos de 70ms.

-EL hilo en inglés donde justifican el código:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11

-Y el documento de Atmel que dice que a 1Mhz se pierde poco:

#include <avr/pgmspace.h>
int longitud=3500;
int  lecturas[3500] ;
double   inicio,fin;

void setup(){

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
  Serial.begin(1000000);
analogRead(0);// lectura que tarda 25 ciclos, el resto 13.


}


void loop(){
  
  if(Serial.available()!=0){
  lectura();
 envio();
 Serial.flush();
 }

}




void lectura(){
  
 

  inicio=micros();
for(int i=0;i<(longitud);i++){
 lecturas[i]   =analogRead(0);
}
fin= micros();
  Serial.println(fin);
}
void envio(){
  double tiempo=fin-inicio;
  Serial.print("tiempo empleado:");
  Serial.print(tiempo);
  Serial.println("microsegundos");
for(int i=0;i<(longitud);i++){
 Serial.print(i);
  Serial.print(",");
   Serial.println(lecturas[i]);
 


}
}