LER DATA E HORA NO ARDUINO . Erro no código

O processing é um completo do Arduino que permite gravar o que se visualiza no Serial Monitor do Arduino para um bloco de notas, ou seja, tudo o que fazes Serial.print(), pode ser gravado para um bloco de notas e está sempre a ser atualizado (preenchido), de x em x tempo, definido pelo teu Delay. O processing tem ligação direta com o Arduino.
Isso é o que eu pretendo, para depois fazer o upload do ficheiro para uma base de dados.

Indo de momento à minha questão, eu de momento tenho um delay(1000);

Os resultados no Serial.Monitor aparecem desta forma:

Gostaria de saber se é possível definir essa data e hora visualizada, para a Data e Hora Atual????????

Exemplo:

2013/07/17 17:10:00

Eu estou a imprimir esse resultados dentro do void loop(),(como mostrei no código publicado anteriormente) e foi retirado de uma linha de código que tirei da janela onde fiz o download da biblioteca time, sendo este o código que estou a utilizar:

  time_t t = now(); // Store the current time in time
                    //  variable t 
                    
  hour(t);          // Returns the hour for the given
                    //  time t
  minute(t);        // Returns the minute for the given
                    //  time t
  second(t);        // Returns the second for the given
                    //  time t
  day(t);           // The day for the given time t

  weekday(t);       // Day of the week for the given
                    //  time t  
  month(t);         // The month for the given time t

  year(t);          // The year for the given time t
  
  

  Serial.print(year(t));
  Serial.print("/");
  Serial.print(month(t));
  Serial.print("/");
  Serial.print(day(t)); 
  Serial.print(" "); 

  Serial.print(hour(t));
  printDigits(minute(t));
  printDigits(second(t));
  Serial.println("");

Obrigado!!

E que tal se usasses um RTC para obteres a data e hora actual em vez de usares essa lib?

PedroS23:
Gostaria de saber se é possível definir essa data e hora visualizada, para a Data e Hora Atual????????

Tens isto no teu programa...

void processSyncMessage() {
  unsigned long pctime;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013

  if(Serial.find(TIME_HEADER)) {
     pctime = Serial.parseInt();
     if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013)
       setTime(pctime); // Sync Arduino clock to the time received on the serial port
     }
  }
}

Para que serve?

Mais... se lesses um pouco a documentação encontrarias isto...

TimeSerial.pde shows Arduino as a clock without external hardware.
It is synchronized by time messages sent over the serial port.
A companion Processing sketch will automatically provide these messages
if it is running and connected to the Arduino serial port.

E isto:

The test sketch uses a message on the serial port to set the time. A Processing sketch that sends these messsages is included in the download but you can test this sketch by sending T1262347200 using the serial monitor (this sets the time to noon on Jan 1 2010). On a unix system, you can set the time with the shell command:

Por isso, quando dizes que não queres que façam o trabalho por ti... eu não acredito.

Mortis:
dentro da pasta Examples estarão os exemplos que o HugoPT falou :wink:

dente eles o "\Arduino\libraries\Time\Examples\TimeSerial"

/* 
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */ 
 
#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST,BYTE);  
  return 0; // the time will be sent later in response to serial mesg
}

As vezes as respostas estão muito mais próximas que as perguntas :wink:

Olá, bom dia a todos!

Eu abri exatamente o exemplo do Serial, que vem com a biblioteca times e estava a ter trabalhar a partir daí.

Não consegui então voltar à data e hora atual e pensei:
Utilizo um RTC externo no arduino e o arduino vai lendo o rtc ate ser hora de ler os portos,
OU
Faço um ciclo no processing que vai lendo os timestamps e de n em n tempo pede ao arduino para ler os portos.

Como irei ter o arduino ligado ao PC a segunda opção é a melhor e mais barata.
(e corro o risco do RTC do arduino se atrasar alguns segundos/dia)

Então, irei ter de fazer um codigo no Processing para ir buscar a Data e Hora atual ao RTC do PC, tendo de fazer algo como um if ou while:

  • tenho de ler a data/hora
  • Verificar se segundos == 0?
  • Se não volta ao inicio
  • se sim envia uma comando ao arduino para ele ler a entrada A0
  • abre um ficheiro .txt e escreve a data/hora e o valor da tensão medida em A0

