Publicidade:

segunda-feira, 14 de setembro de 2015

Arduino - Números aleatórios (repetidos e não repetidos)

No Arduino temos duas funções que nos permitem gerar números aleatórios.

RandomSeed() e Random().

Na verdade os números aleatórios gerados em conjunto pelas funções acimas não são inteiramente aleatórios, eles são na verdade pseudo aleatórios, o que significa dizer, que parecem números aleatórios, mas não são. Na prática, os números aleatórios gerados pelas funções acima, são pré determinados, dependendo do valor passado para RandomSeed(valor).

Normalmente RandomSeed é chamado no início da execução do programa e inicializado com um valor qualquer, porém se na inicialização de RandomSeed for passado sempre o mesmo valor, a sequencia de números aleatórios gerados será sempre a mesma.

Se a intenção for gerar sequencia de números diferentes a cada inicialização de randomSeed, deve-se então, ser passado valores diferentes a cada inicialização.

Existem algumas alternativas no Arduino para conseguirmos números (seed: que significa semente) diferentes a cada vez que se deseja inicializar o RandomSeed. A mais utilizada é utilizar o valor lido de uma porta analógica não conectada, que por não estar conectada, acaba retornando valores diferentes. Nos casos em que os números aleatórios são gerados a partir de uma ação externa do arduino, como o pressionar de um botão, a leitura de um valor ou qualquer outra ação, o valor a ser utilizado para inicializar o RandomSeed, pode ser baseado no valor de millis() do arduino, que é o tempo em millissegundos já passados desde que o arduino foi ligado. Outra possibilidade seria ainda gravar na eeprom o ultimo utilizado para inicializar, e na próxima vez que o arduino inicializar o RandomSeed, o valor gravado na eeprom ser incrementado.

Como vimos, então, randomSeed é utilizado para gerar uma sequencia aleatória de números. Agora vamos ver como funciona a função random(), que é a função que retorna o número aleatório, quando desejamos um.

random() pode ser chamada com dois, ou com um parâmetros. Quando chamada com dois, significa que queremos números aleatórios entre o primeiro e o ultimo valor, por exemplo, random(10, 20) irá retornar somentes os seguintes valores {10,11,12,13,14,15,16,17,18 e 19}. Percebam que 20 não será retornado.

Quando chamada com um único parâmetro, como por exemplo, random(300), significa que irá retornar qualquer valor entre 0 e 299.

abaixo tem um exemplo retirado da página do Arduino:

https://www.arduino.cc/en/Reference/Random

long randNumber; 
void setup() { 
  Serial.begin(9600); 
  // if analog input pin 0 is unconnected, random analog 
  // noise will cause the call to randomSeed() to generate 
  // different seed numbers each time the sketch runs. 
  // randomSeed() will then shuffle the random function. 

  randomSeed(analogRead(0)); 
} 

void loop() { 
  // print a random number from 0 to 299 
  randNumber = random(300); 
  Serial.println(randNumber); 

  // print a random number from 10 to 19 
  randNumber = random(10, 20); 
  Serial.println(randNumber); 
  delay(50); 
}



Aleatórios não repetidos


Quando projetamos um programa que necessita de valores aleatórios, há basicamente duas situações diferentes, que são os casos onde os números sorteados podem se repetir, e outras onde os números não podem se repetir.

Num bingo por exemplo, os números sorteados nunca se repetem, pois a cada valor sorteado o mesmo é removido do globo, enquanto que numa roleta de cassino os valores sorteados podem ser repetidos.

Para conseguirmos gerar números não repetidos, é necessário gerarmos uma lista de números, embaralharmos os mesmos (muda-los de posição de modo aleatório), e posteriormente lermos os números sequencialmente do início da lista até o fim. Assim garantimos que se tenhamos 10 números na lista não iremos ter sorteios repetidos nos primeiros 10 números sorteados.

Para facilitar esse processo, criei uma classe que faz esse trabalho.


/**********************************************************************************
************************************CLASSE UNIQUE RANDOM***************************
**********************************************************************************/

class UniqueRandom{
  private:
    int _index;
    int _min;
    int _max;
    int _size;
    int* _list;
    void _init(int min, int max) {
      _list = 0; 
      if (min < max) { _min = min; _max = max; } else { _min = max; _max = min; }
      _size = _max - _min; 
      _index = 0;
    }    
  public:
    UniqueRandom(int max)           { _init(0,   max); randomize(); } //construtor com 1 parametro
    UniqueRandom(int min, int max)  { _init(min, max); randomize(); } //construtor com 2 parametros
    
