PROBLEMAS CON DATOS GRABADOS EN SD

Buenas tardes:

Primero de todo me presento. (es mi primer post)
Soy un técnico eléctrico industrial que se esta formando en el apartado que mas me gusta, Automatización industrial.
Soy maker y autodidacta, poseo dos impresoras 3D una China (anet A8) y una DIY clon de la prusa I3.
Dibujo en Solid Works. Y lo mas importante es que no pido ayuda hasta que me he quemado las neuronas, jajajaj

Desde hace ya cerca de dos años Estoy envuelto en el inmenso mundo de Arduino, y la verdad es que me desenvuelvo bastante bien en proyectos de nivel medio. Y siempre que tengo dudas leo posts del foro y me ayudan muchísimo a aclarar mis dudas; pero en este caso no hay manera, :C

Pues bien ahí voy:

En diferentes maquinas de uno de mis clientes he de hacerles unos informes (datalogger) sobre una cantidad de cajas que salen o que se mueven por un conveyor automático (camino de rodillos)
El contador en si me resulta muy fácil, leo el estado de una Fotocélula(FC a partir de aquí) y creo un contador.
Mi problema reside en que en el momento de detectar la caja pasar e de imprimir la fecha y la hora en una SD para luego crear una gráfica en excel.

El proyecto se compone de un Arduino Nano, un RTC DS1307, (en otros programas no me da ni un problema), y una shield de SD card (no microSD).
Para la lectura del estado de la FC (ya que devuelve la señal a 24v) he creado un divisor resistivo para reducir la entrada a 5v, esto funciona bien.

Cuando hago un datalogger que me guarda por ejemplo temperaturas, como escribe constantemente no hay problemas, pero en este caso que ha de esperar al paso de una caja, me da problemas en la escritura o en la abertura del archivo para escribir los datos.

Tengo dos sketch’s hechos, primero os pondré el mas sencillo haber si me podeis dar luz a mi problema.

/*
12/11/2016 -- Primera version de un DATALOGGER para contar las cajas que entran en el desvinculado de *********** (NO PUEDO NOMBRAR AL CLIENTE)
-- se utiliza una FC de estado alto (HIGH), de tal manera que al detectar y cambiar su estado a bajo
(LOW), imprimimos en la SD, la hora exacta y "caja detectada" 
16/11/2016 -- Se modifica el programa formateando la SD a Fat32, y cambiando el cierre de la escritura al corchete del segundo  if 

  * SD card 
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK  - pin 13
 ** CS   - pin 4
 */

//---------------------------------librerias necesarias, comunicación Onewire, SPI comunicacion con SD, libreria de la SD y del RTC
#include <Wire.h>
#include <SPI.h>           
#include <SD.h>
#include "RTClib.h"
//_-------------------------------------------------------------------------------------------------------------------------------------

RTC_DS1307 RTC;


const int FC = 3; // FC EN EL PIN 3 CABLE COLOR ROJO
const int chipSelect = 10;
//const int chipSelect = 4;    // DEPENDE DEL MODULO DE LA SD USAREMOS EL PIN 4 O 10


const int led1 = 8;  //LED VERDE
const int led2 = 6;  //LED AZUL
const int led3 = 7;  //LED ROJO


int estadoactualFC = 0;
int estadoanteriorFC = 0;
int contador = 0;

void setup() {

  Wire.begin();
  RTC.begin();
  //RTC.adjust(DateTime(__DATE__, __TIME__)); //establece fecha y hora al compilar el programa, comentar una vez establecida
  Serial.begin(9600);          // ABRIMOS EL PUERTO SERIE 
  

  pinMode(chipSelect, OUTPUT);   //PIN DE LA SD
  pinMode(FC, INPUT);             //PIN DE LA FC
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  
  Serial.print("INICIANDO SD card...");

  // OBSERBAMOS SI LA TARJETA ESTA PRESENTE Y LA INICIALIZAMOS
  
  if (!SD.begin(chipSelect))
     {
      Serial.println("ERROR SD, O NO PRESENTE");
      digitalWrite(led3, HIGH);
      digitalWrite(led1, LOW);
      return;
     
     }
      Serial.println("TARJETA SD ABIERTA");
      digitalWrite(led1, HIGH);
      digitalWrite(led3, LOW);
  
}
//----------------------------------------------------------------------------------------------------------------------------------------------