Tenho agora dúvidas se no Arduino tenho de manter a biblioteca time e classe time.h no separador e eventualmente algum código na main??
Ou se tenho apenas de incluir a classe e bliblioteca no próprio Processing!!????

Alguém me sabe responder??
Vi também nos exemplos da biblioteca Time, uma pasta chamada Processing com um exemplo, alguém me sabe dizer se o mesmo é para o Processing para fazer o que pretendo ou para o Arduino???

*Bubulindo, eu não tinha reparado nesses permonores e ainda estou um pouco confuso.
Pelo que entendi posso ir buscar o RTC do PC através do Processing, correto??
Obrigado pelas informações!!

O Arduino, consegue manter a hora de forma mais ou menos fiável... mas não é garantido que seja correcto durante dias ou semanas. Mas como estás a fazer isto em cima do joelho, não tens muito mais hipóteses.

Outra coisa que não percebo é para que precisas do relógio. Se o Arduino apenas serve para adquirir dados, porque é que não usas o relógio do PC para criar a data e hora a que tiraste determinada medição?

http://www.processing.org/discourse/beta/num_1202317523.html

http://www.processing.org/discourse/beta/num_1169318286.html

Assim apenas tinhas de ter o teu processing a enviar um comando para o Arduino de segundo a segundo e o Arduino respondia com o que tinha medido no AD.

Ou seja, para recapitular... apagas todas as librarias do Time, etc... do Arduino.

Fazes um sketch similar a este:

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

}

void loop(){

if (Serial.available() >0) {
   if (Serial.read() == 'M') {
       valAnalog = analogRead(PinAnalogA0);
       temp = (valAnalog * 5.0) /1024;
    
       Serial.print("  Tensao= " );
       Serial.print(temp);      
   }
}//end if 

}

Assim sempre que enviares um M pela porta série, o Arduino lê e envia-te os dados.
Depois apenas tens de colocar a data e hora do processing (que vai buscar isso ao computador) e meter para o ficheiro txt das amostras.

Dito isto, se fosse a ti, estudava o formato de ficheiro .csv já que é bem mais simples de usar com folhas de cálculo como o Excel.

Estás agora a perceber? O Arduino não precisa de saber as horas. Apenas precisa de responder aos comandos do PC.
Se quiseres algo ainda mais simples, colocas o millis() a fazer com que os dados sejam enviados de segundo a segundo.
Depois o processing vê quando recebeu esses dados e junta isso ao teu ficheiro.

Isto não é difícil de fazer, mas se não sabes de programação ou sistemas não se faz dum dia para o outro.

*bubulindo eu basicamente já fiz o meu código para o Arduino!!

O código para o Arduino é o seguinte:

int PinAnalogA0 = 0; 
float valAnalog=0;  // Coloca o Pino A0 a 0
int redPin=13;
int yellowPin=12;
int greenPin=11;

float temp = 0;
int samples[4]; // variavel para melhor precisão
float maxi=0, mini=1000000;


void setup()
{
  Serial.begin(9600);
  
    pinMode(redPin, OUTPUT);  
    pinMode(yellowPin, OUTPUT);  
    pinMode(greenPin, OUTPUT);    
}

void loop ()
{
//  for(i=0; i<=7; i++)
//  { // Obtem 8 amostras da temperatura
//    samples[i] = ( 5.0 * analogRead(PinAnalogA0)) / 1024;
//    temp = temp + samples[i];
//  delay(500);
//  }
 
    valAnalog = analogRead(PinAnalogA0);
    temp = (valAnalog * 5.0) /1024;
    
    if(temp > maxi) 
    {
      maxi = temp;
    } // regista temperatura maxima
    
    if(temp < mini) 
    {
      mini = temp;
    } // regista temperatura minima

    if(temp > 1.50)
    {
      digitalWrite(redPin, HIGH);   // set the green LED on
      digitalWrite(greenPin, LOW);
      digitalWrite(yellowPin, LOW);           
    }
   
    if(temp <= 0.50)
    {
      digitalWrite(redPin, LOW);   // set the red LED on
      digitalWrite(yellowPin, HIGH); 
      digitalWrite(greenPin, LOW);
    }

    if(temp > 0.50 && temp <= 1.50)
    {
      digitalWrite(redPin, LOW);   // set the red LED on
      digitalWrite(greenPin, HIGH); 
      digitalWrite(yellowPin, LOW); 
    }
 
    Serial.print("  Tensao= " );
    Serial.print(temp);
    Serial.print(" || Tensao min= " );
    Serial.print(mini);
    Serial.print(" || Tensao max= " );
    Serial.print(maxi);
    Serial.println("");
  
    delay(2000);
}

