Problemas com a biblioteca SD num programa

Ola, sou novo aqui e não sei bem como isto funcionar, por isso se não estiver a respeitar alguma regra desculpem.
Estou a fazer um trabalho com vários componentes e até agora estava tudo bem, o problema foi quando tentei usar um adaptador SD card com o resto, quando adiciono essa parte ao código ele simplesmente para de funcionar, sem essa parte funciona perfeitamente. Já testei individualmente e funciona, só não funciona em conjunto com outras coisas. o objetivo do programa é recolher dados do sensor BME280, MPU6050, GPS NEO-6M e transmitir os dados por RF com um APC220, depois guarda todas as informações enviadas no cartão SD, ao mesmo tempo tem um buzzer a ligar e desligar quando o loop recomeça. Já agora, se poderem dizer algo para melhorar digam pff, este código ocupa mais de 90% da memória do Arduino Nano.

/*  Nesta parte do programa serão incluidas todas as bibliotecas  */
#include <SoftwareSerial.h>   //Inclui a biblioteca SoftwareSerial.h
#include <Adafruit_BME280.h>   //Inclui a biblioteca Adafruit_BME280.h
#include <TinyGPSPlus.h>    //Inclui a biblioteca TinyGPSPlus.h
#include <Wire.h>    //Inclui a biblioteca Wire.h
#include <SPI.h>    //Inclui a biblioteca SPI.h
#include <SD.h>   //Inclui a bablioteca SD.h

/*  Nesta parte do programa serão defenidos todos os pinos utilizados pelos componentes  */
#define RXapc 6    //Define o pino 7 como RXapc 
#define TXapc 7    //Define o pino 6 como TXapc
//Os pinos estão definos ao contrário propositalmente porque a biblioteca inverte os pinos RX e TX

#define RXgps 4   //Define o pino 3 como RXapc
#define TXgps 3   //Define o pino 4 como RXapc
//Os pinos estão definos ao contrário propositalmente porque a biblioteca inverte o s pinos RX e TX

#define buzzer 5   //Define o pino 5 como buzzer

SoftwareSerial SerialAPC (RXapc, TXapc);    //Cria a variável do APC220 e atribui-lhe os pinos RXapc e TXapc
SoftwareSerial SerialGPS (RXgps, TXgps);    //Cria a variável do GPS NEO 6M e atribui-lhe os pinos TXgps e TXgps

/*  Nesta parte do programa serão criadas todas as variáveis  */
Adafruit_BME280 bme;    //Cria a variável do sensor bme
TinyGPSPlus gps;    //Cria a variável gps da biblioteca
File SDcard;    //Cria o ficheiro com o nome SDcard

bool USB;   //Cria uma variável booleana para a comunicação serial USB

bool buz = false;    //Cria uma variável booleana para o estado do buzzer

float temperatura, pressao, humidade;   //Cria variáveis decimais do sensor BME280

float latitude, longitude;    //Cria variáveis decimais do GPS NEO  6M
int dia, mes, ano, hora, minuto, segundo;    //Cria variáveis inteiras do GPS NEO  6M

int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;    // Cria variáveis inteiras de 16 bits para os 3 eixos do acelarômetro, 3 eixos do giroscópio e temperatura
int minVal=265, maxVal=402;   //Cria variáveis inteiras do MPU6050
double x, y, z;   //Cria variáveis double do MPU6050
int xAng, yAng, zAng;   //Cria variáveis inteiras do MPU6050