    void randomize() {
      if (_list == 0) { _list = (int*) malloc(size() * sizeof(int)); }  
      for (int i=0; i<size(); i++) {   _list[i] = _min+i;  }   //preenche a lista do menor ao maior valor
      
      //embaralha a lista
      for (int i=0; i<size(); i++) {  
        int r = random(0, size());     //sorteia uma posição qualquer
        int aux = _list[i];               
        _list[i] = _list[r];
        _list[r] = aux;
      }
    }
    
    int next() {                                  //retorna o proximo numero da lista
      int n = _list[_index++];
      if (_index >= size() ) { _index = 0;} //após recuper o ultimo numero, recomeça na posicao 0
      return n;
    }
    
    int size() { return _size; }
    
    ~UniqueRandom(){ free ( _list ); }  //destrutor
};
/**********************************************************************************
************************************FIM CLASSE UNIQUE RANDOM***********************
**********************************************************************************/


/**********************************************************************************
************************************SETUP / LOOP***********************************
**********************************************************************************/

UniqueRandom ur(10, 30); //declaracao do objeto unique random

void setup() {
  Serial.begin(9600);
  
  int seed = 0;
  
  for (int i=0; i<10; i++) {
    seed += ( analogRead(A0) + analogRead(A1) + analogRead(A2) + analogRead(A3) + analogRead(A4) + analogRead(A5) ) ;
    delay(10);
  }
  randomSeed(seed);
  
  Serial.print("Seed: ");
  Serial.println(seed);
  
}

void loop() {
    
  Serial.println("");
  Serial.print( "Iniciando com " );
  Serial.print( ur.size() );
  Serial.print( " itens: " );
    
  ur.randomize();  //gera os numeros aleatoriamente
    
  for (int i=0; i<ur.size(); i++){
    Serial.print( ur.next() );
    Serial.print( " " );
  }
    
  delay(100);
}

/**********************************************************************************
************************************FIM SETUP / LOOP*******************************
**********************************************************************************/




Exemplo de uso com matriz de led 8x8



#include "LedControl.h"

/**********************************************************************************
************************************CLASSE UNIQUE RANDOM***************************
**********************************************************************************/

class UniqueRandom{
  private:
    int _index;
    int _min;
    int _max;
    int _size;
    int* _list;
    void _init(int min, int max) {
      _list = 0; 
      if (min < max) { _min = min; _max = max; } else { _min = max; _max = min; }
      _size = _max - _min; 
      _index = 0;
    }    
  public:
    UniqueRandom(int max)           { _init(0,   max); randomize(); } //construtor com 1 parametro
    UniqueRandom(int min, int max)  { _init(min, max); randomize(); } //construtor com 2 parametros
    
    void randomize() {
      if (_list == 0) { _list = (int*) malloc(size() * sizeof(int)); }  
      for (int i=0; i<size(); i++) {   _list[i] = _min+i;  }   //preenche a lista do menor ao maior valor
      
      //embaralha a lista
      for (int i=0; i<size(); i++) {  
        int r = random(0, size());     //sorteia uma posição qualquer
        int aux = _list[i];               
        _list[i] = _list[r];
        _list[r] = aux;
      }
    }
    
    int next() {                                  //retorna o proximo numero da lista
      int n = _list[_index++];
      if (_index >= size() ) { _index = 0;} //após recuper o ultimo numero, recomeça na posicao 0
      return n;
    }
    
    int size() { return _size; }
    
    ~UniqueRandom(){ free ( _list ); }  //destrutor
};
/**********************************************************************************
************************************FIM CLASSE UNIQUE RANDOM***********************
**********************************************************************************/

/*
 pin 4 is connected to the DataIn 
 pin 6 is connected to the CLK 
 pin 5 is connected to LOAD 
 */

LedControl lc=LedControl(4,6,5,1); //1 max7219
UniqueRandom ur(64); //declaracao do objeto unique random

/* we always wait a bit between updates of the display */
unsigned long delaytime=500;

void setup() {
  int seed = 0;
  
  for (int i=0; i<10; i++) {
    seed += ( analogRead(A0) + analogRead(A1) + analogRead(A2) + analogRead(A3) + analogRead(A4) + analogRead(A5) ) ;
    delay(10);
  }
  randomSeed(seed);
  
  lc.shutdown(0,false);
  lc.setIntensity(0,8);
  lc.clearDisplay(0);
}

