Gravando dados cartão SD

Olá, pessoal.
Estou começando a usar o módulo para leitura e escrita em cartão SD. Já consegui gravar e ler mas não estou conseguindo achar na documentação como somente substituir a linha no arquivo txt. Saberiam como posso fazer isto?

Tipo, com Files.println, grava novo dado na linha abaixo dando pulos de linha, eu precisava apagar o conteúdo e regravar o novo sem precisar ficar removendo o arquivo txt, recriando ele e depois gravar no txt.

Estou montando um código para leitura de hidrômetro e a contagem dos pulsos é que vou gravar no SD. Assim, gravando tipo 52010 pulsos, na próxima gravação, queria apagar o 52010 e gravar 52500 por exemplo no mesmo arquivo sem pular linha e nem colocar ao lado.

Isso somente será possível apagando o arquivo txt e criando novamente?

Desde já agradeço a atenção e ajuda todos.

Usando as tags devidas, publique seu codigo para que posamos entender melhor seu projeto e então ajuda-lo.
Informe também qual arduino e qual biblioteca voce está usando. (e o link dela).

Estou usando Arduino nano e a biblioteca SD.

Usando as tags devidas, publique seu codigo para que posamos entender melhor seu projeto e então ajuda-lo.
É possível gravar sempre no inicio do arquivo, sem a necessidade de deletar e criar novo arquivo.

#include <SPI.h>
#include <SD.h>

File myFile;
long randNumber;
String arquivoTxt = "testeafa.txt";

void setup() {  
  Serial.begin(115200);  

  if (!SD.begin(15)) {
    Serial.println("Erro ao iniciar o cartão SD!");
    return;
  }

  Serial.println("Cartão SD iniciado.");

  if (SD.exists(arquivoTxt)) {
    SD.remove(arquivoTxt);
  }

  randNumber = random(100, 300);
  myFile = SD.open(arquivoTxt, FILE_WRITE);

  if (myFile) {
    Serial.print("Gravando randomicamente...");
    myFile.print(randNumber);
    myFile.close();
    Serial.println("ok.");
  } else {
    Serial.print("erro ao abrir o arquivo ");
    Serial.println(arquivoTxt);
  }

  myFile = SD.open(arquivoTxt);
  if (myFile) {
    Serial.print("lendo o arquivo ");
    Serial.println(arquivoTxt);
    
    while (myFile.available()) {
      Serial.write(myFile.read());
    }

    myFile.close();
  } else {
    Serial.print("erro ao ler o arquivo ");
    Serial.println(arquivoTxt);
  }
}

void loop() {
  // nothing happens after setup
}

randNumber é só exemplo, no logar entrará a soma dos pulsos a cada loop. Dessa forma funciona bem, mas tem ficar removendo o arquivo e recriando.

ficará somente um valor inteiro que irá aumentando de tamanho com o tempo, tipo: 102122.

Somente isto na primeira linha, apagando a primeira linha e gravando novamente.

Veja se este processo atende sua necessidade.
o codigo e a simulação estão em:

Dessa forma não funciona. Nas pesquisas que fiz orientava-se a abrir e fechar em seguida o arquivo para limpá-lo, mas o dados anteriores não foram apagados.

Vou tentar alguma solução em código C puro, pois acho que a biblioteca não tem essa funcionalidade.

Há, só não está documentada, o que dificulta a vida de todo mundo.
ao invés de usar

myFile = SD.open(arquivoTxt, FILE_WRITE);

use

myFile = SD.open(arquivoTxt, O_RDWR);

Isso vai permitir que você sobrescreva o conteúdo. Agora, se você não quiser substituir o conteúdo todo, será necessário saber exatamente a posição do arquivo onde você quer começar a substituir o valor e o seu tamanho, o que não será tão simples dado que a quantidade de pulsos deve variar bastante.

1 Like

Obrigado por apoiar a minha sugestão.

Foi exatamente isto que fiz no exemplo no simulador que indiquei para o OP.

2 Likes

Obrigado pela resposta.
Vou testar aqui e dou retorno. Sim, preciso substituir todo o conteúdo. O SD é caso fique sem energia e, ao iniciar, pretendo pegar o valor acumulado no servidor, pegar o valor acumulado no SD e comparar qual é o maior, no qual teria sido o ultimo a ser processado, e recomeçar a partir da comparação.

Nos testes, surgiu uma dificuldade. Uma coisa são simples mas que a biblioteca parece não estar deixando aplicar é o colocar o valor lido do cartão em uma variável, para que possa somar o próximo pulso. Saberia dizer como fazer o valor printado pelo while em uma variável?

Se o que vai ser gravado no arquivo é somente o número de pulsos, creio que é suficiente fazer:

while (myFile.available()) {
      leitura += myFile.read();
    }

onde a variável leitura é um array de caracteres. Depois você usa toInt() para transformar em um número do tipo long (variáveis do tipo int no Arduino vão somente até 32.767).

#include <SPI.h>
#include <SD.h>

#define CS_PIN 15

