Problema com cartão SD? Programação? Não sei

OI, boa noite

Eu fiz um projeto que ve entrada e saida de pessoas com um sensor infravermelho E18.

A quantidade de pessoas que entra, sai, pessoas na sala e o total disso e mostrado em uma tela LCD 16x2

Mas o meu problema é: Não estou conseguindo gravar o numero total de pessoas que entraram no local no cartão micro SD e não sei o motivo.

Todo o resto está funcionando normalmente menos a gravação no micro SD

**DETALHE: E A MINHA PRIMEIRA VEZ MEXENDO COM ARDUINO

**

Espero não ficar muito confuso !

//SD card
#include <SPI.h>
#include <SD.h>
File ArquivoArduino;

//Painel LCD

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define endereco 0x27
#define colunas 16
#define linhas 2
LiquidCrystal_I2C lcd(0x27, 16, 2);

//Pino sensor, buzzer, SD

int sensor_entrada= 6;
int sensor_saida= 7;
int valor_entrada = 0;
int valor_saida = 0;
int buzzer = 8;
const int SdCard = 4;

//LCD

int conta_entrada = 0;
int conta_saida = 0;
int conta_sala = 0;
int conta_anterior = 0;

void setup() {
Serial.begin(9600);
//SDCard
SD.begin(4);

//Sensor
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8,OUTPUT);

//LCD

lcd.begin(16, 2);
lcd.init();
lcd.display();
lcd.backlight();
lcd.clear();
delay(350);
lcd.print("Sala:0 ");
lcd.setCursor(9, 0);
lcd.print("Tot: 0");
lcd.setCursor(0, 1);
lcd.print("Ent: 0");
lcd.setCursor(9, 1);
lcd.print("Sai: 0");

}
void loop() {
valor_entrada = !digitalRead(sensor_entrada);
valor_saida = !digitalRead (sensor_saida);
digitalRead(buzzer);

//entrada
if(valor_entrada!=1){
digitalWrite(6, HIGH);
digitalWrite(buzzer, HIGH);
delay(50);
digitalWrite(buzzer,LOW);
lcd.setCursor(5,1);
lcd.print(conta_entrada= conta_entrada +1);
lcd.setCursor(14,0);
lcd.print(conta_entrada);
digitalWrite(7, LOW);
delay(2000);
digitalWrite(7, HIGH);

        }
    //Conta sala

{
conta_sala = conta_entrada - conta_saida;
lcd.setCursor(5,0);
lcd.print(conta_sala);
}

//saida  
if(valor_saida!=1){
  digitalWrite(7, HIGH);
  lcd.setCursor(14,1);
  lcd.print(conta_saida= conta_saida +1);   
  digitalWrite(6, LOW); 
  delay(2000); 
  digitalWrite(6, HIGH); 

}
ArquivoArduino = SD.open("dadosArduino.txt", FILE_WRITE);
if (ArquivoArduino){
delay(60000);
ArquivoArduino.println(conta_entrada);
ArquivoArduino.close();
delay(50);
}

}

Olá,

Sempre que colocares código aqui no fórum usa o botão </> para ficar indentado/formatado, para facilitar a respectiva compreensão. Se possível coloca também um esquema simples das ligações entre o Arduino e os restantes componentes (pode ser uma foto de um esquema feito à mão).

Que Arduino usas? Alguns Arduinos funcionam a 5V outros a 3.3V. Penso que os cartões SD geralmente funcionam a 3.3V. Se o Arduino funciona a 5V é necessário assegurar a conversão de nível de tensão 5V para 3.3V nos sinais entre o Arduino e o cartão.

Dizes que o problema está na gravação dos dados no cartão SD. Então no LCD a contagem está correcta?

Não sei exactamente como resolver o problema, mas aqui vão algumas dicas para algumas situações que encontrei no código.

No código defines alguns pinos:

int sensor_entrada= 6;
int sensor_saida= 7;
int buzzer = 8;
const int SdCard = 4;

Mas depois no restante código em vez de usares as definições em alguns locais usas os números, não tirando partido do benefício dessas definições...

Exemplos, em vez disto:

int sensor_entrada= 6;
int sensor_saida= 7;
int buzzer = 8;
const int SdCard = 4;
SD.begin(4);

pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8,OUTPUT);

etc.