void loop() { 
  lc.clearDisplay(0);
  delay(delaytime/2);
  
  ur.randomize();
    
  for(int i=0; i<64; i++) {  
    int r = ur.next();
      
    int l = r / 8;
    int c = r % 8;
     
    delay(100);
    lc.setLed(0, l, c, HIGH );
  }
  
  
  ur.randomize();
    
  for(int i=0; i<64; i++) {  
    int r = ur.next();
      
    int l = r / 8;
    int c = r % 8;
     
    delay(100);
    lc.setLed(0, l, c, LOW );
  }
  
  delay(delaytime*2);
}

Atualização 25/11/2015 - Números do tipo double ou float (com casas decimais)

Essa semana me pediram como fazer para gerar números aleatórios com números números do tipo double ou float, ou seja, com casas decimais. Na verdade a ideia é até bem simples, vamos supor que você queira números aleatórios entre 5.58 e 9.44... considerando os números com até duas casas decimais nesse intervalo.

Nesse caso basta multiplicar o 5.58 por 100 (ou 10² ou pow(10, 2)  ) o que daria um número inteiro igual a 558. Aplicando o mesmo ao 9.44 teremos 944. Se fosse com 3 casas decimais, multiplicaríamos o número por 1000 (ou 10³ ou pow(10,3) ).

Tendo convertido os dois números para inteiros, bastaria agora utilizar a função random normalmente, porém o valor retornado precisa ser divido pelo valor multiplicado anteriormente para que o mesmo volte à mesma faixa utilizada inicialmente, tendo o cuidado de armazenar o resultado em um campo do tipo double, para que as casas decimais não sejam perdidas.

Para facilitar o uso, criei um exemplo com uma função que chamei de randomDouble, onde são passados 3 valores: o valor mínimo, o valor máximo, e a quantidade de casas decimais a ser considerada:



Código:

double randomDouble(double min, double max, int numCasas){
  long _min = min * pow(10, numCasas) + 0.1;  //0.1--> para corrigir erro da funcao pow. funciona até 4 casas. mais que isso da erro no calculo.
  long _max = max * pow(10, numCasas) + 0.1;
  
  return (double) random(_min, _max) / pow(10, numCasas) ; 
}

void setup() { 
  Serial.begin(9600); 
  randomSeed(analogRead(0)); 
} 

void loop() { 
  double randNumber = randomDouble(10.20, 11.05, 2);
  Serial.println(randNumber); 
  
  delay(500); 
}

sábado, 12 de setembro de 2015

Arduino - DIY - Módulo Gravador Attiny85

Como fazer um módulo gravador para Attiny que encaixa no Arduino.

Download: https://docs.google.com/uc?export=download&id=0B9ZzXhiNwNSrUkVpbXpKYWdCbFU

Para ver o artigo sobre os módulos para 74HC595, clique no link abaixo.

http://fabianoallex.blogspot.com.br/2015/08/arduino-modulo-expansor-74hc595.html


Vídeo:




Fotos:













Veja nesse vídeo como fazer a montagem dos componentes:


quinta-feira, 13 de agosto de 2015

Arduino - Modulo Expansor 74HC595



Download:

Módulo com 01 CI: https://docs.google.com/uc?export=download&id=0B9ZzXhiNwNSrV2tMNGNBNkpDV1E
Módulo com 02 CI:  https://docs.google.com/uc?export=download&id=0B9ZzXhiNwNSrZk1oVGZyV3VYSU0


Vídeo demonstrando os módulos funcionando.



Fotos:













Código-fonte


class Expansor74HC595 {
  private:
    int  _pin_clock;
    int  _pin_latch;
    int  _pin_data;
    int  _num_cis;
    byte* _pins;
    int  _auto_send;
  public:
    Expansor74HC595(int pin_clock, int pin_latch, int pin_data, int num_cis){
      _pin_clock        = pin_clock;
      _pin_latch        = pin_latch;
      _pin_data         = pin_data;
      _num_cis          = num_cis;
      _auto_send        = true;
      _pins             = new byte[_num_cis];
 
      pinMode(_pin_clock,OUTPUT);
      pinMode(_pin_latch,OUTPUT);
      pinMode(_pin_data, OUTPUT);
      clear();
    };
   
    void startWrite() { 
      _auto_send = false; 
    };
     