void loop() {

 
  DateTime now = RTC.now(); //--------------Adquirimos la fecha y la hora del reloj
  char myBuffer[16];        //--------------creamos una variable char para imprimir correctamente la fecha EXTRAIDO DEL FORO DE ARDUINO NO RECUERDO EL AUTOR
  sprintf (myBuffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second()); //EXTRAIDO DEL FORO DE ARDUINO
 
   
//--------------------------------------------imprimimos por serial dia y hora
        Serial.print(now.day(), DEC);
        Serial.print('/');
        Serial.print(now.month(), DEC);
        Serial.print('/');
        Serial.print(now.year(), DEC);
        Serial.print(' ');
        Serial.print(myBuffer);
        Serial.println();  

    boolean FC = digitalRead(3);
    Serial.println("estado FC....");
    Serial.println(FC);
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    
//------------------------------------------------------------------ ESTADO FC --------------------------------------------------

estadoactualFC = digitalRead(3);
  
   
if (estadoanteriorFC != estadoactualFC)
    {
      if ( estadoactualFC == LOW )
          {
           if  (dataFile){
             
                dataFile.println();
                dataFile.print(now.day(), DEC);
                dataFile.print('/');
                dataFile.print(now.month(), DEC);
                dataFile.print('/');
                dataFile.print(now.year(), DEC);
                dataFile.print(' ');
                dataFile.print(myBuffer);
                dataFile.print(' ');
                dataFile.print("CAJA DETECTADA");
                digitalWrite(led2, HIGH);
                //dataFile.close(); 
                Serial.print("CAJA DETECTADA ");
                Serial.print(now.day(), DEC);
                Serial.print('/');
                Serial.print(now.month(), DEC);
                Serial.print('/');
                Serial.print(now.year(), DEC);
                Serial.print(' ');
                Serial.print(myBuffer);
                Serial.println();
                digitalWrite(led2, LOW);
                   
             }
            else {
                Serial.println("error abriendo datalog.txt");
                digitalWrite(led3, HIGH);
                delay(500);
                digitalWrite(led3, LOW);
                delay(500);
                }
            contador++;
            dataFile.close();
          }
          estadoanteriorFC = estadoactualFC;
          //dataFile.close();
    }
  Serial.print("Cantidad cajas detectadas.... ");
  Serial.println(contador);
        
  delay(1000); // Para dar estabilidad al programa puede no ser necesario
}

En este el problema es que al abrir y escribir en el archivo UNAS 10 veces entra en error y ya no me escribe mas, y constantemente me devuelve “error al abrir dataFile”
le he dado mil vueltas y no le veo el problema.
Si en este sketch no le vemos solucion colgaré el segundo que es un poco mas lioso.

Sin mas muchas gracias al que se tome la molestia de ayudarme
Un saludo

Simple. Esta línea:

File dataFile = SD.open("datalog.txt", FILE_WRITE);

Debe ir aquí:

