Hoe kan ik de laatste regels uitlezen op een SD kaart??

Arduino specifieke Software
Berichten: 10
Geregistreerd: 26 Apr 2015, 19:22

Hoe kan ik de laatste regels uitlezen op een SD kaart??

Berichtdoor Otto » 20 Mei 2019, 08:54

Hallo ,
ik ben een kleine datalogger aan het maken om druk te meten.
de opstelling bevat een NANO, druksensor, RTC 3231 klok, 16x2 LCD display, een SD kaart module en een drukknop.
elke seconde wordt de druk gemeten, de waarde op het lcd scherm gezet en opgeslagen in een array met 10 plaatsen.
elke 10 seconden worden het gemiddelde van de 10 opgeslagen waarden op de SD kaart weggeschreven met datum en tijd.
hiervoor heb ik een string gemaakt van 16 karakters in de vorm "ddmm_hhmm:ss_p,p" Hierbij is p,p de druk met 1 decimaal.
als de datum of tijd kleiner is dan 10, dan wordt een extra "0" toegevoegd, zodat ik altijd 16 karakters heb.
zo krijg ik een strakke lijst meetwaarden op m'n SD kaart.
tot zover is alles OK.

voor de SD kaart gebruik in de SD library

Nu wil ik met een druk op de knop de laatste 100 meetwaarden regel voor regel elk 1 seconde op het LCD tonen.
dit zijn dus de meetwaarden die aan het einde van het .txt bestand op de SD kaart staan.
De eerste 100 regels tonen op het display lukt me wel, maar

- hoe vind ik de laatste regel van het bestand?
- hoe ga ik dan telkens naar de regel erboven??

mogelijk een eenvoudige aktie, maar ik krijg het niet gevonden.

... of moet ik de datafile omgekeerd opbouwen en telkens de laatste meting bovenaan zetten?? en hoe moet dat dan??

hieronder m'n testcode tot zover, het laatste deel (drukknop lang indrukken) bevat het uitlezen van de eerste 10 regels.

Code: Alles selecteren
/* Spuitdrukregistratieprogramma   v0.6    19-05-2019    Bert Schermers
 *  ONDERDELEN:
 *    1) Arduino Nano
 *          Vin voeding aan +12V spuitcomputer geschakeld 
 *          GND aan massa spuitcomputer
 *    2) LCD Display 16x2
 *    3) I2C module voor LCD display:
 *          GND aan GND
 *          VCC aan 5V
 *          SDA aan A4
 *          SCL aan A5
 *    4) RTC module DS3231:
 *          GND aan GND
 *          VCC aan 5V
 *          SDA aan A4
 *          SCL aan A5
 *    5) RVS Drukknop 2 polig NO veerretour 12mm:
 *         pin1 aan A1
 *         pin2 aan GND
 *    6)  Druksensor TMOEC SKU237545:
 *          rood aan 5V
 *          zwart aan GND
 *          geel aan A2
 *    7)  Micro SD card       
 *          3V3 aan 3V3
 *          CS aan D4 !!
 *          MOSI aan  D11
 *          CLK aan D13
 *          MISO aan D12
 *          GND aan GND
 *                   
 *    8)  Printplaat ca 10,5 cm x 7 cm
 *               
 *    9)  Behuizing: FL150 Halogeenlamp     
 *        Doos 14cm x 11cm x 14 cm
 *         
 *  WERKING:         
 *    1) Na aanzetten van de spuitcomputer wordt eerst de SD kaart gecontoleerd
 *    2) 1x per seconde de spuitdruk uitgelezen op display getoond en in een array opgeslagen
 *    2) elke 10 seconden wordt de tijd en gemiddelde spuitdruk van de laatste 10 metingen
 *       opgeslagen in de logfile op de SD kaart.
 *    3) met de drukknop wordt het mogelijk de laatste 360 metingen terug te roepen op het display.
 *    4) vanaf de uitgenomen sd card is het mogelijk de hele logfile te bekijken. 
 */   

// D01: Declaratie library's -------------------
#include <LiquidCrystal_I2C.h>      // display
#include <Wire.h>                   // I2C module. http://arduino.cc/en/Reference/Wire
#include <DS3232RTC.h>              // datum/tijd module  http://github.com/JChristensen/DS3232RTC
#include <Time.h>                   //http://playground.arduino.cc/Code/Time
#include <TimeLib.h>
#include <OneButton.h>            // drukknop https://github.com/mathertel/OneButton
#include <SPI.h>                  // communicatie SD card https://www.arduino.cc/en/Reference/SPI
#include <SD.h>                   // schrijven/lezen sd card  https://www.arduino.cc/en/Reference/SD

// D02: Declaratie pinning Arduino Nano ----------
OneButton button(A1, true);   // input drukknop menustructuur
int sensorPin = A2;
LiquidCrystal_I2C lcd(0x27, 16, 2); 
File myFile;

