Writing string to SD card / string array

Hello,
I am trying to log flowmeter data on a SD card with Arduino Uno and Adafruit
RTC SD shield.

In order to reduce the number of write cycles to the SD card I am using circular
buffer to store values.
Unfortunately there is no circular buffer for strings (date-time string), so I am
using a string array.
The output on the serial monitor looks ok, but as soon as I uncomment the

// write_data(); //Write value and Time to SD
command the output on the serial monitor produces blank lines and skips
output. Also the date-time string DT[i] cannot be written to the SD card.

output is e.g.
;9.68;94
;17.20;111

Any ideas?

Thanks
Michael

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <CircularBuffer.h>

// RTC
RTC_PCF8523 rtc;
const int chipSelect = 10; //10 is default by shield, but normally on Pin 4
int interval = 1;  //Log to SD Card every 1 seconds

long timer;
String timestring;
String mvalue;

// flowmeter measured 0.103 ml/pulse
float cfactor = 0.103;

byte interrupt = 0;
byte sensorPin = 2;
byte pulseCount;
float flowRate;
float f_ml;
long t_ml;
CircularBuffer<float, 10> buf_f_ml;
CircularBuffer<long, 10> buf_t_ml;
String DT[10];
int i = 0;

unsigned long oldTime;

void setup()
{
  Serial.begin(9600);
  delay(2000);

  //SD Card
  Serial.println("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("SD Card error");
    return;
  }
    Serial.println("card initialized");
    
  //RTC startup
  if (! rtc.begin()) {    
    Serial.println("No RTC found");
  } else {
    Serial.println("RTC clock found");
  }
  if (! rtc.isrunning()) {
    Serial.println("RTC is not configured");
  }

  // flowmeter
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);
  attachInterrupt(interrupt, pulseCounter, FALLING);

  //initialize timestring-array
  for(int j = 0; j < 11; j++) {
    DT[j] = "99-99-99 99:99:99";
  }

  buf_f_ml.clear();
  buf_t_ml.clear();

  timer = millis();
}


void loop() {
  // push each interval one dataset to queue
  if ((timer + interval * 2000) < millis()) {
    timer = millis();
    get_logvalue(); //Get your value
    get_time(); //Get time from RTC
    i++;
    if(buf_f_ml.isFull()) {
      // as soon as I uncomment the follwing line the output
      // on the serial monitor gets screwed up
      // write_data(); //Write value and Time to SD
      buf_f_ml.clear();
      buf_t_ml.clear();
      i = 0;
    }
  }
}

void pulseCounter()
{
  pulseCount++;
}

void get_logvalue() {
    int semic;
    detachInterrupt(interrupt);
    f_ml = pulseCount * cfactor;
    flowRate = (1000.0 / (millis() - oldTime)) * f_ml;
    oldTime = millis();
    t_ml += f_ml;
    // buffer data to reduce number of write cycles to SD Card
    buf_f_ml.push(f_ml);
    buf_t_ml.push(t_ml);
    
    Serial.print(String(i) + ": ");
    Serial.print("Current flow: ");
    Serial.print(int(flowRate));
    Serial.print(".");
    semic = (flowRate - int(flowRate)) * 10;
    Serial.print(semic, DEC) ;
    Serial.print("L/min");
    Serial.print("  Total: ");
    Serial.print(t_ml);
    Serial.println("mL");
    
    pulseCount = 0;
    attachInterrupt(interrupt, pulseCounter, FALLING);
}

void get_time(){ //Read Time from RTC
  DateTime now = rtc.now();
  timestring = now.day();
  timestring += "-";
  timestring += now.month();
  timestring += "-";
  timestring += now.year();
  timestring += " ";
  timestring += now.hour();
  timestring += ":";
  timestring += now.minute();
  timestring += ":";
  timestring += now.second();
  DT[i] = timestring;
  Serial.println("i: " + String(i) + " DT: " + DT[i]);
  Serial.println("TS: " + timestring);
}

void write_data() { //Write to SD card
  File dataFile = SD.open("datalog3.txt", FILE_WRITE);
  int j = 0;
  if (dataFile) {
    while(!buf_f_ml.isEmpty()) {
      String dataString = DT[j] + ";" + String(buf_f_ml.shift()) + ";" + String(buf_t_ml.shift());
      dataFile.println(dataString);
      Serial.println(dataString);
      j++;
    }
    dataFile.close();
  }
  else {
    Serial.println("error writing datalog.txt");
  }
  Serial.println("write end");
}

You know that the SD library code already buffers write operations?

Hello.
Apparently I did not know. Thanks for advice.

Michael

if ( (millis() - timer) >= (interval * 2000)) // which is 2000*1 or 2000 save a bit of time just write 2000 is a change I'd make. `

In fact SDcard hardware only does reads and writes in multiples of 512 bytes, as its based on flash chips, so it has to buffer. In flash ROM all operations are block-wise, not byte-wise, which allows much higher memory density.

Still do not know, why I cannot properly read string array DT[i] in the write_data() module. So I will abandon the buffering idea.
Thanks for your contributions.