    void clear() { 
      for (int i=0; i<_num_cis; i++){ 
        _pins[i] = 0b00000000; 
      }
       
      send();  
    };
   
    int read(int pin)  { 
      if (pin >= _num_cis * 8) {return LOW;} 
       
      int pos = pin / 8;
      pin = pin % 8;
 
             
      return (_pins[pos] & (1 << pin)) != 0;
    };
   
    byte readByte(int num_ci) { 
      return _pins[num_ci];
    };
    
    void send(){
       
      digitalWrite(_pin_latch, LOW); 
      for(int i=_num_cis-1; i>=0; i--) {  shiftOut(_pin_data, _pin_clock, MSBFIRST, readByte(i) );  }
      digitalWrite(_pin_latch, HIGH);
      _auto_send = true;
       
    };
     
    void writeByte(int num_ci, byte b, int first = MSBFIRST) {  
       
      if (first == MSBFIRST){
        byte reversed;
        for(int i=0;i<8;i++){
          reversed |= ((b>>i) & 0b1)<<(7-i);
        }
        b = reversed;
      }
       
      _pins[num_ci] = b; 
      if (_auto_send) { send(); } 
    } ;
     
    void write(int pin, int value) {
      if (pin >= _num_cis * 8) { return; }
       
      int pos = pin / 8;
      pin     = pin % 8;
 
      if (value){
        _pins[pos] |= (1 << pin);  //set a bit HIGH
      } else {
        _pins[pos] &= ~(1 << pin); //set a bit LOW
      }
 
      if (_auto_send) { send(); }
    };
};
  
 
const int PIN_CLOCK = 13; 
const int PIN_LATCH = 12; 
const int PIN_DATA  = 11; 
 
Expansor74HC595 *exp1;
  
void setup() {
  exp1   = new Expansor74HC595(PIN_CLOCK, PIN_LATCH, PIN_DATA, 3);
   
  Serial.begin(9600);
}
  
void loop() {
  for (byte b=0; b<=255; b++) {                    //i=0-> B00000000   i=255-> B11111111
    exp1->startWrite();
    exp1->writeByte(0, b);
    exp1->writeByte(1, b, LSBFIRST);
    exp1->writeByte(2, b);
    exp1->send();
   
    delay(500);
  }
   
  exp1->clear();
  delay(500); 
}

Arduino - NTP - Acessando Servidor de Hora pela Internet ou Rede

Olá Pessoal,

No vídeo abaixo mostro a execução de um sketch que solicita a hora atual a um servidor de horas. Esse Sketch foi baseado inicialmente no exemplo que vem com o Arduino, como mostrado na imagem abaixo e posteriormente alterado para que fosse possível utilizar o DNS com o Arduino 1.0. e disponibilizado nesse endereço: https://gitlab.com/mharizanov/Udp-NTP-Client-with-DNS-on-Arduino/blob/master/arduino_NTP_DNS.ino




