11 novembro 2014

Gravando dados do Arduino no cartão SD

Trabalhando com sensores, muitas vezes temos a necessidade de armazenar os dados para consulta posterior, em situações onde não podemos monitorar o circuito todo o tempo. Pode ser quando desejamos consultar a variação de temperatura de um ambiente ou então verificar quando um determinado alarme foi acionado.

Para casos assim podemos gravar os dados do Arduino em um cartão, utilizando o módulo cartão SD :

gravando dados no cartão SD Arduino

Antes de mais nada não se assuste com a quantidade de pinos. São 16, mas usamos apenas 6 para conexão ao Arduino. Olhando o módulo de frente, você pode  usar tanto os pinos da direita como os da esquerda, pois eles tem a mesma  função. Observe a imagem abaixo :


Módulo SD - Pinos

Com relação aos cartões SD, eu testei 3  modelos de cartão no módulo. Sem citar nomes, o cartão de "marca" não funcionou de jeito nenhum, enquanto os cartões genéricos funcionaram perfeitamente. Todos  foram formatados da mesma maneira, e testados com FAT e FAT32. O módulo funcionou com cartões pequenos, de 512 Mb, e também com cartões de maior capacidade, como os de 8 Gb.

Conectando o módulo cartão SD ao Arduino

O módulo SD se conecta ao Arduino utilizando a interface SPI (arduino.cc/en/Reference/SPI), utilizando no nosso exemplo os pinos 4, 11, 12 e 13. A alimentação do módulo é feita por meio do pino 5V  do Arduino.

Atenção com os pinos de sinal, pois eles trabalham com nível de sinal de 3.3V, de  maneira semelhante aos módulos bluetooth que eu já mostrei aqui no site. Utilize  a calculadora desse link  para calcular o valor dos resistores que você  vai utilizar para montar o divisor de tensão. Eu usei resistores de 220 e 330 ohms, que forneceram um  nível de sinal de aproximadamente 3V, suficiente para os testes :

SD Arduino



Gravando dados no cartão SD

No circuito acima eu liguei um push-button à porta digital 3 para demonstrar como os dados são gravados no cartão SD. A cada toque no botão, um contador é incrementado e esse valor é gravado no cartão com o seguinte formato :

Contador : <valor>

O programa utiliza a biblioteca SD, que já está embutida na IDE do Arduino. No inicio do programa é feito um pequeno teste para verificar se as conexões estão corretas e se o cartão SD está sendo reconhecido. Caso esteja tudo ok, um loop verifica se o botão foi pressionado e em caso afirmativo, grava esse dado no cartão SD junto com o valor atual do contador :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Programa : Teste escrita cartao SD
// Autor : Arduino e Cia
// Baseado no arquivo exemplo da biblioteca SD

// Carrega a biblioteca SD
#include <SD.h>

Sd2Card SDcard;
SdVolume volume;

// Pino do Arduino conectado ao pino CS do modulo
const int chipSelect = 4;  
// Pino do Arduino conectado ao push-button
int pinobotao = 3;
int contador = 0;

void setup()
{
  // Define o pino do push-button como entrada
  pinMode(pinobotao, INPUT);
  Serial.begin(9600);
  //Inicia a comunicacao com o modulo SD
  if (!SD.begin(chipSelect)) 
  {
    Serial.println("Falha ao acessar o cartao !");
    Serial.println("Verifique o cartao/conexoes e reinicie o Arduino...");
    return;
  }
  Serial.println("Cartao iniciado corretamente !");
  Serial.println("Aguardando acionamento do push-button...");
  Serial.println();
}

void loop() 
{
  int valor = digitalRead(pinobotao);
  // Verifica se o push-button foi acionado
  if (valor == 1)
  {
    // Delay caso o botão continue pressionado
    while(digitalRead(pinobotao) == 1)
    {
      delay(100);
    }
    // Incrementa o contador e envia os dados para o
    // Serial monitor
    contador=contador++;
    Serial.print("Botao pressionado. Contador : ");
    Serial.println(contador);
  
    // Abre o arquivo arquivo.txt do cartao SD
    File dataFile = SD.open("arquivo.txt", FILE_WRITE);
    // Grava os dados no arquivo
    if (dataFile) 
    {
      dataFile.print("Contador : ");
      dataFile.println(contador);
      dataFile.close();
    }  
    else 
    {
      // Mensagem de erro caso ocorra algum problema
      // na abertura do arquivo
      Serial.println("Erro ao abrir arquivo.txt !");
    } 
  }
}

Após pressionar o push-button algumas vezes, coloque o cartão SD no seu computador, e abra o arquivo ARQUIVO.TXT. Você terá um arquivo nesse formato :

Arquivo cartão SD