void setup() {    //Inicia o void setup

/*  Nesta parte do programa serão feitas as inicializações dos componentes e   */
  Serial.begin(9600);   //Inicia a comunicação serial com a velocidade 9600bps
  pinMode (buzzer, OUTPUT);     //Define buzzer como output
  SerialAPC.begin(9600);    //Inicia a comunicação serial com o APC220
  SerialGPS.begin(9600);    //Inicia a comunicação serial com o GPS com o valor atribuido á variável GPSBaud
  delay(50);    //Cria um tempo de espera de 50 milisegundos
  Wire.begin();   //Inicia a bibilioteca wire
  Wire.beginTransmission(0x68);   //Inicia a transmissão I2C com o endereço 0x68
  Wire.write(0x6B);   //Envia o valor na comunicação I2C
  Wire.write(0);    //Envia o valor na comunicação I2C
  Wire.endTransmission(true);   //Termina a transmissao I2C 
  SD.begin();   //Inicia o cartão SD
  
/*  Nesta parte do programa serão feitas verificações aos componentes e ligações para saber se estão operacionais  */
if (!Serial){    //Se a comunicação serial USB estiver disponível faz
  USB = true;   //A variável terá o valor de verdadede
  Serial.println("Comunicação USB disponível");   //Imprime no monitor serial a mensagem
  SerialAPC.println("Comunicação USB disponível");    //Imprime no APC220 a mensagem
}   //Termina o programa do if
  else{   //Senão
      USB = false;    //A variável terá o valor de falso
      SerialAPC.println("Comunicação USB não disponível");    //Imprime no APC220 a mensagem
  }   //Termina o programa do else

if (!bme.begin(0x77)){   //Caso se verifique se que não iniciou a comunicação com o endereço 0x77
  Serial.println("BME280 não encontrado, endereço ou ligações erradas");    //Imprime no monitor serial  o erro, possiveis soluções e muda de linha
  SerialAPC.println("BME280 não encontrado, endereço ou ligações erradas");    //Imprime no APC220  o erro, possiveis soluções e muda de linha
}   //Termina o programa do if
  else{
      Serial.println("BME280 operacional");
      SerialAPC.println("BME280 operacional");
  }

  delay(1000);   //Cria um tempo de espera de 1000 milisegundos
}   //Termina o void setup

void loop() {   //Inicia o void loop
/*  Nesta parte do programa será feita a alternância de estado do buzzer  */
if (buz == true){   //Se a variável buz for verdadeira faz
  buz = false;    //A variável buz passa a falsa
}   //Termina o programa do if
  else{   //Senão
    buz = true;   //A variável buz passa a verdadeira
  }   //Termina o programa do else
digitalWrite(buzzer, buz);

/*  Nesta parte do programa serão feitas as leituras e atribuições de valores ás variáveis  */
temperatura = bme.readTemperature();
pressao = bme.readPressure() / 100.0F;
humidade = bme.readHumidity();

while (SerialGPS.available() > 0){    //Se a comunicação serial estiver disponivel faz
   if(gps.encode(SerialGPS.read())){    //Se a biblioteca descodificar a leitura da comunicação serial faz
      latitude = gps.location.lat();    //Atribui a leitura do GPS á variável
      longitude = gps.location.lng();   //Atribui a leitura do GPS á variável
      dia = gps.date.day();   //Atribui a leitura do GPS á variável
      mes = gps.date.month();   //Atribui a leitura do GPS á variável
      ano = gps.date.year();    //Atribui a leitura do GPS á variável
      hora = gps.time.hour();   //Atribui a leitura do GPS á variável
      minuto = gps.time.minute();   //Atribui a leitura do GPS á variável
      segundo = gps.time.second();    //Atribui a leitura do GPS á variável
   }
}

Wire.beginTransmission(0x68);   //Inicia a transmição I2c com o endereço 0x68
Wire.write(0x3B);   //Envia o valor na comunicação I2C
Wire.endTransmission(false);    //Não termina a transmissão 
Wire.requestFrom(0x68,14,true);   //Solicita ao endereço 0x68 14bytes e depois liberta o I2C
  AcX=Wire.read()<<8|Wire.read();   //Converte e atribui a leitura á variável AcX
  AcY=Wire.read()<<8|Wire.read();   //Converte e atribui a leitura á variável AcY
  AcZ=Wire.read()<<8|Wire.read();   //Converte e atribui a leitura á variável AcZ
    xAng = map(AcX,minVal,maxVal,-90,90);   //Remapeia os valores de AcX em outros
    yAng = map(AcY,minVal,maxVal,-90,90);   //Remapeia os valores de AcY em outros
    zAng = map(AcZ,minVal,maxVal,-90,90);   //Remapeia os valores de AcZ em outros
      x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);    //Converte os angulos de radianos para graus no eixo X
      y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);    //Converte os angulos de radianos para graus no eixo Y
      z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);    //Converte os angulos de radianos para graus no eixo Z