Podias usar as definições (usando o #define ou o int como no teu código):

#define PIN_SENSOR_ENTRADA 6
#define PIN_SENSOR_SAIDA 7
#define PIN_BUZZER 8
#define PIN_SDCARD 4
SD.begin(PIN_SDCARD);

pinMode(PIN_SENSOR_ENTRADA, INPUT_PULLUP);
pinMode(PIN_SENSOR_SAIDA, INPUT_PULLUP);
pinMode(PIN_BUZZER,OUTPUT);

etc.

Há algumas instruções que não parecem fazer muito sentido, por exemplo ler o buzzer:

digitalRead(buzzer);

O buzzer está ligado a um pino de saída e não de entrada...

Nas instruções seguintes estás a usar pinos de entrada como se fossem saídas:

digitalWrite(6, HIGH);
digitalWrite(7, LOW);
delay(2000);
digitalWrite(7, HIGH);

O código seguinte tem chavetas '{' '}' sem necessidade. Geralmente usa-se as chavetas '{' '}' para fazer um bloco de código associado a um "if", "while", "for", "switch", etc. ou a uma função.

{
conta_sala = conta_entrada - conta_saida;
lcd.setCursor(5,0);
lcd.print(conta_sala);
}

O teu ciclo principal, o "loop()" tem um tempo de execução muito lento por causa dos delays. Usas delays de 2 segundos e de 60 segundos. Assim fica difícil fazer a detecção de pessoas com os sensores, porque o programa passa a maior parte do tempo bloqueado nos delays... Se esses delays são mesmo necessários procura um tutorial que explique como evitar usar os delays, usando outros métodos que não bloqueiem o ciclo de execução durante tanto tempo. Acho que eu já recomendei alguns noutras threads do forum...

Como é a primeira vez que estás a usar o Arduino, não desanimes! :wink: . No início pode parecer difícil mas depois de ganhares alguma prática fica mais fácil :slight_smile: . Se tiveres oportunidade estuda um livro sobre programação em C e pratica com alguns tutoriais com o Arduino.

Oi!

Muito obrigada pelas dicas, estou aplicando.

Estou usando arduino uno e meu unico problema e que o Cartão SD não está gravando, ja testei o componente e está funcionando corretamente, tanto o componente como o cartão SD

Na tela LCD está aparecendo correto.

Na questão dos delays de 2 segundos e porque precisa continuar desativado por dois segundos para assim a pessoa passar pois a mesma entrada também é a saida.

Você recomenda o uso de um RTC?

Estava pesquisando aqui e acho que vai ter que ser RTC pois eu quero que ele grave duas vezes ao dia....

Se for necessário guardar a data e hora juntamente com a contagem então é boa ideia usar um RTC. Por exemplo um módulo RTC com o DS3231 e pilha de backup, tem exactidão e mantém o relógio em funcionamento mesmo que falhe a alimentação (só é preciso acertar o relógio no inicio).

Se apenas é necessário gravar sem necessidade de saber exactamente a data e hora então basta fazer uma contagem de tempo com o Arduino. A Adafruit tem um bom tutorial que explica como usar a função millis() para fazer a contagem tempo sem usar o delay().

Exemplo:

// Variável global para guardar o tempo anterior em milissegundos (ms).
unsigned long tempo_anterior = 0;

// Variável global com o tempo de intervalo em ms (12 horas = 12*60*60*1000 ms).
unsigned long tempo_de_intervalo = 43200000;

loop() {

  // Obtem o tempo actual em ms em cada execucao do ciclo principal.
  unsigned long tempo_actual = millis();

  // Verifica se o intervalo de tempo ja passou e executa o código pretendido.
  if ( tempo_actual - tempo_anterior > tempo_de_intervalo ) {
    // Actualiza o tempo anterior.
    tempo_anterior = tempo_actual;

    // Coloca aqui o código a executar em cada intervalo de tempo.
    // Por exemplo, gravar no cartao SD, etc.
    // ...

  }


}

Não estou bem a ver com está implementado fisicamente esse sistema de contagem de pessoas. Penso que teria de ser implementado num ponto que possibilite a passagem apenas de uma pessoa de cada vez.

Como o ponto de entrada também é o de saída, para determinar se a pessoa está a entrar ou a sair uma possibilidade seria distanciar os sensores de modo a activar um sensor de cada vez. Dependendo da ordem de activação seria possível determinar se a pessoa está a entrar ou a sair. Teriam de entrar ou sair com algum espaço entre si... o que seria difícil garantir...

Então, pelo que percebi, esse delay de 2 segundos é para evitar fazer múltiplas contagens enquanto passa apenas uma pessoa. Nesse caso, em vez de usar um delay grande, não seria mais simples usar os dados dos sensores para determinar se a pessoa já passou? Isto é, faz-se a contagem de uma pessoa apenas quando se detecta a sequência: Sensor OFF -> Sensor ON -> Sensor OFF. Para isso, em vez de verificares o sensor de 2 em 2 segundos, poderias usar um pequeno delay, por exemplo 20ms, para verificar os sensores e determinar se a sequência é detectada. Apenas uma ideia :slight_smile: ...

Oi, setei as variaveis para fazer 2 intervalos de tempo certo? Certo, como testei usei um segundo e dois segundos

  unsigned long tempo_de_intervalo1 = 1000;
  unsigned long tempo_de_intervalo2 = 2000;
  unsigned long tempo_anterior = 0;

E depois no void loop() botei:

unsigned long tempo_actual = millis();
 if ( tempo_actual - tempo_anterior > tempo_de_intervalo1 ) {
   
    tempo_anterior = tempo_actual;
    ArquivoArduino.println(conta_entrada);
    ArquivoArduino.close();
    delay(50); 

    } 
    if ( tempo_actual - tempo_anterior > tempo_de_intervalo2 ) {
   
    tempo_anterior = tempo_actual;
    ArquivoArduino.println(conta_entrada);
    ArquivoArduino.close();
    delay(50);    

}

Mas ainda não gravou, estou com real bastante dificuldade nisso.... Sera que e porque não setei uma variavel para tempo_actual?

Se fores ver os exemplos, este pedaço de código tem sempre algo mais à volta.

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

Eu aconselharia a fazeres isto e veres se o cartão é inicializado correctamente.

Depois, que hardware estás a utilizar para ler o cartão? Um shield? Que shield?
Já tentaste um dos exemplos do Arduino só para testar se o cartão funciona com o teu hardware? Se não, começa por aí. O mais importante é provar primeiro que todas as ligações estão a funcionar com exemplos para cada um dos módulos e depois começar a utilizar os mesmos.

Depois, este pedaço de código tem alguns problemas.

unsigned long tempo_actual = millis();
 if ( tempo_actual - tempo_anterior > tempo_de_intervalo1 ) {
   
    tempo_anterior = tempo_actual;
    ArquivoArduino.println(conta_entrada);
    ArquivoArduino.close();
    delay(50); 

    } 
    if ( tempo_actual - tempo_anterior > tempo_de_intervalo2 ) {
   
    tempo_anterior = tempo_actual;
    ArquivoArduino.println(conta_entrada);
    ArquivoArduino.close();
    delay(50);    

}

Isto porque em metade das vezes vais tentar escrever para o cartão, mas já fechaste o ficheiro no if anterior. Porque precisas destes dois intervalos a escrever a mesma coisa para o cartão? Já que são múltiplos, porque não acomodar tudo no mesmo if?

unsigned long tempo_actual = millis();
unsigned char segundoDado = 0; 

 if ( tempo_actual - tempo_anterior > tempo_de_intervalo1 ) {
   
    tempo_anterior = tempo_actual;
    ArquivoArduino.println(conta_entrada);
    if (segundoDado % 2 == 0){
           ArquivoArduino.println(conta_entrada); //este ocorre metade das vezes do de cima. 
           segundoDado++;
    }
    ArquivoArduino.close();
    delay(50); 

    } 


}