O código que fiz para o Processing foi este:

import processing.serial.*; // Importa a biblioteca de comunicação serie
Serial myPort;// Cria um objeto para comunicação
String sensorReading="";
PFont font;
PrintWriter output; //escreve os dados recebidos pela porta 


void setup() 
{
  size(1100,200); // Define o tamanho da janela
  myPort = new Serial(this, "COM4", 9600);  //Conecta-se com a porta COM3
  myPort.bufferUntil('\n');  // Espera receber o primeiro sinal da usb
  font = createFont(PFont.list()[2],32);
  textFont(font);
  output = createWriter( "C:/Users/alunosdefi/Desktop/data.txt" ); //cria o ficheiro de texto neste caminho

}

void draw() 
{
//Nao faz nada mas é necessario declarar
}  

void serialEvent (Serial myPort)
{ 
 sensorReading= myPort.readStringUntil('\n'); // Pega a primeira linha recebida na porta serial
  if(sensorReading != null)
  {   // Se a linha não estiver em branco
    sensorReading=trim(sensorReading); // remove os espaços em branco
 // remove os espaços em branco
  }
  output.println(second() + "\t" + sensorReading); // escreve segundo tab e o valor da tensão x tab valor tensao y
 output.flush(); //escreve todos os dados no ficheiro
 
 writeText("Sensor Reading: " + sensorReading); 
}
  
void writeText(String textToWrite){ //Mostra os valores de tensão numa nova janela com o formato writeText definido anteriormente
  background(230);             //cor de fundo da janela
  fill(0);
  text(textToWrite, width/20, height/2);   
}

Com este código já estou a gravar para um bloco de notas .txt, os valores da tensao lida de 1 em 1 segundo (definida pela delay) e o valor da tensao minima e maxima lida até o momento.

Pelo que percebi, devo manter o meu código de Arduino intacto.
Devo alterar apenas o Processing de forma a ir buscar a Data/hora do Pc imprimir e gravar os mesmos para o mesmo ficheiro txt. que estou a gravar a tensao correto??
O codigo será algo semelhante a este:
Date d = new Date();
long current = d.getTime()/1000; ???

Muito Obrigado

Pedro,

Como o PC ficará o tempo todo conectado ao arduino, você pode seguir a sugestão do bubulindo e economizar com o RTC. Envia a solicitação de dados do PC para o arduino ('M') e o arduino imprime na serial os dados que já estás a ler.

Vá estudando, faça testes isolados (um sketch para testar a comunicação via serial, um para testar a livraria time, etc), tente entender cada linha do código de cada parte e depois junta tudo para o teu projeto final. Assim você encontra a forma que você acha melhor para fazer o que queres.

O meu código tem uma diferença... não existe delay. Se calhar devias tentar isso.

Eu vou pretender gravar os valores de tensão para o bloco de notas de X em X tempo, neste meu caso será 15 minutos, (960 000 milisegundos) ou seja delay(960 000),
Irei fazer um ciclo for do género:

samples[5];
for (int i=0; i<4; i++)
{
samples[i] = ( 5.0 * analogRead(PinAnalogA0)) / 1024;
temp = temp + samples[i];
delay(180000);
}
temp=temp/5;

Serial.print("Tensao=");
Serialprint(temp);
delay(960000);

Desta forma, creio que de 3 em 3 minutos ele lê o valor de tensão da porta analogica A0, no total de 5 medições!
Ao fim de 15 minutos, calcula a média dos 5 valores lidos de 3 em 3 minutos e imprime no Serial_Monitor o valor!
Desta forma terei mais exatidão dos resultados, da tensão média que variou nesses 15 minutos!!

Concordam com o código e com esta minha sugestão???

Contudo neste momento queria tentar gravar para testar de 2 em 2 segundos, por isso coloquei o delay(2000) e neste momento estou a gravar para o bloco de notas através do Processing de 2 em 2 segundos!
aparecendo desta forma no bloco de notas:
6 Tensao= 2.45 || Tensao min= 2.45 || Tensao max= 2.45
8 Tensao= 2.60 || Tensao min= 2.45 || Tensao max= 2.60
10 Tensao= 2.60 || Tensao min= 2.45 || Tensao max= 2.60
12 Tensao= 2.58 || Tensao min= 2.45 || Tensao max= 2.60
...