/*  Nesta parte do programa serão feitas todas as impressões no monitor serial  */
if(USB = true){
Serial.print("Temperatura = ");   //Imprime no monitor serial a condição meteorológica
Serial.print(temperatura);    //Imprime no monitor serial o valor da variável correspondente á condição meteorológica
Serial.println("ºC");  //Imprime no monitor serial as unidades e muda de linha
  Serial.print("Pressão = ");   //Imprime no monitor serial a condição meteorológica
  Serial.print(pressao);    //Imprime no monitor serial o valor da varável corresdente á condição meteorológica
  Serial.println("hPa");   //Imprime no monitor serial as unidades e muda de linha
    Serial.print("Humidade = ");    //Imprime no monitor serial a condição meteorológica
    Serial.print(humidade);   //Imprime no monitor serial o valor da variável correspondente á condição meteorológica
    Serial.println("%");    //Imprime no monitor serial as unidades e muda de linha 2 vezes

Serial.print("Localiazação: ");   //Imprime no monitor serial "Localização: "
Serial.print(latitude, 6);    //Imprime no monitor serial o valor da variável corrspondente á latitude
Serial.print(", ");    //Imprime no monitor serial 
Serial.print(longitude, 6);    //Imprime no monitor serial o valor da variável corrspondente á longitude
  Serial.print("\tData e Hora: ");   //Imprime no monitor serial um espaço entre o texto anterior e "Data/Tempo: "
  Serial.print(dia);   //Imprime no monitor serial o valor da variável corrspondente ao dia
  Serial.print("/");    //Imprime no monitor serial uma divisão entre o dia e mês
  Serial.print(mes);   //Imprime no monitor serial o valor da variável corrspondente ao mês
  Serial.print("/");    //Imprime no monitor serial uma divisão entre o mês e ano
  Serial.print(ano);    //Imprime no monitor serial o valor da variável corrspondente ao ano
    Serial.print("  ");   //Imprime no monitor serial um espaço entre a data e tempo
    Serial.print(hora);    //Imprime no monitor serial o valor da variável corrspondente ás horas
    Serial.print(":");    //Imprime no monitor serial a divisão entre as horas e os minutos
    Serial.print(minuto);    //Imprime no monitor serial o valor da variável corrspondente aos minutos
    Serial.print(":");    //Imprime no monitor serial a divisão entre os minutos e os segundos
    Serial.println(segundo);    //Imprime no monitor serial o valor da variável corrspondente aos segundos
    
Serial.print("Ângulo X= ");    //Imprime no monitor serial o ângulo do eixo X
Serial.print(x);   //Imprime no monitor serial o valor da variável X
Serial.println("º");   //Imprime no monitor serial a unidade e muda de linha
  Serial.print("Ângulo Y= ");    //Imprime no monitor serial o ângulo do eixo Y
  Serial.print(y);   //Imprime no monitor serial o valor da variável Y
  Serial.println("º");   //Imprime no monitor serial a unidade e muda de linha
    Serial.print("Ângulo Z= ");    //Imprime no monitor serial o ângulo do eixo Z
    Serial.print(z);   //Imprime no monitor serial o valor da variável Z
    Serial.println("º\n");   //Imprime no monitor serial a unidade e muda de linha
    
Serial.println("============================================================");
}   //Termina o programa do if

/*  Nesta parte do programa serão feitas todas as impressões (transmissões) para o APC220  */
SerialAPC.print("Temperatura = ");   //Imprime no APC220 a condição meteorológica
SerialAPC.print(temperatura);    //Imprime no APC220 o valor da variável correspondente á condição meteorológica
SerialAPC.println("ºC");  //Imprime no APC220 as unidades e muda de linha
  SerialAPC.print("Pressão = ");   //Imprime no APC220 a condição meteorológica
  SerialAPC.print(pressao);    //Imprime no APC220 o valor da varável corresdente á condição meteorológica
  SerialAPC.println("hPa");   //Imprime no APC220 as unidades e muda de linha
    SerialAPC.print("Humidade = ");    //Imprime no APC220 a condição meteorológica
    SerialAPC.print(humidade);   //Imprime no APC220 o valor da variável correspondente á condição meteorológica
    SerialAPC.println("%");    //Imprime no APC220 as unidades e muda de linha 2 vezes