if ( estadoactualFC == LOW )
  {
    File dataFile = SD.open("datalog.txt", FILE_WRITE); // Aquí
    if  (dataFile) {

El problema es el siguiente: qué pasa si abro el archivo y no lo cierro porque no se detectó otra caja?

Pues eso: abres el archivo independientemente de que se haya detectado una caja o no, pero lo cierras sólo si se detecta. Pero cuando no? Por eso los intentos consecuentes de apertura fallaban, porque ese archivo seguía "enganchado" a un objeto File que nunca cerró (y sigue ocupando memoria aunque la referencia parezca haber sido eliminada al finalizar la función loop).

Esto último lo digo por experiencia. En un programa enlistador de archivos que una vez intenté hacer, había olvidado cerrar cada archivo que abría; y eso eventualmente hizo que el programa se colgara, por haberse llenado la memoria RAM.

Que raro es esto?

dataFile.println();
                dataFile.print(now.day(), DEC);
                dataFile.print('/');
                dataFile.print(now.month(), DEC);
                dataFile.print('/');
                dataFile.print(now.year(), DEC);
                dataFile.print(' ');
                dataFile.print(myBuffer);
                dataFile.print(' ');
                dataFile.print("CAJA DETECTADA");
                digitalWrite(led2, HIGH);
                //dataFile.close(); 
                Serial.print("CAJA DETECTADA ");
                Serial.print(now.day(), DEC);
                Serial.print('/');
                Serial.print(now.month(), DEC);
                Serial.print('/');
                Serial.print(now.year(), DEC);
                Serial.print(' ');
                Serial.print(myBuffer);

mybuffer inserta hh:mm:ss y no pudiste hacerlo con dd/mm/yy? un solo mybuffer del tamaño adecuado

char myBuffer[17];        // 6+2+1+6+2 +1 = 17 lugares
sprintf (myBuffer, "%02d/%02d/%02d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second()); //EXTRAIDO DEL FORO DE ARDUINO

o lo pones al revés, hora primero fecha después.

lucario448- muchas gracias , no habia pensado en eso. Tenia entendido que la orden File... era solo para crearlo, veo que lo crea y lo abre.

Surbyte- Ahora recuerdo que la variable char para coger el dia y la hora lo encontré en una respuesta tuya de un problema de un compañero del foro. No acabo de entender que te parece raro, el utilizar el mybuffer para la hora o no utilizarlo para la fecha.

Muchísimas gracias a los dos, de todo se aprende y es lo que me motiva a seguir.

Perdona surbyte, acabo de releer tu respuesta y lo acabo de entender a la primera!!!
Que cracks!!

Muchísimas gracias
Repaso el código y lo resubo para el que lo pueda necesitar!!

/*
Creado por Yagoto de la empresa N2 instal.ladors 
12/11/2016 -- Primera version de un DATALOGGER para contar las cajas que entran en el desvinculado de *********** (NO PUEDO NOMBRAR AL CLIENTE)
-- se utiliza una FC de estado alto (HIGH), de tal manera que al detectar y cambiar su estado a bajo
(LOW), imprimimos en la SD, la hora exacta y "caja detectada" 
16/11/2016 -- Se modifica el programa formateando la SD a Fat32, y cambiando el cierre de la escritura al corchete del segundo  if 
21/12/2016 -- Se modifica la abertura del fichero "dataFile" dentro del primer if donde detectamos el paso de las cajas agradecimiento a Lucario448 del foro de Arduino
21/12/2016 -- Se modifica la variable "char" para la adquisicion de la fecha y la hora todo en el mismo "mybuffer", agradecer a Surbyte del foro de Arduino por dar aun mas luz a mi proyecto

  * SD card 
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK  - pin 13
 ** CS   - pin 4
 */

//---------------------------------librerias necesarias, comunicación Onewire, SPI comunicacion con SD, libreria de la SD y del RTC
#include <Wire.h>
#include <SPI.h>           
#include <SD.h>
#include "RTClib.h"
//_-------------------------------------------------------------------------------------------------------------------------------------

RTC_DS1307 RTC;


const int FC = 3; // FC EN EL PIN 3 CABLE COLOR ROJO
const int chipSelect = 10;
//const int chipSelect = 4;    // DEPENDE DEL MODULO DE LA SD USAREMOS EL PIN 4 O 10


const int led1 = 8;  //LED VERDE
const int led2 = 6;  //LED AZUL
const int led3 = 7;  //LED ROJO


int estadoactualFC = 0;
int estadoanteriorFC = 0;
int contador = 0;

void setup() {

  Wire.begin();
  RTC.begin();
  //RTC.adjust(DateTime(__DATE__, __TIME__)); //establece fecha y hora al compilar el programa, comentar una vez establecida
  Serial.begin(9600);          // ABRIMOS EL PUERTO SERIE 
  

  pinMode(chipSelect, OUTPUT);   //PIN DE LA SD
  pinMode(FC, INPUT);             //PIN DE LA FC
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  
  Serial.print("INICIANDO SD card...");

  // OBSERBAMOS SI LA TARJETA ESTA PRESENTE Y LA INICIALIZAMOS
  
  if (!SD.begin(chipSelect))
     {
      Serial.println("ERROR SD, O NO PRESENTE");
      digitalWrite(led3, HIGH);
      digitalWrite(led1, LOW);
      return;
     
     }
      Serial.println("TARJETA SD ABIERTA");
      digitalWrite(led1, HIGH);
      digitalWrite(led3, LOW);
  
}




void loop() {

 
  DateTime now = RTC.now(); //--------------Adquirimos la fecha y la hora del reloj
  char myBuffer[17];        // 6+2+1+6+2 +1 = 17 lugares extraido del foro arduino
  sprintf (myBuffer, "%02d/%02d/%02d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second()); //EXTRAIDO DEL FORO DE ARDUINO
   
//--------------------------------------------imprimimos por serial dia y hora
        Serial.println();
        Serial.print(myBuffer);
        Serial.println();  

    boolean FC = digitalRead(3);
    Serial.println("estado FC....");
    Serial.println(FC);
    
    
//------------------------------------------------------------------ ESTADO FC --------------------------------------------------

estadoactualFC = digitalRead(3);
  
   
if (estadoanteriorFC != estadoactualFC)
    {
      if ( estadoactualFC == LOW )
          {
           File dataFile = SD.open("datalog.txt", FILE_WRITE);
           if  (dataFile)
           {
                dataFile.println();
                dataFile.print(myBuffer);
                dataFile.print(' ');
                dataFile.print("CAJA DETECTADA");
                digitalWrite(led2, HIGH);
                //dataFile.close(); 
                Serial.print("CAJA DETECTADA ");
                Serial.print(' ');
                Serial.print(myBuffer);
                Serial.println();
                digitalWrite(led2, LOW);
                   
             }
            else {
                Serial.println("error abriendo datalog.txt");
                digitalWrite(led3, HIGH);
                delay(500);
                digitalWrite(led3, LOW);
                delay(500);
                }
            contador++;
            dataFile.close();
          }
          estadoanteriorFC = estadoactualFC;
          //dataFile.close();
    }
  Serial.print("Cantidad cajas detectadas.... ");
  Serial.println(contador);
        
  delay(1000); // Para dar estabilidad al programa puede no ser necesario
}

La solución fue de Lucario. Yo apunté a otra cosa. Suerte. Si esta listo agrega [SOLUCIONADO] al título