Baseado nesse exemplo, fiz algumas modificações para que fosse possível extrair além de hora, minuto e segundo, extrair também dia da semana, dia, mês e ano. Pra isso foi preciso criar uma função que lesse o Unix Time e extraísse data e hora completa. No código, essa função se chama void localTime(...). Essa função foi baseada no funcionamento interno da Biblioteca DateTime (http://playground.arduino.cc/Code/DateTime), que não teve, nesse exemplo, a necessidade de ser utilizada totalmente.

No Brasil um serviço disponível é o http://ntp.br/ o qual possui alguns IPs que fornecem a hora via protocolo NTP (https://pt.wikipedia.org/wiki/Network_Time_Protocol).

Servidores NTP.br
a.st1.ntp.br200.160.7.186 e 2001:12ff:0:7::186
b.st1.ntp.br201.49.148.135
c.st1.ntp.br200.186.125.195
d.st1.ntp.br200.20.186.76
a.ntp.br200.160.0.8 e 2001:12ff::8
b.ntp.br200.189.40.8
c.ntp.br200.192.232.8
gps.ntp.br200.160.7.193 e 2001:12ff:0:7::193

Há Vários outros sites com esse serviço e há ainda a possibilidade de acessar através de um servidor próprio e interno.

A partir desse exemplo, é possível atualizar um RTC, ou mesmo ter data e hora sem a necessidade de um modulo RTC. Mas é importante observar que não é aconselhável fazer essa consulta repetidamente para toda vez que quiser saber a hora ou mostrar ela em algum lugar. O ideal seria ter um período de, por exemplo, a cada 24 horas fazer essa atualização. Uma estratégia pra quem quer ter a data e hora no Arduino sem um rtc, seria ter uma variável que armazenasse o Unix Time lido, e outra que armazenasse o millis do Arduino da ultima vez que foi feita a leitura da hora no servidor. Com isso, toda vez que quiser saber a hora atual, bastaria fazer a seguinte conta:

[millis atual] - [millis lido ao ler a hora]

Com isso, bastaria transformar o resultado acima em segundos e somar ao Unix Time e então fazer a extração da data e hora como mostrado no vídeo. Quem sabe eu faça um vídeo futuramente mostrando como fazer isso.

Outro detalhe importante, é saber o fuso horário retornado pelo servidor. Caso seja diferente, haverá a necessidade de ajustar o Unix time retornado ao fuso horário local.

vídeo:




código-fonte:


/*
alterado por Fabiano A. Arndt,
baseados nos créditos abaixo.

fabianoallex@gmail.com
www.youtube.com/fabianoallex
*/

/*
Udp NTP Client with DNS
I updated the example code to use DNS resolution from the Arduino 1.0 IDE
Basically tries to use the load-balanced NTP servers which are
"magically" returned from DNS queries on pool.ntp.org
If DNS fails, fall back to the hardcoded IP address
for time.nist.gov
bearpaw7 (github), 01DEC2011
This code is also in the public domain.
*/

/*
Udp NTP Client

Get the time from a Network Time Protocol (NTP) time server
Demonstrates use of UDP sendPacket and ReceivePacket 
For more on NTP time servers and the messages needed to communicate with them, 
see http://en.wikipedia.org/wiki/Network_Time_Protocol

created 4 Sep 2010 
by Michael Margolis
modified 17 Sep 2010
by Tom Igoe

This code is in the public domain.

*/

/**********************************************************************************
************************************BIBLIOTECAS************************************
**********************************************************************************/
#include <SPI.h>   
#include <Ethernet.h>
#include <EthernetUdp.h>
#include "Dns.h"
/**********************************************************************************
************************************FIM BIBLIOTECAS********************************
**********************************************************************************/

/**********************************************************************************
************************************ETHERNET CONFIG/FUNCTIONS**********************
***********************************************************************************
se for rodar numa rede com firewall, verifique se os ip utilizado está liberado.
Servidores da NTP.br
a.st1.ntp.br 200.160.7.186 e 2001:12ff:0:7::186
b.st1.ntp.br 201.49.148.135
c.st1.ntp.br 200.186.125.195
d.st1.ntp.br 200.20.186.76
a.ntp.br 200.160.0.8 e 2001:12ff::8
b.ntp.br 200.189.40.8
c.ntp.br 200.192.232.8
**********************************************************************************/

byte mac[] = {  0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD};
unsigned int localPort = 8888;   // local port to listen for UDP packets
IPAddress timeServer(200, 192, 232, 8);  // time.nist.gov NTP server (fallback) - segunda tentativa caso a primeira de erro

const int NTP_PACKET_SIZE= 48;    // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE];   // buffer to hold incoming and outgoing packets 

//host para a primeira tentativa
const char* host = "ntp02.oal.ul.pt";  // servidor da NTP.br - ver lista acima para todos os servidores da NTP.br
//const char* host = "192.168.200.254";  // servidor interno 01 - caso tenha um servidor de hora interno, pode ser configurado o nome ou ip na variavel host
//const char* host = "192.168.200.253";  // servidor interno 02

EthernetUDP Udp;
DNSClient Dns;
IPAddress rem_add;

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address) {
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 

  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;    // Stratum, or type of clock
  packetBuffer[2] = 6;    // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision

  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49; 
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
 
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

/**********************************************************************************
************************************FIM ETHERNET CONFIG/FUNCTIONS******************
**********************************************************************************/

/**********************************************************************************
************************************UNIX TIME FUNCTIONS****************************
***********************************************************************************
localTime --> converte o unix time para ano, mes, dia semana, dia, hora, 
              minuto e segundo
              função baseada na biblioteca dateTime, pois não era necessário usar 
              toda a biblioteca.
              (http://playground.arduino.cc/Code/DateTime)
              descrição original: 
                convert the given timep to time components
                this is a more compact version of the C library localtime function
**********************************************************************************/
#define LEAP_YEAR(_year) ((_year%4)==0)
static  byte monthDays[] = {31, 28, 31, 30 , 31, 30, 31, 31, 30, 31, 30, 31};

void localTime(unsigned long *timep, byte *psec, byte *pmin, byte *phour, byte *pday, byte *pwday, byte *pmonth, byte *pyear) {
  unsigned long long epoch =* timep;
  byte year;
  byte month, monthLength;
  unsigned long days;
  
  *psec  =  epoch % 60;
  epoch  /= 60; // now it is minutes
  *pmin  =  epoch % 60;
  epoch  /= 60; // now it is hours
  *phour =  epoch % 24;
  epoch  /= 24; // now it is days
  *pwday =  (epoch+4) % 7;
  
  year = 70;  
  days = 0;
  while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= epoch) { year++; }
  *pyear=year; // *pyear is returned as years from 1900
  
  days  -= LEAP_YEAR(year) ? 366 : 365;
  epoch -= days; // now it is days in this year, starting at 0
  
  for (month=0; month<12; month++) {
    monthLength = ( (month==1) && LEAP_YEAR(year) ) ? 29 : monthDays[month];  // month==1 -> february
    if (epoch >= monthLength) { epoch -= monthLength; } else { break; }
  }
  
  *pmonth = month;  // jan is month 0
  *pday   = epoch+1;  // day of month
}