SerialAPC.print("Localiazação: ");   //Imprime no APC220 "Localização: "
SerialAPC.print(latitude, 6);    //Imprime no APC220 o valor da variável corrspondente á latitude
SerialAPC.print(", ");    //Imprime no APC220 ", "
SerialAPC.print(longitude, 6);    //Imprime no APC220 o valor da variável corrspondente á longitude
  SerialAPC.print("\tData e Hora: ");   //Imprime no APC220 um espaço entre o texto anterior e "Data/Tempo: "
  SerialAPC.print(dia);   //Imprime no APC220 o valor da variável corrspondente ao dia
  SerialAPC.print("/");    //Imprime no APC220 uma divisão entre o dia e mês
  SerialAPC.print(mes);   //Imprime no APC220 o valor da variável corrspondente ao mês
  SerialAPC.print("/");    //Imprime no APC220 uma divisão entre o mês e ano
  SerialAPC.print(ano);    //Imprime no APC220 o valor da variável corrspondente ao ano
    SerialAPC.print("  ");   //Imprime no APC220 um espaço entre a data e tempo
    SerialAPC.print(hora);    //Imprime no APC220 o valor da variável corrspondente ás horas
    SerialAPC.print(":");    //Imprime no APC220 a divisão entre as horas e os minutos
    SerialAPC.print(minuto);    //Imprime no APC220 o valor da variável corrspondente aos minutos
    SerialAPC.print(":");    //Imprime no APC220 a divisão entre os minutos e os segundos
    SerialAPC.println(segundo);    //Imprime no APC220 o valor da variável corrspondente aos segundos
    
SerialAPC.print("Ângulo X= ");    //Imprime no APC220 o ângulo do eixo X
SerialAPC.print(x);   //Imprime no APC220 o valor da variável X
SerialAPC.println("º");   //Imprime no APC220 a unidade e muda de linha
  SerialAPC.print("Ângulo Y= ");    //Imprime no APC220 o ângulo do eixo Y
  SerialAPC.print(y);   //Imprime no APC220 o valor da variável Y
  SerialAPC.println("º");   //Imprime no APC220 a unidade e muda de linha
    SerialAPC.print("Ângulo Z= ");    //Imprime no APC220 o ângulo do eixo Z
    SerialAPC.print(z);   //Imprime no APC220 o valor da variável Z
    SerialAPC.println("º\n");   //Imprime no APC220 a unidade e muda de linha

/*  Nesta parte do programa serão feitas todas as gravações no cartão SD  */

SDcard = SD.open("Cansat.txt", FILE_WRITE);    //Cria o ficheiro Cansat.txt ou abre caso já exista
if (SDcard) {    //Se o ficheiro abrir faz
  SDcard.print("Temperatura = ");   //Imprime no ficheiro do cartão SD a condição meteorológica
  SerialAPC.print(temperatura);    //Imprime no ficheiro do cartão SD o valor da variável correspondente á condição meteorológica
  SDcard.println("ºC");  //Imprime no ficheiro do cartão SD as unidades e muda de linha
    SDcard.print("Pressão = ");   //Imprime no ficheiro do cartão SD a condição meteorológica
    SDcard.print(pressao);    //Imprime no ficheiro do cartão SD o valor da varável corresdente á condição meteorológica
    SDcard.println("hPa");   //Imprime no ficheiro do cartão SD as unidades e muda de linha
      SDcard.print("Humidade = ");    //Imprime no ficheiro do cartão SD a condição meteorológica
      SDcard.print(humidade);   //Imprime no ficheiro do cartão SD o valor da variável correspondente á condição meteorológica
      SDcard.println("%");    //Imprime no ficheiro do cartão SD as unidades e muda de linha 2 vezes

SDcard.print("Localiazação: ");   //Imprime no ficheiro do cartão SD "Localização: "
SDcard.print(latitude, 6);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente á latitude
SDcard.print(", ");    //Imprime no ficheiro do cartão SD ", "
SDcard.print(longitude, 6);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente á longitude
  SDcard.print("\tData e Hora: ");   //Imprime no ficheiro do cartão SD um espaço entre o texto anterior e "Data/Tempo: "
  SDcard.print(dia);   //Imprime no ficheiro do cartão SD o valor da variável corrspondente ao dia
  SDcard.print("/");    //Imprime ficheiro do cartão SD uma divisão entre o dia e mês
  SDcard.print(mes);   //Imprime no ficheiro do cartão SD220 o valor da variável corrspondente ao mês
  SDcard.print("/");    //Imprime no ficheiro do cartão SD uma divisão entre o mês e ano
  SDcard.print(ano);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente ao ano
    SDcard.print("  ");   //Imprime no ficheiro do cartão SD um espaço entre a data e tempo
    SDcard.print(hora);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente ás horas
    SDcard.print(":");    //Imprime no ficheiro do cartão SD a divisão entre as horas e os minutos
    SDcard.print(minuto);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente aos minutos
    SDcard.print(":");    //Imprime no ficheiro do cartão SD a divisão entre os minutos e os segundos
    SDcard.println(segundo);    //Imprime no ficheiro do cartão SD o valor da variável corrspondente aos segundos
    
SDcard.print("Ângulo X= ");    //Imprime no ficheiro do cartão SD o ângulo do eixo X
SDcard.print(x);   //Imprime no ficheiro do cartão SD o valor da variável X
SDcard.println("º");   //Imprime no ficheiro do cartão SD a unidade e muda de linha
  SDcard.print("Ângulo Y= ");    //Imprime no ficheiro do cartão SD o ângulo do eixo Y
  SDcard.print(y);   //Imprime no ficheiro do cartão SD o valor da variável Y
  SDcard.println("º");   //Imprime no ficheiro do cartão SD a unidade e muda de linha
    SDcard.print("Ângulo Z= ");    //Imprime no ficheiro do cartão SD o ângulo do eixo Z
    SDcard.print(z);   //Imprime no ficheiro do cartão SD o valor da variável Z
    SDcard.println("º\n");   //Imprime no ficheiro do cartão SD a unidade e muda de linha
  SDcard.close();    //Fecha o ficheiro
}   //Termina o programa do if
 
  delay(200);   //Cria um tempo de espera de 200 milisegundos
}   //Termina o void loop`