// D03: Declaratie variabelen --------------------
float tempC;                         // temp sensor DS3231
int statusEnkelklik = 0;              // registratie drukknop 1x kort indrukken
int statusDubbelklik = 0;             // registratie drukknop 2x kort achterelkaar indrukken
int statisLangeklik = 0;              // registratie drukknop1x lang indrukken
int LCDminTeller = 0;                 // minutenteller voor LCD uitschakelen na 2 minuten geen gebruik
int sensorValue1 = 0;              // uitgelezen signaal 0-1024 van de analoge ingang A2
int sensorValue2 = 0;               // 2x uitlezen en middelen
float sensorVolt = 0;               // omgerekend naar 0-5 V
float sensorBar = 0;               // omgerekend naar 0-12 bar voor SKU237545
int readings[10];                // 10 readings from the analog input
int readIndex = 0;              // the index of the current reading
float total = 0;                  // the running total
float average = 0;                // the average
int seconde = 61;                 // seconde omhouden voor 1 meting per seconde
bool lcdAan = true;
String buffer;
                       

// EINDE DECLARATIES----------------------------------

// NU VOLGT SETUP, wordt 1x doorlopen-----------------
void setup() {
// SU01: Instellen inputs, Outputs en startinstellingen
button.attachClick(enkelklik);
button.attachDoubleClick(dubbelklik);
button.attachLongPressStart(langeklik);

for (int thisReading = 0; thisReading < 10; thisReading++) {
    readings[thisReading] = 0;                              //alle 10 geheugenplaatsen op 0
  }
// SU02: Opstarten -----------------------------------
Wire.begin();                 // Start I2C
Serial.begin(9600);
lcd.begin();                  //Start display
lcd.backlight();
//delay(1000);
setSyncProvider(RTC.get);     // Start RTC uitlezen.  the function to get the time from the RTC
setSyncInterval(86400);                                      // 1x per dag een re-sync                                                     
RTCdatum();                                                  // Fu01: Datum op display
RTCtijd();                                                   // Fu02: Tijd op display
// RTCtemp();                                                // Fu03: Temp op display
lcd.setCursor(0,1);
lcd.print("START.."); delay(1000);
if (!SD.begin(4)) {
    lcd.setCursor(0,1);lcd.print("SD FOUT");
    return;}
  lcd.setCursor(0,1);lcd.println("SD OK! ");
  delay(1000);
  lcd.setCursor(0,1);lcd.println("GEREED");
}
void loop() {
 button.tick(); delay(10);
 tmElements_t tm; RTC.read(tm);
 if(tm.Second != seconde) {                         // bij elke nieuwe seconde 
  RTCtijd();                                        // tijd op display 
  sensorValue1 = analogRead(sensorPin);               // uitlezen waarde sensor (0-1024)
  delay(25);
  sensorValue2 = analogRead(sensorPin);
  sensorVolt = ((sensorValue1+sensorValue2)*2.5)/1024.0; // middelen en omrekenen naar volts
  sensorBar = 3.0*(sensorVolt-0.47);                     // omrekenen naar bar
  total = total - readings[readIndex];                   // Array: oudste waarde aftrekken
  readings[readIndex] = sensorBar;// druk opslaan   // Array: nieuwe meting opslaan
  total = total + readings[readIndex];              // Array: nieuwe meting optellen
  average = total / 10; // calculate the average    // Array: gemiddelde 10 metingen.
  readIndex = readIndex + 1;                        // Array: index 1 verhogen
  if (readIndex >= 10) {readIndex = 0;}             // Array: na meting 9 terug naar 0
  lcd.setCursor (6,1);
  lcd.print(" p=");
  lcd.print(sensorBar,2);
  lcd.print("bar ");
   
  if (tm.Second%10==0) {  lcd.backlight();          // elke 10 seconden
    String data = "" ;                              // string maken voor de SD
    if (tm.Day < 10) data += String("0");
    data += String(tm.Day);
    if (tm.Month < 10) data += String("0");
    data += String(tm.Month);
    data += String(" ");
     if (tm.Hour < 10) data += String("0");
    data += String(tm.Hour);
     if (tm.Minute < 10) data += String("0");
    data += String(tm.Minute);
    data += String(":");
     if (tm.Second < 10) data += String("0");
    data += String(tm.Second);
    data += String(" ");
    data += String(sensorBar,1);
    Serial.println (data);
      myFile = SD.open("datalog3.txt", FILE_WRITE);
      if (myFile) {                                    // if the file opened okay, write to it:
          myFile.println(data);
          myFile.close();}                           // close the file:
         
      else { Serial.println("error opening test.txt");} // if the file didn't open, print an error
      lcd.noBacklight();
      }
 }
 seconde = tm.Second;
}