/**********************************************************************************
************************************FIM UNIX TIME FUNCTIONS************************
**********************************************************************************/

/**********************************************************************************
**************************************** FUNÇÕES FORMATAR DATA/HORA ***************
**********************************************************************************/
String zero(int a){ if(a>=10) {return (String)a+"";} else { return "0"+(String)a;} }

String diaSemana(byte dia){
  String str[] = {"Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sabado"};
  return str[dia];
}
/**********************************************************************************
****************************************FIIM FUNÇÕES FORMATAR DATA/HORA ***********
**********************************************************************************/

/**********************************************************************************
**************************************** SETUP / LOOP *****************************
**********************************************************************************/
void setup() {
  pinMode(4, OUTPUT);      //ANTES DE INICIAR O ETHERNET, DESABILITA O SDCARD
  digitalWrite(4, HIGH);

  Serial.begin(9600);
  if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); }
  
  Udp.begin(localPort);
  Dns.begin(Ethernet.dnsServerIP() );
}

void loop() {
  if(Dns.getHostByName(host, rem_add) == 1 ){
    Serial.println("DNS resolve...");  
    Serial.print(host);
    Serial.print(" = ");
    Serial.println(rem_add);
    sendNTPpacket(rem_add);
  } else {
    Serial.println("DNS fail...");
    Serial.print("time.nist.gov = ");
    Serial.println(timeServer); // caso a primeira tentativa não retorne um host válido
    sendNTPpacket(timeServer);  // send an NTP packet to a time server
  }
  
  delay(1000); //aguarda um segundo, para receber os dados enviados.
  
  if ( Udp.parsePacket() ) {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read the packet into the buffer
  
    // the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  
    Serial.print("Segundos desde 1 de Jan. de 1900 = " );
    Serial.println(secsSince1900);     
  
    Serial.print("Unix time = ");
    const unsigned long seventyYears = 2208988800UL;      // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    unsigned long epoch = secsSince1900 - seventyYears;  //desconta 70 anos
    // print Unix time:
    Serial.println(epoch);         

    byte ano, mes, dia, dia_semana, hora, minuto, segundo;            
    localTime(&epoch, &segundo, &minuto, &hora, &dia, &dia_semana, &mes, &ano); //extrai data e hora do unix time
    
    Serial.print("Ano: ");
    Serial.println(ano+1900);
    Serial.print("Mes: ");
    Serial.println(mes+1);
    Serial.print("Dia da semana: ");
    Serial.println(dia_semana);
    Serial.print("Dia: ");
    Serial.println(dia);
    Serial.print("Hora: ");
    Serial.println(hora);
    Serial.print("minunto: ");
    Serial.println(minuto);
    Serial.print("segundo: ");
    Serial.println(segundo);
    
    String s = diaSemana(dia_semana) + ", " + zero(dia) + "/" + zero(mes+1) + "/" + (ano+1900) + " " + zero(hora) + ":" + zero(minuto) + ":" + zero(segundo);
    
    Serial.println(s);
    Serial.println(" ");
  }
  
  delay(10000); //atualiza novamente em 10 segundos
}



/**********************************************************************************
**************************************** FIM SETUP / LOOP *************************
**********************************************************************************/