Muy buenas! gracias por su atención.
Estoy realizando un proyecto con arduino, mi intención: medir vibraciones con un acelerómetro. Para ello he conectado dicho acelerómetro a arduino vía I2C utilizando la librería "wire.h".
Tengo un problema, y es que después de toda la conexión, el conjunto no mide bien. Estoy casi seguro que el problema son los tiempos.
Utilizo matlab para recibir y tratar los datos para hacer un estudio en frecuencia.
Para el timing, he intentado con la programación de los timers, pero creo que entra en conflicto tanto con la librería wire como con la función serial.print (envio los datos hacia matlab por puerto serial). También he intentado utilizar las clasicas funciones micros y milis, sin buenos resultados.
Mi objetivo es que el código se ejecute justamente en 1 milisegundo, para conseguir una frecuencia de muestreo de 1kHz, que es la frecuencia de muestreo del acelerómetro. Adjunto uno de los códigos que he realizado:
#include<Wire.h>
const int MPU_addr=0x68; // I2C address of the MPU-6050
int16_t AcZ;
int tiempo,tiempo1,tiempo2,tiempo3;
int sensibilidad=0;
int filtro=0;
void setup(){
Serial.begin(2000000);
while (!Serial.available()){}
sensibilidad=Serial.read();
delay(1000);
Serial.read();
while (!Serial.available()){}
filtro=Serial.read();
delay(1000);
writeTo(0x6B,0); // inicializa el acelerómetro
writeTo(0x1C,sensibilidad); // configuramos el acelerometro en 24=16g;16=8g;8=4g;0=2g
writeTo(0x1A,filtro); //configuracion del filtro paso bajo para 3=44Hz;0=260Hz;
}
void loop(){
tiempo2=micros();
while (tiempo3<1000){
tiempo3=micros()-tiempo2+tiempo1;
}
tiempo=micros();
Wire.beginTransmission(MPU_addr);
Wire.write(0x3F); // starting with register 0x3F (ACCEL_ZOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,2,true); // request a total of 2 registers
AcZ=Wire.read()<<8|Wire.read();// 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Serial.print(AcZ);
Serial.print('\n');
tiempo1=micros()-tiempo;
tiempo3=0;
}
void writeTo(byte address, byte val) {
Wire.beginTransmission(MPU_addr); // start transmission to device
Wire.write(address); // send register address
Wire.write(val); // send value to write
Wire.endTransmission(); // end transmission
}
Soy bastante novato en el tema, si precisan de mas información solo pregunten. Muchas gracias de nuevo.
Empecemos por esto
Serial.begin(2000000);
A no ser que tengas un DUE no se que arduino te soporta 2M Baudios, menos que menos un UNO como veo indicas.
Asi que eso ya tienes algo para corregir!!
115200 es lo máximo.
Tal vez con suerte algo mas.
Buenas, gracias por responder.
.
Cambié los baudios a unos más adecuados según me dijiste surbyte y no ha habido mejoría.
He descubierto que el siguiente código realiza bien las lecturas cuando programo el periodo de la interrupción a 4 milisegundos ó 250Hz (o menor):
#include<Wire.h>
#include<MsTimer2.h>
const int MPU_addr=0x68; // I2C address of the MPU-6050
volatile int16_t AcZ;
int frecuencia=1000;
int sensibilidad=0;
int filtro=0;
void setup(){
Serial.begin(115000);
while (!Serial.available()){}
sensibilidad=Serial.read();
delay(1000);
Serial.read();
while (!Serial.available()){}
filtro=Serial.read();
delay(1000);
Wire.begin();
writeTo(0x6B,0); // inicializa el acelerómetro
writeTo(0x1C,sensibilidad); // configuramos el acelerometro en 24=16g;16=8g;8=4g;0=2g
writeTo(0x1A,0); //configuracion del filtro paso bajo para 3=44Hz;0=260Hz;
MsTimer2::set(4,readvalue);
MsTimer2::start();
}
void readvalue(void){
sei();
Wire.beginTransmission(MPU_addr);
Wire.write(0x3F); // starting with register 0x3F (ACCEL_ZOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,2,true); // request a total of 2 registers
AcZ=Wire.read()<<8|Wire.read();// 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Serial.print(AcZ);
Serial.print('\n');
}
void loop(){
}
void writeTo(byte address, byte val) {
Wire.beginTransmission(MPU_addr); // start transmission to device
Wire.write(address); // send register address
Wire.write(val); // send value to write
Wire.endTransmission(); // end transmission
}
Estoy probando la exactitud de la medida a través de una herramienta generadora de tonos online y un altavoz, lo excito a 100Hz y realiza bien la lectura.Cuando intento aumentar la velocidad de muestreo, los resultados empiezan a ser incorrectos.
He medido el tiempo que toma realizar las instrucciones de la función llamada con la interrupción, y es menor a 1 milisegundo, en concreto 684 microsegundos. Claro, lo he leído con la función micros(), la cual he leído por ahí parece que entra en conflicto con los timers...
No tengo ni idea de porque ocurre esto, como ya he dicho, he probado con diversas librerías para los timers, ademas de códigos similares al del primer post.
Muchas gracias por su ayuda.
No dije que funcionaría a 115200, solo que 2Mhz no es un valor utilizable por un UNO en el puerto serie.
El código es tu responsabilidad. No se de donde lo sacaste pero si esta fallando, yo presiono siempre RESET, ME OLVIDO de lo que esta fallando y vuelvo al demo mas próximo del que partí.
Empiezo nuevamente y voy introduciendo cambios y lo documento en mi libreta.
Paso a paso elaboro lo que busco y sino se donde fallé.
Bien, empecemos por lo básico.
El MPU6050 presenta bien los datos x puerto serie? no dije MATLAB olvida MATLAB por ahora.
Si eso funciona correctamente, entonces a un código que presenta los datos correctamente por puerto serie solo debes agregarle la comunicación esperable por MATLAB.
surbyte:
El MPU6050 presenta bien los datos x puerto serie?
Sí, la comunicación está hecha, el código funciona. El problema que no para periodos inferiores a 4 milisegundos. He mirado en el foro y este problema es común, solo quería saber si alguien tenia alguna idea.