File gravarCartaoSd;
File lerCartaoSd;
long randNumber;
String arquivoTxt = "testeafa.txt";
String pulsosSd;

void setup() {  
  Serial.begin(115200);
  SD.begin(CS_PIN);

  randNumber = random(100, 300);
  gravarCartaoSd = SD.open(arquivoTxt, FILE_WRITE);

  if (gravarCartaoSd) {
    Serial.println(" ");
    Serial.println("Gravando randomicamente...");
    gravarCartaoSd.print(randNumber);
    gravarCartaoSd.close();
    Serial.println("ok.");
  } else {
    Serial.print("erro ao abrir o arquivo ");
    Serial.println(arquivoTxt);
  }
  
  lerCartaoSd = SD.open(arquivoTxt, O_RDWR);
  if (lerCartaoSd) {
    Serial.print("lendo o arquivo ");
    Serial.println(arquivoTxt);
    
    while (lerCartaoSd.available()) {
      pulsosSd += lerCartaoSd.read();
    }

    Serial.print("Pulsos: ");
    Serial.println(pulsosSd.toInt());

    lerCartaoSd.close();
  } else {
    Serial.print("erro ao ler o arquivo ");
    Serial.println(arquivoTxt);
  }
}

void loop() {
  delay(1000);
}

Teria como dar revisado no código por favor e verificar onde estou errando? Não está atribuindo o valor a variável pulsosSd.

Obrigado.

Fui olhar com mais calma o exemplo que o @ruilviana fez no wokwi e quando tentei usar a abordagem que eu propus (criar um array de char) ela não funcionou porque o compilador diz que a função myFile.read() está retornando um int e não um char.
Eu mexi então no programa, simplesmente atribuindo uma variável long e parece ter funcionado.

Teste essa versão aqui:

#include <SPI.h>
#include <SD.h>

#define CS_PIN 15

File gravarCartaoSd;
File lerCartaoSd;
long randNumber;
String arquivoTxt = "testeafa.txt";
long pulsosSd;

void setup() {  
  Serial.begin(115200);
  SD.begin(CS_PIN);

  randNumber = random(100, 300);
  gravarCartaoSd = SD.open(arquivoTxt, FILE_WRITE);

  if (gravarCartaoSd) {
    Serial.println(" ");
    Serial.println("Gravando randomicamente...");
    gravarCartaoSd.print(randNumber);
    gravarCartaoSd.close();
    Serial.println("ok.");
  } else {
    Serial.print("erro ao abrir o arquivo ");
    Serial.println(arquivoTxt);
  }
  
  lerCartaoSd = SD.open(arquivoTxt, O_RDWR);
  if (lerCartaoSd) {
    Serial.print("lendo o arquivo ");
    Serial.println(arquivoTxt);
    
    while (lerCartaoSd.available()) {
      pulsosSd = lerCartaoSd.read();
    }

    Serial.print("Pulsos: ");
    Serial.write(pulsosSd);
    lerCartaoSd.close();
  } else {
    Serial.print("erro ao ler o arquivo ");
    Serial.println(arquivoTxt);
  }
}

void loop() {
  delay(1000);
}
1 Like

Consegui resolver. Agora, inserindo o seek e abrir o aquivo como O_RDWR, o ponteito é posicionado para gravar a partir da posição 0(zero) e, assim, passou a reescrever sem precisar apagar o arquivo txt de criá-lo novamente. Para colocar o valor que está no arquivo txt em uma variável, cada caractere fica em uma variável char e depois concateno cada caractere em outra variável do tipo String e depois passo a string para int.

Obrigado ruilviana e Brazilino pela ajuda.

#include <SPI.h>
#include <SD.h>

File myFile;
File myFileRead;
long randNumber;
String pulsosSd = "";
char ler;
long pulsosInt;
long somaPulsos;

void setup() {  
  Serial.begin(115200);  

  if (!SD.begin(15)) {
    Serial.println("Erro ao iniciar o cartão SD!");
    return;
  }

  Serial.println(" ");
  Serial.println("Cartão SD iniciado.");
  randNumber = random(1000, 3000);
  myFile = SD.open("testeafa.txt", O_RDWR);

  if (myFile) {
    Serial.print("Gravando randomicamente...");
    myFile.seek(0); 
    myFile.print(randNumber);
    myFile.close();
    Serial.println("ok.");
  } else {
    Serial.println("erro ao abrir o arquivo testeafa.txt");
  }

  myFileRead = SD.open("testeafa.txt", FILE_READ);
  if (myFileRead) {
    Serial.println("Lendo o arquivo testeafa.txt...");
    
    while (myFileRead.available()) {
      ler = myFileRead.read();
      pulsosSd.concat(ler);
    }

    Serial.print("Pulsos: ");
    Serial.println(pulsosSd);

    myFileRead.close();
  } else {
    Serial.println("erro ao ler o arquivo testeafa.txt");
  }

  pulsosInt = pulsosSd.toInt();
  somaPulsos = pulsosInt + 1;

  Serial.print("Soma dos pulsos: ");
  Serial.println(somaPulsos);
}

void loop() {
  // nothing happens after setup
}