Não tens problemas de incompatibilidade com os pinos? Que reacção é que o Arduino tem quando "deixa de funcionar"?

Se acrescento a parte do SD ele simplesmente para, não faz nada, é como se não tivesse código nenhum dentro, nem void setup faz. Descobri que o problema é só com esta linha:
SDcard = SD.open("Cansat.txt", FILE_WRITE); //Cria o ficheiro Cansat.txt ou abre caso já exista
Quando coloco essa linha ele para completamente.

Uma coisa que pensei é que abrir e fechar o ficheiro de forma tão rápida e consistente não vai fazer bem ao cartão. Não podes, por exemplo, abrir o ficheiro e continuar a gravar com o ficheiro aberto e só fechares quando quiseres mudar de ficheiro ou houver um erro, por exemplo?

Já testaste o cartão SD separadamente para ver se esse código funciona?

Experimenta colocar um Serial.print ("inicio"); logo a seguir à linha Serial.begin(9600); Depois vê se por acaso a palavra início está a ser enviada repetidamente, pois significa que ficaste sem memória.

O cartão SD não tem um ChipSelect? O SD.begin() necessita de receber como parâmetro o pino de selecção do cartão. Como tens o cartão SD ligado e, como perguntei em cima, já funcionou com um dos exemplos da biblioteca SD??

Já testaste o cartão SD separadamente para ver se esse código funciona?

Sim, funciona perfeitamente com o codigo exemplo;

Experimenta colocar um Serial.print ("inicio"); logo a seguir à linha Serial.begin(9600); depois vê se por acaso a palavra início está a ser enviada repetidamente, pois significa que ficaste sem memória.

Ele faz print e repete algumas vezes até para, e coloco outro caracteres que não fazem parte desse print;

O cartão SD não tem um ChipSelect? O SD.begin() necessita de receber como parâmetro o pino de selecção do cartão. Como tens o cartão SD ligado e, como perguntei em cima, já funcionou com um dos exemplos da biblioteca SD??

Ele tem mas experimentei com e sem e não fez nenhuma diferença, parece funcionar normalmente sem ele, por isso optei por tirar;

Uma coisa que pensei é que abrir e fechar o ficheiro de forma tão rápida e consistente não vai fazer bem ao cartão. Não podes, por exemplo, abrir o ficheiro e continuar a gravar com o ficheiro aberto e só fechares quando quiseres mudar de ficheiro ou houver um erro, por exemplo?

É uma boa ideia, irei implementar mas mesmo assim não funciona;

O problema deve ser mesmo memória, eu testei o mesmo codigo sem fazer alguns prints e ele funcionou, mas mal, o void loop só vez duas ou três vezes, depois travou dnv

Edit: já

Descobri o problema, a biblioteca TinyGPSPlus tem problemas de compatiblidade com a biblioteca SD, usei a TinyGPS.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.