Agora só preciso mesmo de substituir esses segundos do lado esquerdo, pela Data e Hora do RTC do PC, fazendo isso no Processing, aí está o que é + importante para este projeto e que ainda não consegui!!!!

Pronto!!!!
Consegui!! :slight_smile:

Era isto que pretendia:

Se me poderem ajudar, verifiquem pf se o código anterior no Arduino, para ler de 15 em 15 e fazer a média dos 5 valores lidos de 3 em 3, vos parece bem!!!

Obrigado a todos pela vossa ajuda!!!

Não. Não me parece bem. Parece-me aliás ridículo.

Pesquisa por millis e o exemplo blink without delay.

bubulindo:
Não. Não me parece bem. Parece-me aliás ridículo.

Pesquisa por millis e o exemplo blink without delay.

Reparei que a função millis() volta a zero, passado 50 dias, neste caso a minha aplicação seria para o funcionamento do arduino, durante o ano inteiro!!
Será que com essa função isso iria resultar passado os 50 dias?
Qual é a diferença de utilizar ou não o delay nesse meu exemplo?
Qual é a parte "ridicula" no código? Não funcionaria na prática?

Devido à forma como as variáveis são usadas no calculo, o millis funciona sempre. Mesmo no overlap.

A parte ridícula é empancar o microcontrolador por 15 minutos. Experimenta fazer algo com ele durante esses 15 minutos a ver se funciona...

Eu vou pretender gravar os valores de tensão para o bloco de notas de X em X tempo, neste meu caso será 15 minutos, (960 000 milisegundos) ou seja delay(960 000),

Um grande LOL.
Eu assino por baixo que isso e ridiculo.Para tu teres uma noçao do ridiculo que é o que tu estas a fazer e tipo "vou programar o arduino para no Natal daqui a uns meses me acender um led" por isso vou usar um delaaaaaaayyyyyyyy super gigante.
Vais pensar que eu sou louco correcto pois ninguem fará isto, certo?
Pois bem tu estas a faze-lo so que durante 15 minutos apenas.
Se colocares isso assim todos se vao rir desse delay.
Nao estou a dizer que é impossível tu correres essa tarefa de 15 em 15 minutos, é possivel sim, mas da maneira correcta
Como o Bubulindo te disse ve o exemplo Blink without delay.A tua resposta esta lá.
Há muitas formas de se apertar um parafuso de estrela, podes usar uma faca (as minhas ferramentas enquanto criança XD),um alicate,um garfo,martelo, ou então o correcto, que é usar uma chave estrela com a dimensão correcta e o parafuso sairá intacto e reutilizável sem
dano.É isto que te destinge de um bom programador de um desenrascado ...

Fiquei pensando: "como conseguirá tirar amostragens a cada 3 minutos se o programa estiver em um delay de 15 minutos?" :wink:

Se fizeres o cálculo terás 19 minutos e não 15 que é o que estavas a dizer.

Exorciza esses delays, rapaz!!! xD

Pensa que o arduino pode tirar amostragens de três em tês minutos armazenado a média e mandar mensagem para o PC pela serial, somente quando o computador solicitar ou a cada x tempo sem ficar travadão. É necessário um protocolo master simples e o teu trabalho ficará muito mais elegante!

Se calhar eu também não fui explicito!!
Na verdade eu no Arduino vou converter a tensão lida em Temperatura!!
Como estou a usar o Processsing, o mesmo vai buscar-me os valores lidos pelo Arduino pelo delay definido no Arduino (15minutos), e coloca os mesmos no bloco de texto, no qual usarei para construir a minha Base da Dados!!

Objetivo final??
O objetivo final deste projeto é verificar a variação da Temperatura num dado local, durante o ano todo!!
Nesse sentido, basta-me gravar no bloco de notas, o valor da Temperatura de 15 em 15 minutos, o que equivale a ter 4 valores por hora e 96 valores registados de temperatura por dia! Este foi o tempo que estabeleci.