Pode não ser exatamente esse o problema, mas experimente reduzir o nome do arquivo. "dadosArduino" tem 12 caracteres, quando usualmente se usa até 6.

O limite original eram 8 para o nome assumindo uma extensão de 3.

Uma outra possibilidade a ser verificada está no trecho SDbegin(4);
Isso pressupõe que o pino SS (Chip Select) do seu cartão SD está conectado no pino 4 do Arduíno. Porém, por padrão, o SS é ligado no pino 10.

Nesse mesmo ponto, é importante que o pino SS seja setado como OUTPUT, para que o Arduíno não entre em modo slave na comunicação SPI com o módulo SD Card.

Olá' @Small_Lexy,
para que possamos te ajudar melhor, por favor post um esquema com as ligações do seu projeto.

RV mineirin

Oi, gravação funcionando a todo vapor. Fiz dessa forma e está tudo ok

 if(((tempo_actual - tempo_de_intervalo1) >= 60000) && !PrimeiroIf ) {
          DadoIR = SD.open("dados.txt", FILE_WRITE);
          DadoIR.println("O total de pessoas ao meio dia foi : " + String(conta_entrada) + " pessoas.");
              Serial.println("O total de pessoas ao meio dia  foi : " + String(conta_entrada) + " pessoas.");
          DadoIR.close();
        tempo_de_intervalo1 = tempo_actual;
        PrimeiroIf = true;
    }

      if((tempo_actual - tempo_de_intervalo2) >= 120000) {
          DadoIR = SD.open("dados.txt", FILE_WRITE);
          DadoIR.println("O total de pessoas a meia noite foi : " + String(conta_entrada) + " pessoas.");
             Serial.println("O total de pessoas a meia noite foi : " + String(conta_entrada) + " pessoas.");
          DadoIR.println("Fim do dia.");
          DadoIR.close();
       tempo_de_intervalo2 = tempo_actual; 
    }