33 comentários:

  1. Oi Adilson bom dia.
    Excelente post.
    Será que daria pra ler o conteúdo do cartão diretamente pela serial sem tirar o SD do módulo?
    Grande abraço

    ResponderExcluir
    Respostas
    1. Boa tarde Márcio !

      Obrigado. Tem como ler sim, estive pesquisando isso, só preciso descobrir agora se consigo ler apenas uma "parte" do texto. Por exemplo, fazer o Arduino procurar uma string em um arquivo texto.

      Se eu conseguir, solto um novo post sobre isso. :-)

      Grande abraço. Valeu !

      Excluir
  2. Amigo, estou fazendo um programa para gravar em um módulo SD um arquivo txt com as informações de um eletrodo de pH, no entanto esta gravando dados corrompidos, criando pastas e múltiplos arquivos corrompidos, tipo seus nomes está com letras em arabes simbolos e por ai vai.
    O engraçado que o programa não houve modificações e antes funcionava, já formatei o cartão SD no tipo fat jah liguei o cable select do cartão SD no pino 4 e pino 10, a unica coisa que mudei foi implementar um modulo RTC e um DTH11.

    Abaixo deixo meu programa.

    ResponderExcluir
    Respostas
    1. Bom dia,

      Já tentou separar o programa em partes para ver se alguma delas está interferindo na gravação ?

      Abraço.

      Excluir
  3. #include // Biblioteca para o display LCD
    #include // Biblioteca para SD card
    #include // Biblioteca para o relógio
    #include // Biblioteca para o Termo Higrometro

    #define DHTPIN A3 // pino que estamos conectado
    #define DHTTYPE DHT11 // DHT 11
    DHT dht(DHTPIN, DHTTYPE);

    DS1307 rtc(A4, A5); //Modulo relogio ligado as portas A4 e A5 do Arduino
    LiquidCrystal lcd(8, 7, 6, 5, 3, 2); // Define as entradas digitais do display

    // Declaração de variavéis de pH
    int convph = 0; // Sinal do sensor de pH 0-1024
    float ph = 0.00; // Valor já calculado para exibição do pH no display

    // Declaração de variavéis de temperatura
    int convtemp =0; // Sinal do sensor de temperatura 0 - 1024
    float temp = 0.00; // Valor já calculado para exibição da temperatura no display

    // Declaração de variavéis do Termo Higrometro
    float t;
    float h;

    // Declaração de variavéis do data logger SD
    int botaoAB = 0; // Botão A B
    File arquivo;
    int state = 0;
    int tela=0;

    // Caracteres
    byte aluno[8] = {B01110,B01110,B00100,B01110,B10101,B00100,B01010,B10001};
    byte term[8] = {B00100,B01010,B01010,B01110,B01110,B11111,B11111,B01110};
    byte ur[8] = {B00100,B00100,B01110,B01110,B11111,B11101,B11011,B01110};
    byte tol[8] = {B00000,B00100,B01110,B00100,B00000,B01110,B00000,B00000};
    byte cloc[8] = {B01110,B10101,B10101,B10111,B10001,B10001,B01110,B10001};

    ResponderExcluir
  4. void setup() // Programa principal
    {
    rtc.halt(false); //Aciona o relogio

    //rtc.setDOW(TUESDAY); //Define o dia da semana
    //rtc.setTime(20, 19, 20); //Define o horario
    //rtc.setDate(02, 12, 2014); //Define o dia, mes e ano

    rtc.setSQWRate(SQW_RATE_1);
    rtc.enableSQW(true);
    pinMode(10, OUTPUT);
    pinMode(4, OUTPUT);
    lcd.createChar(1, aluno); lcd.createChar(2, term); lcd.createChar(3, ur); lcd.createChar(4, tol); lcd.createChar(5, cloc);
    lcd.begin(20,4); // Definição do tipo do display
    lcd.print(" TCC - POLITEC "); lcd.write(1); lcd.print("Leandro "); lcd.write(1);
    lcd.print("Vinicius"); lcd.print(" MEDIDOR DATA LOGGER");
    Serial.begin(9600); // Inicia comunicação serial
    if(!SD.begin(4)) // Verifica a comunicação com o SD card
    {
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3);
    lcd.print(" Sem cartao SD!");
    Serial.println("Erro ao iniciar cartao SD!");
    return;
    }
    dht.begin();
    delay(1000); // Tempo de atualização do display
    }

    ResponderExcluir
  5. void loop() // Programa Principal com loops de repetição
    {
    // CÁLCULO DO pH E TEMPERATURA E UMIDADE
    convph = analogRead(A1); // Variavél conv recebe valor de 0 - 1024 do eletrodo de pH
    ph = (((convph- 219.00) * 5.00)/349.00) + 4.00; // Cálculo para atribuir o valor de pH
    convtemp = analogRead(A0); // Variavél convtemp recebe valor de 0 - 1023 do PT-100
    temp = (((convtemp - 205.01) * 100.00)/819.42); // Cálculo para atribuir o valor de temperatura
    t = dht.readTemperature();
    h = dht.readHumidity();
    delay(800); // Atualização das leituras

    // DATA LOGGER VIA SD
    botaoAB = analogRead (A2);
    if(botaoAB > 790 && botaoAB < 850){
    state = !state;
    delay(300);
    }
    if (state == HIGH){
    arquivo = SD.open("data.txt", FILE_WRITE);
    if(arquivo){
    arquivo.print(ph);
    arquivo.print(";");
    arquivo.println(temp);
    arquivo.close();
    delay(1000);
    }
    }
    if(botaoAB > 480 && botaoAB < 540){
    tela ++;
    delay (300);
    if(tela == 5){
    tela =1;
    }
    }
    switch (tela){
    case 1:
    // LEITURA E EXIBIÇÃO DO PH
    lcd.clear (); lcd.setCursor(0, 0); lcd.print(" PH-METRO");
    //lcd.setCursor(0, 1); lcd.print(convph);
    lcd.setCursor(6, 2); lcd.print(ph);
    lcd.setCursor(11, 2); lcd.print(" pH");
    if(ph >=6.5 && ph <=7.5){
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" Solucao Neutra");
    }
    if(ph >=3.5 && ph <6.5){
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" Acido Fraco");
    }
    if(ph <3.5){
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" Acido Forte");
    }
    if(ph >7.50 && ph <=10.5){
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" Base Fraca");
    }
    if(ph >10.50){
    lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(" Base Forte");
    }
    break;

    case 2:
    // LEITURA E EXIBIÇÃO DE TEMPERATURA
    lcd.clear ();
    lcd.print(" TEMPERATURA PT-100"); //lcd.setCursor(0, 1); lcd.print(convtemp);
    lcd.setCursor(5, 2); lcd.write(2); lcd.setCursor(7, 2); lcd.print(temp);
    lcd.setCursor(14, 2); lcd.print("C"); lcd.setCursor(13,2); lcd.print((char)223);
    break;

    case 3:
    // TELA DO TERMOHIGROMETRO
    lcd.clear (); lcd.print(" TERMO HIGROMETRO");
    lcd.setCursor(6,1);
    lcd.write(2); lcd.print(t,1);lcd.print("C");lcd.print((char)223);
    lcd.setCursor(5,2);
    lcd.write(3); lcd.print(h,1);lcd.write(4); lcd.print("5% ");
    break;

    case 4:
    // TELA DO DATA LOGGER VIA SD
    lcd.clear (); lcd.print(" DATA LOGGER");
    lcd.setCursor(0,1);
    lcd.print("Data ");
    lcd.print(rtc.getDateStr(FORMAT_SHORT)); lcd.print(" "); lcd.print(rtc.getDOWStr(FORMAT_SHORT));
    lcd.setCursor(0,2);
    lcd.write(5); lcd.print(" ");
    lcd.print(rtc.getTimeStr());
    if(state==HIGH){
    lcd.setCursor(0, 3); lcd.print(" Gravando SD...");
    }
    else{
    lcd.setCursor(0, 3); lcd.print("Aperte A para Gravar");
    }
    break;
    }
    }

    ResponderExcluir
  6. Olá, gostei muito desse post, só me tira uma duvida... tem como usar um display para ler os arquivos existentes no SD?? uma visualização tipo do DOS do windows, quando nós digitamos o comando "DIR"... seria bom...

    ResponderExcluir
    Respostas
    1. Boa noite,

      Tem sim, só não consigo testar isso agora... Nos programas de exemplo da biblioteca SD tem um exemplo chamado CardInfo, que mostra todos os arquivos do cartão utilizando o comando root.ls(LS_R | LS_DATE | LS_SIZE);, que é "quase" um DIR do DOS. :-)

      Acho que você pode se basear nisso para ler os nomes dos arquivos que estão no cartão e jogar isso em um display LCD.

      Abraço !

      Excluir
  7. Desculpe pela pergunta, talvez seja meio besta, mas já que a comunicação é serial, porque não são utilizados os pinos RX e TX?

    ResponderExcluir
    Respostas
    1. Bom dia Rigel,

      Podem ser utilizados também, dependendo do projeto. Mas no caso, a porta serial é "simulada" pela conexão USB.

      Não sei se essa era a sua dúvida, mas qualquer coisa volte aí.

      Abraço !

      Excluir
  8. Bom dia!
    Uma pergunta, exemplo, tenho esses dados no meu sd:
    23 44 23 f4
    12 fd d3 d3
    e3 22 32 23

    Como faço para identificar cada linha como : 23 44 23 f4 pegar isso no SD e guardar numa varialve tipo String? para poder manipular?

    att
    Pedro Gonçalves

    ResponderExcluir
    Respostas
    1. Bom dia Pedro,

      Estou preparando um post sobre esse assunto, mas você pode ter algumas informações neste link: http://forum.arduino.cc/index.php?topic=127711.0

      Abraço!

      Excluir
  9. Bom dia!
    Gostaria de saber se posso usar um divisor de tensão de R1=1000 R2=2000 ou R1=10000e R2=20000

    ResponderExcluir
  10. Boa tarde,

    Estou fazendo um projeto onde utilizo o shield yun dragino, onde o mesmo não utiliza USB para fazer a comunicação entre o PC e o arduino, ele cria uma rede e faz essa comunicação a partir dela. Então, será que funciona utilizar esse módulo SD para salvar os dados coletados?

    ResponderExcluir
    Respostas
    1. Boa noite Rodolfo,

      Não conheço essa placa, mas a princípio não vejo problema em utilizar o SD nessa configuração.

      Abraço!

      Excluir
  11. boa tarde
    tenho uma maquinade ciclos repetivos, gostaria de saber como faço um programa para um arduino que informe a quantidade de peças que ela produziu e o tempo que ela ficou funcionando atraves de um sensor de pulso.

    ResponderExcluir
    Respostas
    1. Boa noite,

      Você vai precisar de um RTC, correto ? Estou deduzindo que você vai medir a produção diária. Que tipo de sensor você vai usar ?

      Abraço!

      Excluir
  12. Olá, Estou tendo o seguinte código de erro:
    0x1, 0xFF
    Você sabe o que pode ser?

    ResponderExcluir
    Respostas
    1. Boa tarde,

      Esse erro aparece na hora da compilação ?

      Abraço!

      Excluir
  13. Bom dia!
    Existe algum motivo para não utilizar a saída 3.3v do próprio arduino e remover os resitores?

    Grato

    ResponderExcluir
    Respostas
    1. Bom dia,

      Você vai precisar dos resistores pq o nível de sinal do módulo é de 3.3V, independente se você alimentar o mesmo com 3.3V ou 5V.

      Abraço!

      Excluir
  14. Bom dia, desculpe minha ignorancia, eu sou novo nessa area, mas se eu for realizar um prejeto com arduino, o sensor de temperatura dht22 e salvar as mediçoes em um cartao sd, precisarei ainda desse potenciometro, ou posso conectar o cartao direto ? obrigado

    ResponderExcluir
    Respostas
    1. Oi Leonardo,

      Esse projeto em específico não utiliza potenciômetro. Seria algum outro componente ?

      Abraço!

      Excluir
  15. Olá, fiz um código semelhante ao exemplo, mando gravar os dados que necessito, após retirar o cartão SD com o Arduino e colocar no PC, o arquivo está normal. Após colocar o cartão SD com o Arduino ainda ligado, o código não executa mais a escrita. Gostaria de saber o motivo, aguardo uma resposta, muito obrigado.

    ResponderExcluir
    Respostas
    1. Boa noite Fábio,

      Realmente depois que vc retira o cartão e coloca novamente, ele dá esse erro. É necessário reiniciar o Arduino.

      Abraço!

      Excluir
  16. Boa noite, o esquema de ligação da figura está realmente certo? Ainda vou testar aqui em casa, mas me parece que os resistores estão conectados diretamente um na saida do outro, fechando o circuito direto... por exemplo o fio amarelo, vc alimentou ele com positivo, passou por um resistor e já tem outro resistor em seguida, fechando circuito com o pino 12

    ResponderExcluir
    Respostas
    1. Oi Hemerson,

      Não, o fio amarelo sai do pino 12, vai para o resistor, e com o 2o. resistor (que está ligado ao negativo), ele faz um divisor de tensão. Não tem positivo no fio amarelo. passa direto....

      Abraço!

      Excluir
    2. Obrigado pela resposta amigo.

      Abraço

      Excluir
    3. Oi,

      eu fiz o esquema conforme o artigo, mas só fica dando erro ao abrir arquivo txt e falha no cartão, já verifiquei todas as conexões. Pode me ajudar?

      Ps.: uso um arduino mega. (mas usei os mesmos pinos)

      Excluir
  17. Olá amigo, consigo salvar em um txt normal sem cartão SD ?

    ResponderExcluir
  18. Boa Tarde,

    Estou tendo dificuldades em fazer este projeto funcionar. Estou utilizando este módulo SD com um Arduino Mega.

    Fiz a conexão dos resistores nos pinos Mosi-51, MISO-50, CLK-52, CS-53 e alterei a linha 12 para const int chipSelect = 53;

    Testei 4 cartões SD de 1, 2, 4 e 64GB com formatação FAT e FAT32, mas nenhum dos testes que realizei funcionou. Poderia me ajudar?

    Obrigado

    ResponderExcluir