O que pretendia com o ciclo for, era que o Arduino lê-se o valor da temperatura de 3 em 3 minutos, e quando tivesse 5 valores lidos, ou seja, ao fim dos 15 minutos, fizesse a média dessas 5 temperaturas lidas e que a mesma fosse, através do processing, gravada para o bloco de texto.
Para isso eu defini um delay para correr o ciclo for, de 3 em 3 minutos e outro para enviar os dados para o Processing de 15 em 15.
Neste caso, não me interessa ter LED's a piscar. As saídas que terei é de LED acessos, sempre que a Temperatura passe acima ou abaixo de um dado valor, e se tiver dentro da gama de temperaturas que pretendo, fica com um LED verde ativo!!!

Eu ainda não testei esse ciclo for, mas penso que sabem agora o que pretendo exatamente...
Acham que poderia então fazer isso de uma maneira mais eficaz e com maior exatidão???

Para isso eu defini um delay para correr o ciclo for, de 3 em 3 minutos e outro para enviar os dados para o Processing de 15 em 15.

Mais uma vez, o teu programa tem de ser feito sem um unico delay!
Esquece os delays, sao a abordagem errada!!!

Neste caso, não me interessa ter LED's a piscar

Se estas a dizer isto referente ao exemplo "blink without delay" é porque ou não o leste ou não entendeste a conclusão desse exemplo :~
Se achares que somos nos que estamos errados tenta ir ao forum Programming Questions - Arduino Forum e coloca la isso com esse delay e vê as respostas que te vão dar ...

PedroS23:
Neste caso, não me interessa ter LED's a piscar.

Fique com a mesma impressão que o Hugo, pois o exemplo é o led piscar, mas o método é sem a utilização do dalay.

PedroS23:
Eu ainda não testei esse ciclo for, mas penso que sabem agora o que pretendo exatamente...
Acham que poderia então fazer isso de uma maneira mais eficaz e com maior exatidão???

O procedimento estava claro, o código é que esta travado. Se você testou e esta feliz com o resultado podes deixar assim, mas veja o exemplo abaixo me diz tua opinião:

int PinAnalogA0 = 0;     //Sensor

long previousMillis = 0; // ultimo tempo de execução
long interval = 180000;  // intevalo de 3 minutos para cada amostragem
//você pode criar tantas variáveis iguais à acima quanto julgar necessárias,
//ou pode usar um array e buscar os valores assim exemplo:
//#define tempoAmostra 0
//if(currentMillis - previousMillis[tempoAmostra] >= interval[tempoAmostra])

int samples[5]; //Array para guardar os samples
int curSample = 0; //Array para guardar o exemplo atual

void setup() {
  Serial.begin(9600); //Inicia a serial
}

void loop() //loop infinito que nunca deve ser travado ;)
{
  unsigned long currentMillis = millis(); //pega o milesimo de segunto atual
  
  if(currentMillis - previousMillis >= interval) { //calcuta para saber se o intervalo desejado já ocorreu
    previousMillis = currentMillis;
    
    int total = 0;
    float media = 0;
    
    samples[curSample] = ( 5.0 * analogRead(PinAnalogA0)) / 1024;
    
    if(curSample++ >= 5){ //Já temos 5 amostrages (0 a 4), como 5*3=15 é tempo de notificar o pc
      curSample = 0; //zera o contador para reiniciar as amostragens (editado)
      for (int i=0; i<4; i++) //corre as amostragens 
        total += samples[i]; //soma na variável total
      
      media=total/5;//tira a média das amostragens
      
      Serial.print("Tensao="); //imprime o texto
      Serial.println(media);    //imprime o valor
    }
  }
  
  /*
  O looop continua a ser executado, sem pausas Delays, 
  então se desejas algo a cada 1 minuto é possível, pois
  não esta travado por três minutos, percebes?
  
  if(currentMillis - OutraVarTempoAnterior > OutraVarInterval) { //exemplo a cara 10 segundos
    OutraVarTempoAnterior = currentMillis;
    //executa algo
  }
  (...)
  if(currentMillis - OutraVarTempoAnterior2 > OutraVarInterval2) { //exemplo a cada um segundo
    OutraVarTempoAnterior2 = currentMillis;
    //executa algo
  }
  */
}

Não testei o código acima, o escrevi em poucos minutos para ilustrar o que estamos tentando te dizer. Como podes ver, não estou fazendo um só led piscar LOL