// NU VOLGEN DE FUNCTIEPROGRAMMA'S-----------------------------------------------------------------------------------------

// Fu01: RTC DATUM UITLEZEN EN OP DISPLAY.--------------------------------------------------------------------------------
void RTCdatum(){
    tmElements_t tm; RTC.read(tm);             
     lcd.setCursor(0,0);
     if (tm.Day < 10) lcd.print("0");            //  voorloop nul
     lcd.print(tm.Day, DEC); lcd.print('-');
     if (tm.Month < 10) lcd.print("0");
     lcd.print(tm.Month, DEC);
     }

// Fu0: RTC TIJD UITLEZEN EN OP DISPLAY.-----------------------------------------------------------------
void RTCtijd(){
    tmElements_t tm; RTC.read(tm);             
     lcd.setCursor(8,0);
     if (tm.Hour < 10) lcd.print("0");     
     lcd.print(tm.Hour, DEC);
     lcd.print(":");
     // if (tm.Second%2==0) lcd.print(":");       // knipperende : tussen uur en minuut
     //    else lcd.print (" ");
     // if (tm.Second%2==0)  digitalWrite(LedNano, HIGH);      //NANOled knippert
     // else digitalWrite(LedNano, LOW);
     if (tm.Minute < 10) lcd.print("0");
     lcd.print(tm.Minute, DEC);
     lcd.print(":");
     if (tm.Second < 10) lcd.print("0");
     lcd.print(tm.Second, DEC);
 }

 /* Fu03: RTC TEMPERATUUR UITLEZEN EN OP DISPLAY.-----------------------------------------------------------------
void RTCtemp(){
    tmElements_t tm; RTC.read(tm);             
    tempC = (RTC.temperature() /4);
    lcd.setCursor(14,0);
    lcd.print("T");
    if (tempC < 10) lcd.print("0");   
    lcd.print(tempC,1);
    lcd.print("C");
}
*/
// Fu04: DRUKKNOP ENKELE KLIK
void enkelklik() {
  for (int i =0; i<10; i++){
  lcd.backlight();
  delay (50);
  lcd.noBacklight();
  delay (50);
}
}

//Fu05: DRUKKNOP DUBBELKLIK
void dubbelklik() {
// re-open the file for reading:
  myFile = SD.open("datalog3.txt");
  if (myFile) {
    Serial.println("datalog3.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
    lcd.setCursor(0,1); lcd.print("Gereed          ");
}

// Fu06: DRUKKNOP LANGEKLIK = uitlezen datafile
void langeklik() {
  myFile.close();
  myFile = SD.open("datalog3.txt", FILE_READ);
  for (int i =0; i<10; i++){
  buffer=myFile.readStringUntil('\n');
  lcd.backlight();
  lcd.setCursor(0,1);
  lcd.print(buffer);
  delay(1000);
  }
}

Advertisement

Gebruikers-avatar
Berichten: 118
Geregistreerd: 01 Okt 2015, 11:54
Woonplaats: Castricum

Re: Hoe kan ik de laatste regels uitlezen op een SD kaart??

Berichtdoor FonzieBonzo » 20 Mei 2019, 13:22

Met SD.Seek() kun je naar een bepaalde positie van je bestand gaan.
Je werkt met vaste lengtes dus als je eerst met SD.size() de grootte van het bestand op vraagt,
kun je met SD.Seek() x aantal regel terug gaan als je hebt uitgerekend hoeveel bytes één regel bevat.


Gr,
Fonzie

Berichten: 10
Geregistreerd: 26 Apr 2015, 19:22

Re: Hoe kan ik de laatste regels uitlezen op een SD kaart??

Berichtdoor Otto » 21 Mei 2019, 08:17

Ja!! dat is het! als je het weet is het allemaal niet zo moeilijk...
ik heb een testbestand aangemaakt van 2500 regels
daar de volgende code op losgelaten:

myFile = SD.open("TESTDATA.txt", FILE_READ); // file openen, in read modus
// Serial.println(myFile.size()); // even ertussen om mee te kijken hoe groot de file is
aantal = myFile.size()-1800; // 1 regel is 18 char, dus 100 regels terug is minus 1800
myFile.seek(aantal); // nu gaat de cursor naar 100 regels voor het einde

for (int i=0;i<100;i++){ // 100 regels 1 voor 1 opvragen:
buffer=myFile.readStringUntil('\n'); // de regel gaat in de buffer
lcd.setCursor(0,1);
lcd.print(buffer); // de regel komt op het LCD
delay(1000); // seconde wachten... heb je tijd om de LCD te lezen

en achteraf denk je: "dat ik dat niet zelf heb bedacht!"

voor mij is het opgelost, ik kan weer verder!

Fonzie: bedankt!!

Terug naar Arduino software

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 20 gasten