Muy buenas!! Espero que estén bien haciendo sus quehaceres!
Tengo aquí, un muy buen proyecto, que una vez listo, me encantaría subirlo bien explicado al foro, ya que tiene muchísimas cosas útiles.
El proyecto se trata de un arduino UNO al cual se encuentran conectados: 2x acelerómetros, una tarjeta SD, un reloj RTC DS1307, y una tarjeta BluetoothBee, a través de la cual conecto el arduino al computador, mediante un puerto COM virtual. Cuenta además con un botón normal y un led indicador. Todo funciona muy bien, excepto por una cosa, que es mi pregunta de hoy.
El código lo muestro más abajo.
Antes de hacer lo que dije (subir esto al foro completamente), necesito resolver un último problemita. Verán en el código (un poco largo, pero no difícil de entender), que hay una sección donde hay un "for", donde dentro de el se envía por serial una larga cadena de datos, que son los datos obtenidos desde los acelerómetros.
El problema es, que a veces y no siempre, el programa al tomar las mediciones y enviármelas por serial, se cuelga. No me queda otra que resetearlo... Cada vez que aprieto el botón el cual es leído por el primer "while" de la función "loop()", se comienza con la toma de datos, y es precisamente allí donde a veces llega hasta la mitad de la medición sin entregar el último valor leído en forma completa, y ... ya se pegó de nuevo. A veces funciona muy bien, y hace la medición completa.
Las condiciones del entorno son, que No hay ruido electromagnético o muy poco (escritorio, no hay router cerca) y que las conexiones están casi todas soldadas y bien conectadas. Mientras mido, no toco el circuito con nada.
Alguien me podría decir entonces, cuál es o podría ser una razón para que el programa se quede pegado en la parte del "for"? Puede ser por culpa de la programación? O solamente podría ser por algo de hardware?
Muchísimas gracias, y además, gracias por la paciencia.
Muchos saludos!!
Tengo aquí, un muy buen proyecto, que una vez listo, me encantaría subirlo bien explicado al foro, ya que tiene muchísimas cosas útiles.
El proyecto se trata de un arduino UNO al cual se encuentran conectados: 2x acelerómetros, una tarjeta SD, un reloj RTC DS1307, y una tarjeta BluetoothBee, a través de la cual conecto el arduino al computador, mediante un puerto COM virtual. Cuenta además con un botón normal y un led indicador. Todo funciona muy bien, excepto por una cosa, que es mi pregunta de hoy.
El código lo muestro más abajo.
Antes de hacer lo que dije (subir esto al foro completamente), necesito resolver un último problemita. Verán en el código (un poco largo, pero no difícil de entender), que hay una sección donde hay un "for", donde dentro de el se envía por serial una larga cadena de datos, que son los datos obtenidos desde los acelerómetros.
El problema es, que a veces y no siempre, el programa al tomar las mediciones y enviármelas por serial, se cuelga. No me queda otra que resetearlo... Cada vez que aprieto el botón el cual es leído por el primer "while" de la función "loop()", se comienza con la toma de datos, y es precisamente allí donde a veces llega hasta la mitad de la medición sin entregar el último valor leído en forma completa, y ... ya se pegó de nuevo. A veces funciona muy bien, y hace la medición completa.
Las condiciones del entorno son, que No hay ruido electromagnético o muy poco (escritorio, no hay router cerca) y que las conexiones están casi todas soldadas y bien conectadas. Mientras mido, no toco el circuito con nada.
Alguien me podría decir entonces, cuál es o podría ser una razón para que el programa se quede pegado en la parte del "for"? Puede ser por culpa de la programación? O solamente podría ser por algo de hardware?
Muchísimas gracias, y además, gracias por la paciencia.
Muchos saludos!!
Código:
#include <SD.h> // Librería de la tarjeta SD que incluye SPI. Se molestará junto con la librería SPI, siesque se usa.
#include <Wire.h> // Librería de comunicaciones I2C. Por defecto: 100kHz.
#define ADLX_A (0x1D) // Dirección I2C del Acelerómetro 1
#define ADLX_B (0x53) // Dirección I2C del Acelerómetro 2
#define DS1307 (0x68) // Dirección I2C del RTC DS1307
#define ActivityLed (0x07) // LED indicador está en Pin 7
#define InitSensor (0x05) // Primer sensor en Pin5 (sensores simulables por un interruptor común)
#define SecondSensor (0x04) // Segundo sensor en Pin4
#define DistanciaSensores 1 // Distancia entre sensores en [metros]
// Registros de Acelerómetros
#define BW_RATE (0x2C) // Data rate and power mode control
#define POWER_CTL (0x2D) // Power Control Register
#define DATA_FORMAT (0x31) // Data format control
#define DATAZ0 (0x36) // Z-Axis Data 0
#define DATAZ1 (0x37) // Z-Axis Data 1
#define Rango (0x00) // Rango: 0x00=2, 0x01=4, 0x02=8, 0x03=16[g]
#define OffsetA 0 // Offset que se le darán a los resultados de las mediciones
#define OffsetB 0
#define CS_SD 10 // ChipSelect Pin = 10, para la tarjeta SD
// Variables para el programa base
char Values_Z[2]; // Arreglo de 2 espacios para el dato del eje Z de los acelerómetros
char buffer[15]; // Se utiliza para crear un archivo nuevo, nombre.extensión
String NombreArchivoNuevo="Datos",Offset_A,Offset_A2,Rang;
int z,i,NumeroArchivo,Range;
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int SegundosMedicion=10; //120 no funciona.
float Zeta,Velocidad;
//unsigned long Tiempo,Tiempo1,Tiempo2;
/////////////////////////////////// -- SETUP -- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
pinMode(ActivityLed,OUTPUT);
pinMode(5,OUTPUT);
pinMode(InitSensor,INPUT);
pinMode(SecondSensor,INPUT);
pinMode(CS_SD, OUTPUT);
digitalWrite(CS_SD, HIGH);
Serial.begin(115200); // 57600 es la velocidad de programación. Para lo demás podría ser hasta 1000000 o 2000000(no probado).
Wire.begin(); // Predeterminado: 100(kHz) de comunicación
// Inicializar tarjeta SD
if (!SD.begin(CS_SD)) {
Serial.println("Falla de carga de tarjeta SD.");
Led(5);
}
else {
Serial.println("Tarjeta SD inicializada - OK.");
Led(1);
}
// Inicializar acelerómetros
writeTo(ADLX_A, BW_RATE, 0x0D); // 0x0D = 800Hz and 400 Bandwidth, probablemente es lo correcto para I2C a 400kHz
writeTo(ADLX_B, BW_RATE, 0x0D);
writeTo(ADLX_A, DATA_FORMAT, Rango);
writeTo(ADLX_B, DATA_FORMAT, Rango);
writeTo(ADLX_A, POWER_CTL, 0x08);
writeTo(ADLX_B, POWER_CTL, 0x08);
//SelfTest(); // Hacer un SELF-TEST de los acelerómetros - REVISAR
// Preparar el contenido de los archivos
switch(Rango) {
case 0x01:
Rang="+-4[g]";
Range=4;
break;
case 0x02:
Rang="+-8[g]";
Range=8;
break;
case 0x03:
Rang="+-16[g]";
Range=16;
break;
default:
Rang="+-2[g]";
Range=2;
}
}
void loop(){
File Archivo;
while(digitalRead(InitSensor)==0) {} // Mientras el primer sensor de llegada del tren no indique nada...
// Tiempo1=millis();
digitalWrite(ActivityLed,HIGH); // Inicio de mediciones
Serial.println("Tren entrando.");
TWBR=72; // Para que I2C funcione a 100(kHz). 72 para 100kHz y 12 para 400kHz
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // Extraer datos del reloj
TWBR=12; // Para que I2C funcione a 400(kHz). 72 para 100kHz y 12 para 400kHz
File root = SD.open("/");
NumeroArchivo=LastFile(root);
Serial.println(NumeroArchivo);
NumeroArchivo=NumeroArchivo+1;
NombreArchivoNuevo = NombreArchivoNuevo + NumeroArchivo + ".csv";
Serial.println(NombreArchivoNuevo);
NombreArchivoNuevo.toCharArray(buffer,15);
Archivo = SD.open(buffer,FILE_WRITE); //Otra cosa es: SD.remove("Datos.csv");
/* while(digitalRead(SecondSensor)==0) {} // Mientras el segundo sensor de llegada del tren no indique nada...
Tiempo2=millis();
Tiempo=(Tiempo2-Tiempo1)*1000;
Velocidad=(DistanciaSensores/Tiempo)*3.6;
for(int j=0;j<=400*SegundosMedicion;j++){ // MEDICIONES
digitalWrite(6,HIGH); // Para medir frecuencia de muestreo
digitalWrite(6,LOW);
readFrom(ADLX_A, DATAZ0, 2);
z = ((int)Values_Z[1]<<8)|(int)Values_Z[0];
z=z+OffsetA;
Zeta=(z*Range*9.80665)/512;
Serial.println(Zeta, DEC);
Archivo.print(Zeta);
Archivo.print(";");
readFrom(ADLX_B, DATAZ0, 2);
z = ((int)Values_Z[1]<<8)|(int)Values_Z[0];
z=z+OffsetB;
Zeta=(z*Range*9.80665)/512;
Serial.println(Zeta, DEC);
Archivo.println(Zeta);
}
Serial.println("FIN");
Archivo.println("Fin;Fin");
digitalWrite(ActivityLed,LOW); // Fin de lectura de acelerómetros
Archivo.close();
}
/////////////////////////////////// -- FUNCIONES -- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Write commands via I2C
void writeTo(int DEVICE, byte address, byte val) {
Wire.beginTransmission(DEVICE); // start transmission to device
Wire.write(address); // send register address
Wire.write(val); // send value to write
Wire.endTransmission(); // end transmission
}
// Reads num bytes starting from address register on device in to _buff array
void readFrom(int DEVICE, byte address, int Bytes_A_Leer) {
Wire.beginTransmission(DEVICE); // start transmission to device
Wire.write(address); // sends address to read from
Wire.endTransmission(); // end transmission
Wire.beginTransmission(DEVICE); // start transmission to device
Wire.requestFrom(DEVICE, Bytes_A_Leer); // request X bytes from device
int i = 0;
while(Wire.available()) // device may send less than requested (abnormal)
{
Values_Z[i] = Wire.read(); // receive a byte
i++;
}
Wire.endTransmission(); // end transmission
}
// To find the last file on the SD card
int LastFile(File dir) {
boolean Count = true;
File temp;
int NumArch=0,NumMaxArch=0,NA1,NA2,NA3;
String NomArch;
while(true) {
File entry=dir.openNextFile();
if(!entry && Count) { // Si no encuentra archivo y no encontró ninguno, crear el primero.
temp=SD.open("Vacio100.csv",FILE_WRITE);
temp.close();
NumMaxArch=100;
break;
}
if(!entry && !Count) break; // Si no encuentra archivo pero ya encontró otros, salir de este Loop.
NomArch=entry.name();
NA1=NomArch.charAt(5); // setCharAt(num,"x") sirve para cambiar un caracter por otro.
NA2=NomArch.charAt(6);
NA3=NomArch.charAt(7);
NumArch=((NA1-48)*100)+((NA2-48)*10)+(NA3-48); // Ordenar los números y restarles 48, para convertirlos de ascii a dec.
if(NumArch>NumMaxArch) NumMaxArch=NumArch;
Count=false;
}
return(NumMaxArch);
}
void Led(int e) {
for(int i=0;i<e;i++) {
digitalWrite(ActivityLed,HIGH);
delay(100);
digitalWrite(ActivityLed,LOW);
delay(100);
}
}
byte bcdToDec(byte val) {
return ((val/16*10)+(val%16));
}
void getDateDs1307(byte *second, // Función para extraer hora y fecha del reloj
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
Última edición: