Posts with «embedded devices» label

Wi-Fi Body Scale with Arduino

In this post we present the design of a scale that connects to the Internet and automatically sends weight info on a Google Document.

The project is composed of

 

Hardware

Taking a look at the diagram, we can distinguish three sections:

one for handling digital inputs (two buttons and scale’s switch),
the LCD manager
the analog signal acquisition from load cells


You may notice that P1 and P2 buttons are respectively managed by Arduino’s A3 and A4 inputs (configured as digital), while the INT switch reads the A5 signal (digital as well).

The LCD display used in our project belongs to the family of those based on HD44780 chipset, equipped with seven-pin control (RW, D4, D5, D6, D7, RS and Enable). As you can see from the diagram, RW is permanently connected to ground so it’s only operating in writing mode.

D4, D5, D6 and D7 pins are respectively managed by 3, 5, 6 and 7 digital pins of the Arduino Uno; RS is managed by pin 8 and the Enable pin from pin A0 (this configuration will also be specified in the software).

Besides the power supply (a VCC connected to 5V) and the ground (GND), the display requires a level of voltage between 0 and 5 volts to adjust the contrast in the input pin VO (adjustment made through R6 potentiometer).

Finally the display has 2 pin (A and K respectively anode and cathode) for switching on the backlight: feeding the pin with a voltage of 5V, the backlight is turned on, otherwise it is off.

The switching on and off is handled via a push-button switch that connects or disconnects the ground from the cathode.

Finally let’s analyze the part that manages the analog signal from the load cells: this is done by INA125 integrated component, a high precision amplifier developed specifically for measuring tools like scales.


The IC is fitted with two pins (6 and 7) representing the input of the differential amplification stage. These pins are connected to the two ends of the Wheatstone bridge (which in our project correspond to two of the load cell pins).

As you can figure out, the differential signal coming from the bridge has an absolute value of just a few millivolts: our project requires an amplification of about 500 times, obtained with a 120 ohm resistor.

The amplified output is provided at pins 10 and 11 of INA125; these pins are connected to A1 analog of the Arduino board, which therefore will be used for reading the value ADC.

R1: 39 ohm
R2: 1 kohm
R3: 4,7 kohm
R4: 4,7 kohm
R5: 330 ohm
R6: Trimmer 10 kohm
R7: 4,7 kohm

C1: 100 nF 63 VL
C2: 100 µF 25 VL

U1: INA125

P1: Microswitch
P2: Microswitch

LCD: Display LCD 8×2

 

Hacking  the Velleman scale

Our system is designed to be matched to the high-capacity scale produced by Velleman. But you can using any scale usign 4 load cells. The original Velleman electronics and display must be phased out and replaced with our project.

The scale structure is made up of 4 load cells (arranged on the 4 corners), which are configured between them so as to create a single Wheatstone bridge.

To make the connection to our board you must disassemble the lower section of the scale in order to access the electronics.

Referring to Fig A, which shows the structure of the scale viewed from below, with a quick visual analysis is easy to figure out that some blue and red wires are connected to each other while the yellow wires are connected to the switches positioned on the front of the two cells that identify the presence of a person.


To hack the scale follow these steps:


  • unsolder or cut all the red and blue wires, push in short those that were already shorted previously,

  • unsolder or cut the yellow wires coming from the cells numbered 1 and 3, put them in parallel (possibly by welding), extend them and take them to the two terminals on the new INT printed board (Fig.B)

  • unsolder or cut the white wire that is referred to as G3 (Wheatstone bridge mass) on the original printed circuit, extend take it to terminal 1 on the new printed circuit;

  • unsolder or cut the white wire that is referred to as G2 (Wheatstone bridge positive) on the original printed circuit, extend take it to terminal 3 on the new printed circuit;

  • unsolder or cut the white wire that is referred to as G1 and G4 on the original printed circuit, extend take it to terminal 4 and 2 on the new printed circuit (differential signal on the Wheatstone bridge)

 


The Sketch

As for the LCD, Arduino provides a convenient library (<LiquidCrystal.h>) already supporting different kinds of LCD (both 8 and 16 chars for 2 lines) based on the parallel interface chipset HD44780.

After the inclusion of the library, you must initialize the connection to the display, through LiquidCrystal LCDDisplay (8, A0, 3, 5, 6, 7), in this command, the parameters passed to the function and indicate Arduino’s hardware pins used to connect RS, Enable, D4, D5, D6 and D7 pins of the display.

Depending on the Arduino setup could be necessary to execute LCDDisplay.begin (width, height) in which the parameters indicate the physical dimensions of the display: LCDDisplay.begin (8, 2) in this case.

The library makes available instructions:

  • LCDDisplay.setCursor (x, y) to position the cursor in a certain position
  • LCDDisplay.print (String) to print strings


Management of Arduino’s EEPROM is done by the <EEPROM.h> library  that, once included, provides the functions:


  • EEPROM.write (add, date) to write a byte in a particular cell and

  • EEPROM.read (add) that the instead reads a byte from one cell (the add parameter specifies the address of the EEPROM cell).


Wi-Fi network and internet connection are managed thanks to the <WiServer.h> library; you just need to define some variables to configure the network (like IP’s and Network masks).


The adapter to connect and publish data on Google Documents shall operate as a Web Client: this configuration is done in the setup instruction WiServer.init (NULL) in which the NULL parameter specifies client mode.


You must create a function that will receive and handle the response from the server, this is done by the googlePublish.setReturnFunc  (Gestione_Risposte_Web) instruction  in our example. This function must be defined later in the code: in our example is void Gestione_Risposte_Web (char * data, int len) and receives as parameters both a pointer to a string containing the response and the length (in bytes) of the response.


Sending information requires to make a POST request to Google’s servers: WiServer library makes available a POSTrequest just to do this.


You must define the IP address of the server to which you want to connect (Google in our case) and define a structure of the POSTrequest (in our case, the variable is called googlePublish) containing the IP address of the server, the TCP / IP port the server name (spreadsheets.google.com), URL of POST execution and finally a function (SearchQuery in our case) that builds POST request body.

 

/******************************************************
 BilanciaWiFi
 Autori: Ingg. Tommaso Giusto e Ing. Alessandro Giusto
 Email:  tommro@libero.it
******************************************************/

// Inclusione Libreria per Display LCD 8x2
#include <LiquidCrystal.h>
// Inclusione Libreria per EEPROM scheda
#include <EEPROM.h>
// Inclusione Libreria per Server Web WiFi
#include <WiServer.h>
// Inclusione Libreria per SD Card
//#include <SD.h>

// Definizione pin INPUT/OUTPUT
const int PinVPeso = A1;         // Ingresso analogico uscita peso
const int PinPulsanteP1 = A3;    // Ingresso pulsante P1 su A3
const int PinPulsanteP2 = A4;    // Ingresso pulsante P2 su A4
const int PinInterruttore = A5;  // Ingresso interruttore su A5

// Definizione/Inizializzazione PIN Display LCD
// LCD RS pin D8
// LCD Enable on pin A0
// LCD D4, D5, D6, D7 on pins D3, D5, D6, D7
// LCD R/W pin a massa
// LCD V0 pin trimmer tra +5V e massa
LiquidCrystal LCDDisplay (8, A0, 3, 5, 6, 7);

/******************************************************
 Definizione struttura EEPROM
******************************************************/

/*****************************************************/
// Byte 0x000        Nome
// ...               Utente
// Byte 0x01F        000 (0x00 Carattere fine stringa)
// ...               
// ...               
// ...               
// Byte 0x120        Nome
// ...               Utente
// Byte 0x13F        009 (0x00 Carattere fine stringa)
/*****************************************************/
#define StartNomiUtentiEEPROMADD          0x0000
#define EndNomiUtentiEEPROMADD            0x013F
#define DimensioneNomeUtenteEEPROMADD     32
#define NumMaxNomiUtenti                  10

/*****************************************************/
// Byte 0x140        Parte Alta Peso Utente 000
// Byte 0x141        Parte Bassa Peso Utente 000
// ...               
// ...               
// ...               
// Byte 0x152        Parte Alta Peso Utente 009
// Byte 0x153        Parte Bassa Peso Utente 009
/*****************************************************/
#define StartPesiUtentiEEPROMADD          0x0140
#define EndPesiUtentiEEPROMADD            0x0153
#define DimensionePesoUtenteEEPROMADD     2

#define PesoMIN                           100
#define PesoMAX                           2000
#define AnalogDifferenzaPesoMAX           15

#define CalibrazioneSensoreMIN            0
#define CalibrazioneSensoreMAX            80

/******************************************************
 Definizione variabili globali
******************************************************/

// Definizione Parametri Rete Wireless
#define WIRELESS_MODE_INFRA	1  // Infrastrutturata (basata su Access Point)
#define WIRELESS_MODE_ADHOC	2  // Ad-hoc (senza Access Point)

// Parametri di rete
unsigned char local_ip[] = {192, 168, 0, 89};      // Indirizzo IP
unsigned char gateway_ip[] = {192, 168, 0, 254};	    // Indirizzo gateway IP
unsigned char subnet_mask[] = {255, 255, 255, 0};   // Subnet Mask
const prog_char ssid[] PROGMEM = {"FlashMob"};	    // SSID access point

// Selezione tipo di cifratura rete Wireless
unsigned char security_type = 0;  // 0 -> nessuna cifratura
                                  // 1 -> cifratura WEP
                                  // 2 -> cifratura WPA
                                  // 3 -> cifratura WPA2

// Password cifratura per WPA/WPA2 (max. 64 cratteri)
const prog_char security_passphrase[] PROGMEM = {"12345678"};

// Password cifratura per WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Selezione tipo di rete Wireless infrastrutturata
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

// Variabili per lunghezza SSID e password di cifratura
unsigned char ssid_len;
unsigned char security_passphrase_len;

// Definizione Parametri Pubblicazione Google
// Indirizzo IP per server www.google.it
uint8 google_ip[] = {209, 85, 229, 101};

// Richiesta POST verso GOOGLE
POSTrequest googlePublish (google_ip, 80, "spreadsheets.google.com", "", searchQuery);

// Stringa per eseguire pubblicazione
char newURL[] = {"/formResponse?formkey=dDFPcWhxNlZxMEpnUnhNdE5fT1lDcWc6MQ&ifq&entry.0.single=++++++++++++++++++++++++++++++++&entry.1.single=999,9&submit=Submit"};

// This function generates the body of our POST request
void searchQuery() {
}

// Indica presenza SD Card
//boolean presenzaSDCard;

// Inizializzazione Scheda
void setup() {
  // Inizializzo dimensioni LCD (8x2)
  LCDDisplay.begin (8, 2);

  // Inizializzo pin usati come INPUT/OUTPUT
  pinMode (PinInterruttore, INPUT);  
  pinMode (PinPulsanteP1, INPUT);
  pinMode (PinPulsanteP2, INPUT);

  // Se all'accensione rilevati tutti e 2 i pulsanti premuti
  if ((PulsantePremuto (PinPulsanteP1) == 1) &&
      (PulsantePremuto (PinPulsanteP2) == 1)) {
    // Segnalo inizializzazione in corso
    LCDDisplay.setCursor (0, 0);
    LCDDisplay.print ("Init EEP");
    LCDDisplay.setCursor (0, 1);
    LCDDisplay.print ("in corso");

    // Inizializzo EEPROM scheda
    InizializzaEEPROM();
    // Attesa
    delay (500);
  }
  // Inizializzo porta seriale
  Serial.begin (9600);  
  Serial.println ("Bilancia WiFi");
  Serial.println ("By Ingg. Tommaso e Alessandro Giusto");
  // Invio stato utenti
  InviaProgrammazioneUtenti();

  // Segnalo Avvio Web
  LCDDisplay.setCursor (0, 0);
  LCDDisplay.print ("  Init  ");
  LCDDisplay.setCursor (0, 1);
  LCDDisplay.print ("  web   ");  

  // Inizializzo WiServer
  WiServer.init (NULL);
  WiServer.enableVerboseMode (false);

  // Inizializzazione richiesta POST (parametro indica funzione a cui verra' passata la risposta)
  googlePublish.setReturnFunc (Gestione_Risposte_Web);    

/*
  // Inizializzo SD Card
  pinMode(10, OUTPUT);  
  presenzaSDCard = SD.begin (4);
  // Se inizializzazione SD fallita  
  if (presenzaSDCard == false)
    Serial.println ("Init SD FAULT!");
  // Se inizializzazione SD riuscita
  else
    Serial.println ("Init SD OK!");
*/
}

// Programma Principale
void loop() {
  // Ciclo infinito di esecuzione
  for (;;) {
    // Gestione Peso
    GestionePeso();

    // Per circa 1 sec
    for (byte tmp = 0; tmp < 250; tmp++) {
      // Gestione programmazione seriale
      GestioneSeriale();
      // Gestione WiServer
      GestioneWiServer();
      // Attesa
      delay (4);
    }    // Chiusura ciclo for per circa 1 sec
  }    // Chiusura ciclo infinito di esecuzione
}

/******************************************************
 Definizione funzioni
******************************************************/

// Funzione Gestione Peso
void GestionePeso() {
  // Indice utente selezionato
  //    0,..,(NumMaxNomiUtenti-1) -> selezionato utente 1,..,NumMaxNomiUtenti
  //    0xFF -> nessun utente selezionato
  static int IndiceUtenteSelezionato = 0xFF;
  // Indica l'indice carattere visualizzato  
  static int IndiceCarattere = 0;
  String NomeUtenteSelezionato;
  int PesoUtenteSelezionato;
  int LunghezzaNomeUtenteSelezionato;
  int ValoreSensorePeso1, ValoreSensorePeso2;
  int ValoreSensorePesoTMP1, ValoreSensorePesoTMP2, ValoreSensorePesoTMP3, ValoreSensorePesoTMP4;
  static int CalibrazioneSensore;
  int CalibrazioneSensoreTMP;
  int PesoCalcolato;
  int tmp;

  // Se non premuto interruttore (utente non salito)
  if (PulsantePremuto (PinInterruttore) == 0) {
    // Leggo valore sensore per calibrazione
    CalibrazioneSensoreTMP = analogRead (PinVPeso);
    // Se valore sensore per calibrazione valido
    if ((CalibrazioneSensoreTMP >= (int) (CalibrazioneSensoreMIN)) &&
      (CalibrazioneSensoreTMP <= (int) (CalibrazioneSensoreMAX)))
      // Aggiorno valore sensore per calibrazione
      CalibrazioneSensore = CalibrazioneSensoreTMP;
  }    // Chiusura if non premuto interruttore (utente non salito)

  // Se premuto tasto 1
  if (PulsantePremuto (PinPulsanteP1) == 1) {
    // Azzero indice carattere visualizzato
    IndiceCarattere = 0;

    // Verifico tutte le posizioni utente
    for (tmp = 0; tmp < NumMaxNomiUtenti; tmp++) {
      // Seleziono utente selezionato
      switch (IndiceUtenteSelezionato) {
        // Se selezionato ultimo utente/nessun utente selezionato
        case (NumMaxNomiUtenti - 1): case 0xFF:
          // Seleziono primo utente
          IndiceUtenteSelezionato = 0;
          break;    // Chiusura case selezionato ultimo utente/nessun utente selezionato

        // Se selezionato altro utente
        default:
          // Seleziono prossimo utente
          IndiceUtenteSelezionato++;
          break;    // Chiusura case nessun utente selezionato
      }    // Chiusura switch seleziono utente selezionato

      // Se trovato utente con nome non nullo
      if (LeggiNomeUtente (IndiceUtenteSelezionato).length() != 0x00)
        // Blocco ciclo for verifico tutte le posizioni utente
        break;
    }    // Chiusura ciclo for verifico tutte le posizioni utente

    // Se non trovato utente con nome non nullo
    if (tmp == NumMaxNomiUtenti)
      // Seleziono nessun utente
      IndiceUtenteSelezionato = 0xFF;
  }    // Chiusura if premuto tasto 1

  // Se utente selezionato
  if (IndiceUtenteSelezionato != 0xFF) {
    // Leggo nome/peso utente
    NomeUtenteSelezionato = LeggiNomeUtente (IndiceUtenteSelezionato);
    PesoUtenteSelezionato = LeggiPesoUtente (IndiceUtenteSelezionato);
    // Calcolo lunghezza nome utente    
    LunghezzaNomeUtenteSelezionato = NomeUtenteSelezionato.length();
    // Seleziono lunghezza nome utente
    switch (LunghezzaNomeUtenteSelezionato) {
      case 0:
        // Indico nessun utente selezionato
        IndiceUtenteSelezionato = 0xFF;
        break;
      case 1: case 2: case 3: case 4: case 5: case 6: case 7:
        LCDDisplay.clear();
        LCDDisplay.setCursor ((8 - LunghezzaNomeUtenteSelezionato) / 2, 0);
        LCDDisplay.print (NomeUtenteSelezionato);
        break;
      case 8:
        LCDDisplay.setCursor (0, 0);
        LCDDisplay.print (NomeUtenteSelezionato);
        break;
      default:
        if ((IndiceCarattere + 8) > LunghezzaNomeUtenteSelezionato)
          IndiceCarattere = 0;

        LCDDisplay.setCursor (0, 0);
        LCDDisplay.print (&NomeUtenteSelezionato[IndiceCarattere]);

        // Messaggio scorrevole
        IndiceCarattere++;
        if ((IndiceCarattere + 8) > LunghezzaNomeUtenteSelezionato)
          IndiceCarattere = 0;
        break;
    }    // Chiusura switch seleziono lunghezza nome utente
    LCDDisplay.setCursor (0, 1);
    LCDDisplay.print (PesoUtenteSelezionato / 1000);
    LCDDisplay.print ((PesoUtenteSelezionato % 1000) / 100);
    LCDDisplay.print ((PesoUtenteSelezionato % 100) / 10);
    LCDDisplay.print (".");
    LCDDisplay.print (PesoUtenteSelezionato % 10);    
    LCDDisplay.print (" Kg");

    // Se premuto interruttore (utente salito)
    if (PulsantePremuto (PinInterruttore) == 1) {
      LCDDisplay.setCursor (0, 1);
      LCDDisplay.print ("..... Kg");

      // Leggo valore analogico peso
      for (;;) {
        // Attesa
        delay (500);
        // Eseguo prima lettura peso
        ValoreSensorePesoTMP1 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP2 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP3 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP4 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePeso1 = ((ValoreSensorePesoTMP1 + ValoreSensorePesoTMP2 + ValoreSensorePesoTMP3 + ValoreSensorePesoTMP4) / 4);

        // Attesa
        delay (500);
        // Eseguo seconda lettura peso
        ValoreSensorePesoTMP1 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP2 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP3 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePesoTMP4 = analogRead (PinVPeso);
        delay (125);
        ValoreSensorePeso2 = ((ValoreSensorePesoTMP1 + ValoreSensorePesoTMP2 + ValoreSensorePesoTMP3 + ValoreSensorePesoTMP4) / 4);

        // Se peso stabilizzato
        if ((ValoreSensorePeso1 <= ValoreSensorePeso2) && ((ValoreSensorePeso2 - ValoreSensorePeso1) < (int) (AnalogDifferenzaPesoMAX)) ||
            (ValoreSensorePeso1 > ValoreSensorePeso2) && ((ValoreSensorePeso1 - ValoreSensorePeso2) < (int) (AnalogDifferenzaPesoMAX)))
          // Blocco ciclo for leggo valore analogico peso
          break;
      }    // Chiusura ciclo for leggo valore analogico peso

      // Calcolo peso utente
      PesoCalcolato = (int) (ValoreSensorePeso2 - CalibrazioneSensore);
      PesoCalcolato = (PesoCalcolato + (((int) (PesoCalcolato * (int) (10))) / (int) (62)));

//    68.1 KG
//    642   con calibrazione: 62 -> Veff = 580

      // Se peso valido
      if ((PesoCalcolato >= (int) (PesoMIN)) && (PesoCalcolato <= (int) (PesoMAX))) {
        // Memorizzo peso utente
        ScriviPesoUtente (IndiceUtenteSelezionato, PesoCalcolato);

        // Visualizzo peso calcolato
        LCDDisplay.setCursor (0, 1);
        LCDDisplay.print (PesoCalcolato / 1000);
        LCDDisplay.print ((PesoCalcolato % 1000) / 100);
        LCDDisplay.print ((PesoCalcolato % 100) / 10);
        LCDDisplay.print (".");
        LCDDisplay.print (PesoCalcolato % 10);    
        LCDDisplay.print (" Kg");

        // Richiedo pubblicazione        
        LCDDisplay.setCursor (0, 0);
        LCDDisplay.print ("Pubblic?");

        // Per massimo 5 secondi attendo pressione tasto 2
        for (tmp = 0; tmp < 10; tmp++) {
          // Se premuto tasto 2
          if (PulsantePremuto (PinPulsanteP2) == 1) {
            // Indico pubblicazione in corso     
            LCDDisplay.setCursor (0, 0);
            LCDDisplay.print ("Pubblic.");
            LCDDisplay.setCursor (0, 1);
            LCDDisplay.print ("  wait  ");

            // Eseguo pubblicazione
            for (tmp = 0; tmp < NomeUtenteSelezionato.length(); tmp++) {
              newURL[76 + tmp] = NomeUtenteSelezionato.charAt(tmp);
              if (newURL[76 + tmp] == ' ')
                newURL[76 + tmp] = '+';
            }
            newURL[124] = ((PesoCalcolato / 1000) + 0x30);
            newURL[125] = (((PesoCalcolato % 1000) / 100) + 0x30);      
            newURL[126] = (((PesoCalcolato % 100) / 10) + 0x30);      
            newURL[128] = ((PesoCalcolato % 10) + 0x30);      
            googlePublish.setURL(newURL);
            googlePublish.submit();    
            delay (500);
            // Blocco ciclo for
            break;
          }
          delay (500);          
        }    // Chiusura ciclo for per massimo 5 secondi attendo pressione tasto 2
/*
        // Se SD rilevata
        if (presenzaSDCard == true) {
          // Verifico/Creo directory BilanciaWiFi
          if (!(SD.exists ("BilanciaWiFi")))
            SD.mkdir ("BilanciaWiFi");

          // Memorizzo il peso su file
          File filePeso;
          // Apro il file in scrittura
          char nomeFilePeso[50] = {"BilanciaWiFi/"};
          for (tmp = 0; tmp < NomeUtenteSelezionato.length(); tmp++) {
            charTmp[0] = NomeUtenteSelezionato.charAt(tmp);
            strcat (nomeFilePeso, charTmp);
          }
          strcat (nomeFilePeso, ".txt");          
          filePeso = SD.open (nomeFilePeso, FILE_WRITE);

          // Se apertura file OK
          if (filePeso) {
            // Memorizzo il peso
            filePeso.print ((PesoCalcolato / 1000) + 0x30);
            filePeso.print (((PesoCalcolato % 1000) / 100) + 0x30);
            filePeso.print (((PesoCalcolato % 100) / 10) + 0x30);
            filePeso.print (".");
            filePeso.print ((PesoCalcolato % 10) + 0x30);
            filePeso.print (" Kg");
            // Chiudo il file:
            filePeso.close();
          }
        }
*/

        LCDDisplay.setCursor (0, 0);
        LCDDisplay.print ("  Step  ");
        LCDDisplay.setCursor (0, 1);
        LCDDisplay.print ("  off   ");

        // Attendo utente scende dalla bilancia
        for (;;) {
          // Se non premuto interruttore (utente non salito)
          if (PulsantePremuto (PinInterruttore) == 0)
            break;
        }
      }    // Chiusura if peso valido
    }    // Chiusura if premuto interruttore (utente salito)
  }    // Chiusura if utente selezionato

  // Se nessun utente selezionato
  else {
    LCDDisplay.setCursor (0, 0);
    LCDDisplay.print (" Chose  ");
    LCDDisplay.setCursor (0, 1);
    LCDDisplay.print (" user   ");
  }    // Chiusura if nessun utente selezionato
}

// Funzione Gestione Seriale
void GestioneSeriale() {
  String comandoRicevutoString = "";
  int numeroUtenteRicevuto;
  String nomeUtenteRicevuto = "";

  // Se ricevuti dati dalla porta seriale
  if (Serial.available()) {
    // Attendo tutti i dati
    delay (250);

    // Ricevo i dati
    while (Serial.available())
      comandoRicevutoString += (char) (Serial.read());

    // Invio comando ricevuto    
    Serial.println (comandoRicevutoString);

    // Se ricevuti almeno 15 caratteri
    if (comandoRicevutoString.length() >= 15) {
      // Se ricevuto comando programmazione nome utente (NOME_UTENTE_xx=)USER_NAME_01=Boris
      if ((comandoRicevutoString.substring (0, 12).equals("P_USER_NAME_")) &&
          (isdigit(comandoRicevutoString.charAt (12))) &&
          (isdigit(comandoRicevutoString.charAt (13)))) {
        // Estraggo numero utente ricevuto
        numeroUtenteRicevuto = (((comandoRicevutoString.charAt (12) - 0x30) * 10) +
                                (comandoRicevutoString.charAt (13) - 0x30));
        // Se ricevuto numero utente corretto
        if ((numeroUtenteRicevuto >= 1) && (numeroUtenteRicevuto <= NumMaxNomiUtenti)) {
          // Estraggo nome utente
          nomeUtenteRicevuto = comandoRicevutoString.substring (15);
          // Se nome troppo lungo
          if (nomeUtenteRicevuto.length() > DimensioneNomeUtenteEEPROMADD)
            // Tronco il nome
            nomeUtenteRicevuto = nomeUtenteRicevuto.substring (0, DimensioneNomeUtenteEEPROMADD);

          // Memorizzo il nome
          ScriviNomeUtente (numeroUtenteRicevuto - 1, nomeUtenteRicevuto);
          // Azzero il relativo peso
          AzzeraPesoUtente (numeroUtenteRicevuto - 1);
          // Indico OK
          Serial.println ("OK");
          // Invio su  porta seriale lo stato utenti
          InviaProgrammazioneUtenti();
          // Termino funzione
          return;
        }
      }
    }  

    // Indico errore
    Serial.println ("FAULT");
    // Termino funzione
    return;
  }
}

// Invia su  porta seriale lo stato utenti
void InviaProgrammazioneUtenti() {
  for (int numeroUtente = 0; numeroUtente < NumMaxNomiUtenti; numeroUtente++) {
    Serial.print ("Us. ");
    Serial.print ((numeroUtente + 1) / 10);
    Serial.print ((numeroUtente + 1) % 10);
    Serial.print (": ");
    Serial.println (LeggiNomeUtente (numeroUtente));
  }
}

// Funzione Gestione WiServer
void GestioneWiServer() {
  // Gestione WiServer
  WiServer.server_task();
}

// Gestione diverse risposte provenienti dal WEB
void Gestione_Risposte_Web (char* data, int len) {

  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  while (len-- > 0) {
    Serial.print(*(data++));
  } 

}

// Scrive il nome di un utente
// INPUT:   Posizione utente (0,..,9)
//          Nome utente in formato stringa
// OUTPUT:  -
// Note:    -
void ScriviNomeUtente (int NomePosition, String NomeUtente) {
  // Azzero nome utente selezionato
  AzzeraNomeUtente (NomePosition);

  // Scrivo i caratteri nome utente selezionato
  for (int tmp = 0; tmp < NomeUtente.length(); tmp++)
    EEPROM.write (StartNomiUtentiEEPROMADD + tmp +
                  (NomePosition * DimensioneNomeUtenteEEPROMADD), NomeUtente.charAt(tmp));
}

// Legge il nome di un utente
// INPUT:   Posizione utente (0,..,9)
// OUTPUT:  Nome utente in formato stringa
// Note:    -
String LeggiNomeUtente (int NomePosition) {
  String NomeUtente = "";
  char NomeUtenteChar;

  // Leggo i caratteri nome utente selezionato
  for (int tmp = 0; tmp < DimensioneNomeUtenteEEPROMADD; tmp++) {
    // Leggo singolo carattere
    NomeUtenteChar = EEPROM.read (StartNomiUtentiEEPROMADD + tmp +
                                  (NomePosition * DimensioneNomeUtenteEEPROMADD));

    // Se trovato carattere fine nome
    if (NomeUtenteChar == 0x00)
      // Blocco ciclo for leggo i caratteri nome utente selezionato
      break;

    // Accodo carattere letto
    NomeUtente = NomeUtente + NomeUtenteChar;
  }

  // Ritorno il nome
  return (NomeUtente);
}

// Azzera il nome di un utente
// INPUT:   Posizione utente (0,..,9)
// OUTPUT:  -
// Note:    -
void AzzeraNomeUtente (int NomePosition) {
  // Azzero caratteri nome utente selezionato
  for (int tmp = 0; tmp < DimensioneNomeUtenteEEPROMADD; tmp++)
    EEPROM.write (StartNomiUtentiEEPROMADD + tmp +
                  (NomePosition * DimensioneNomeUtenteEEPROMADD), 0); 
}

// Scrive il peso di un utente
// INPUT:   Posizione utente (0,..,9)
//          Peso utente
// OUTPUT:  -
// Note:    -
void ScriviPesoUtente (int PesoPosition, int PesoUtente) {
  // Memorizzo peso nome utente
  EEPROM.write (StartPesiUtentiEEPROMADD + 
                (PesoPosition * DimensionePesoUtenteEEPROMADD), (byte) (PesoUtente >> 8));
  EEPROM.write (StartPesiUtentiEEPROMADD + 1 +
                (PesoPosition * DimensionePesoUtenteEEPROMADD), (byte) (PesoUtente & 0x00FF));
}

// Legge il peso di un utente
// INPUT:   Posizione utente (0,..,9)
// OUTPUT:  Peso utente
// Note:    -
int LeggiPesoUtente (int PesoPosition) {
  // Ritorno il peso
  return (((int) (EEPROM.read (StartPesiUtentiEEPROMADD +
                               (PesoPosition * DimensionePesoUtenteEEPROMADD))) << 8) +
           (int) (EEPROM.read (StartPesiUtentiEEPROMADD + 1 +
                               (PesoPosition * DimensionePesoUtenteEEPROMADD))));
}

// Azzera il peso di un utente
// INPUT:   Posizione utente (0,..,9)
// OUTPUT:  -
// Note:    -
void AzzeraPesoUtente (int PesoPosition) {
  // Azzero peso nome utente
  ScriviPesoUtente (PesoPosition, 0);
}

// Inizializza EEPROM scheda
// INPUT:   -
// OUTPUT:  -
// Note:    -
void InizializzaEEPROM() {
  // Azzero i nomi/pesi di tutti gli utenti
  for (int tmp = 0; tmp < NumMaxNomiUtenti; tmp++) {
    AzzeraNomeUtente (tmp);
    AzzeraPesoUtente (tmp);
  }    
}

// Verifica lo stato di un pulsante
// INPUT:   Pin pulsante
// OUTPUT:  Stato pulsante    0 -> pulsante non premuto
//                            1 -> pulsante premuto
// Note:    -
int PulsantePremuto (int PinPulsante) {
  if (digitalRead (PinPulsante) == LOW)
    return (1);
  else
    return (0);
}

 

Install the WiShield libraries


To work properly, the Wifi shield requires specific libraries that must be installed in the Arduino IDE used to compile the sources so you’ll need to put these libraries in the Arduino libraries path.


The library supports multiple operating modes (APP_WEBSERVER, APP_WEBCLIENT, APP_SOCKAPP, APP_UDPAPP and APP_WISERVER).

The default value is APP_WEBSERVER, which runs on most Arduino systems but has several limitations. The main limitation is that it can’t function both as a client and server simultaneously.


It is therefore recommended the APP_WISERVER (in the library named “WiServer.h“) which allows the Arduino shield equipped with Wi-Fi to be configured and operated either as a Web Server as a Web Client.


In the first case, you can serve connection requests from external web clients and send HTML pages in response, in the second it will be possible to connect to a web server and send GET or POST requests.


To configure the WiShield library as APP_WISERVER you must open the apps-conf.h file, comment the “#define“ APP_WEBSERVER row and uncomment the “#define” of APP_WISERVER row.


Something like:


/ / # define APP_WEBSERVER

/ / # define APP_WEBCLIENT

/ / # define APP_SOCKAPP

/ / # define APP_UDPAPP

# defineAPP_WISERVER


Configuring publishing

Performing data publication on Google Documents requires three distinct steps:


  1. Configuring Wi-Fi network access;
  2. Creating a Google Docs form module: each module is characterized by an identifying 34 characters string – FormKey) and each field is characterized by an identification number (called Entry).
  3. Inserting the FormKey / Entry in the Arduino software.



Configuring network parameters

First you must configure and update the IP address, Subnet Mask, Gateway IP and Network SSID, then select the encryption mode and change password information for your network. Save all, compile and run the upload Software tab.

Creating the Google  module doc

Create a form on Google Docs, modify the form with two fields (username and weight, both of type string) and save the job. (the result is something like the one shown in Figure). In our case, we left the default file name and called the two fields “User Name” and “User weight”

take note of this key string because then it will be inserted in the Arduino software: as you can see from the picture, the link shows the form key assigned to the module (in this example, the link is: https://docs.google.com/spreadsheet/viewform?formkey=dDFPcWhxNlZxMEpnUnhNdE5fT1lDcWc6MQ which implies that the form assigned key is “dDFPcWhxNlZxMEpnUnhNdE5fT1lDcWc6MQ”);

 

Clicking on the link will open a new page that shows the data entry form: within this form text fields are marked with “entry.0.single“, “entry.1.single“, etc … (basically with an integer id)

 To see which number has been assigned to our fields you need to display the HTML source of the form (the result is something like the one shown in this Figure).

You can easily find the ID numbers assigned to different fields (in our example “entry.0.single” is the “Name” and “entry.1.single” is the “weight“).

Take note of this information because it will be included in the source Arduino as well.

Formkey / entry

Once you have created the form, the Arduino source will be configured so that it is compatible with the form you created.

A variable is defined in Arduino source named newURL[]: the variable is initialized with a standard format then modified to perform publication (refer to Figure 11 to identify it in the code).


Replace the default values with those obtained at the time of the creation of the form, compile and download it to the Arduino board.

 

 

 

How to program user names

The configuration of user names can be made via serial port and Serial Monitor. To program it, connect to the board (via USB cable) and open the Arduino Serial Monitor. As a first step the card sends a summary of the current configuration.


To program a new user name you must send a string in the format “P_USER_NAME_xx = User Name” with xx between 01 and 10 ID (put an empty string to delete the selected user.) If all the posted information is correct, this is confirmed by the message “Ok” otherwise “Fault”.

 

Using the scale


The scale software is able to distinguish up to 10 users (each identified by its name) and, for each one, it stores the last measured weight.


If you want to clear the memory (which we recommend at first use) is sufficient to hold down either of the two buttons (the display indicates the operation with “EEP init in progress”).

Later, you can configure names following the procedure described in the “Programming user names” section.


As the next step the Web management interface will start and the system will enter its normal operation. The user selection is done by pressing button P1.


Going over the scale starts the weighing procedure (lasting several seconds): weight is displayed and stored and the scale asks for publishing on the web: by pressing P2 the operation is performed.

Arduino ISP (In System Programming) and stand-alone circuits

We use an Arduino to program other ATmega without bootloader . This technique allows you to use all flash memory for code and make boards using new ATmega, cheaper than those with bootloader.

The qualities that have made the success of Arduino are undoubtedly the open-source software, many libraries, a good hardware and a virtually infinite Reference that explains each possible use of the platform.

But if we use Arduino for a specific use, we can integrate it into a specific circuit and program the micro in a way that performs a single firmware. We may so remove the bootloader and leave to the firmware the entire program memory.

The ATmega328 has 32 Kbytes of flash, that when the chip is mounted on Arduino are not all available, as a portion is reserved to the bootloader, the purpose of which is to communicate with the IDE Arduino to load programs (sketch) to be performed. The same bootloader, on each power on or reset of Arduino, verifies the presence of a sketch in flash memory and executes it. The bootloader occupies a space of 512 bytes, in the case of Arduino UNO.

Well, in a stand-alone application the bootloader no longer needed.

The configuration of the micro ATmega328P needs, in addition to the power (+5 VDC to pins 7 and 20, GND to pins 8 and 22), a 16-MHz crystal between pins 9 and 10, two 22 pF ceramic capacitors from between these pins and GND, a 10 k Ω resistor between pin 1 and +5 VDC for pull-up the reset line.

 

Programming ATMEGA in stand-alone

Anyone knows that it is necessary program Arduino uploading a sketch via USB, using the software called IDE and the operation is quite simple.

We can see a screenshot of the IDE with an Arduino sketch loaded and UNO during the receipt of the sketch (notice the yellow LED on).

The technique will test allows the use of a board Arduino as ISP Programmer.

We start with the list of required materials:

•               Arduino UNO / Duemilanove (will be used as a programmer);

•               ATmega328P chip (chip to be programmed);

•               Breadboard and jumper;

•               a crystal of 16 MHz, two ceramic capacitors from 22 pF, a resistance of 10 K Ω 1/4 W, a resistance of 560 Ω 1/4 W LED 3 or 5 mm;

•               seven male-male jumper wires.

A resistance of 120 Ω 1/4 of watts, and an electrolytic capacitor or tantalum from 10 uF 10 ÷ 16 volts.


Now we prepare our target circuit and first of all insert the chip on the Breadboard, these are the connections to make:

•               through the jumper to be Breadboard connect pins 7 and 20 of the chip to the positive supply line (+5 volts);

•               in the same way we connect the pins 8 and 22 of the chip to the ground line supply (GND);

•               connect pin 1 of the chip to the +5 V line through the resistor of 10 k Ω;

•               insert the crystal to the pins 9 and 10 of the chip;

•               insert the two 22 pF ceramic capacitors; both must have a leg connected to GND, while the other will serve to connect a capacitor to pin 9 and the other to pin 10 of the chip;

•               insert one end of resistor 560 Ω at the pin 19 and the other end into an empty spot on the breadboard, and to this end we connect the anode LED(the longer pin) , whose other end (cathode) goes to GND;

 

At this point we can connect to the Arduino Breadboard using jumper cables under the following matches:

•               Arduino pin 10 goes to pin 1 of the chip;

•               Arduino pin 11 goes to pin 17 of the chip;

•               pin 12 of Arduino is connected to pin 18 of the chip;

•               pin 13 to Arduino pin 19 goes on the chip;

•               the +5 V pins of Arduino goes to the positive supply line of the breadboard;

•               any of the three GND pin of Arduino goes to the ground line of the breadboard.

 

Now look the software to reveal the “trick” that sends a sketch, using the IDE, to the chip on the Breadboard, bypassing Arduino that will play the role of Programmer ISP.

What we need to do is create a virtual board, starting from the original (corresponding to the model we are using Arduino) and making some simple but essential changes. We must first locate the file that is boards.txt containing all information relating to the various boards that the IDE shows us when we execute the command Tools->Board. Typically this file is located in the folder of the IDE software, the path X: \ mypath \ arduino-xxx \ hardware \ arduino, where X is the letter that indicates the logical drive and myPath the folder or location containing the program (xxx indicates the version of the program).

Now open the file with Notepad and see a long series of lines arranged in groups separated by a line consisting of a repetition of the symbol ”#”,each group representing a different board. The lines are identified by the initial code, the same for all, but different for the board, the name that will appear in the submenu Tools->Board is inserted in the first row in the group.

The code is represented by the word “uno” which is at the beginning of each line.

The line containing the word “name” (usually the first) is followed by “=” and then the name that the board will have in the IDE.

Other information that concern us are:

uno.upload.maximum_size = 32256: Sets the maximum capacity of flash memory that we can use in practice from 32 Kbytes of Flash which has the total ATmega328P we must subtract the space occupied by the bootloader, for the Arduino UNO is 512 byte;

uno.bootloader.low_fuses = 0xffuno.bootloader.high_fuses = 0xdeuno.bootloader.extended_fuses = 0×05; these three lines are the “fuse”, are used to set the behavior of the chip and are expressed with hexadecimal values;

uno.build.f_cpu = 16000000L: This line must correspond to the clock frequency for which the chip has been set, by means of the fused, expressed in Hz, 1 Hz 6,000,000 correspond to 16 MHz, precisely the frequency of the quartz or, more precisely, the present external oscillator to Arduino UNO; this value is used as a reference for timing controls of the software, such as delay () and millis ().

 

And now we create our own virtual board, writing these lines of code:

 

atmsa16.name=ATmega in Stand Alone (w/ Arduino as ISP)
atmsa16.upload.protocol=stk500
atmsa16.upload.maximum_size=32768
atmsa16.upload.speed=115200
atmsa16.upload.using=arduino:arduinoisp
atmsa16.bootloader.low_fuses=0xff
atmsa16.bootloader.high_fuses=0xdf
atmsa16.bootloader.extended_fuses=0x05
#### atmsa16.bootloader.extended_fuses=0x07
atmsa16.bootloader.path=optiboot
atmsa16.bootloader.file=optiboot_atmega328.hex
atmsa16.bootloader.unlock_bits=0x3F
atmsa16.bootloader.lock_bits=0x0F
atmsa16.build.mcu=atmega328p
atmsa16.build.f_cpu=16000000L
atmsa16.build.core=arduino

 

Following the approach of the file will separate this group of lines to those of other boards, inserting a line of ”#”.The end result should be:

We note that are varied: the code (atmsa16 instead of uno), the maximum_size (brought to its maximum capabilities of Flash, since we do not reserve space for the bootloader), then there a new line (atmsa16.upload.using = arduino: arduinoisp) that allows us to understand the IDE that will program the chip in stand-alone and not on the Arduino. Another new line is preceded by some “# # # #” that disables it, the reason is easily explained: the extended_fuses is set to 0×05, and in some special cases, during the transfer of the sketch could be an error bound the setting of this value.As we shall see later, simply change the following two lines of code:

 <em># # # # Atmsa16.bootloader.extended_fuses = 0x05</em>
<em>atmsa16.bootloader.extended_fuses = 0x0</em>7

thus activating the value 0×07 instead of 0×05, it will work out. Of course, this change should not be made before, but only if you get the error.

 

Program the micro

At this point we are ready for the final step: send our sketches to the chip mounted on the breadboard and then will test the operation separating it from Arduino.


To read the new board in the file, the IDE must be restarted, so if this program was open, when editing the file boards.txt must close it and restart it. To verify that our modification is successful, it is sufficient now run the command Tools->Board and check if there is now our “stand-alone” board, otherwise we should close the IDE and check the file boards.txt, because certainly we made ​​a mistake.

The technique used to send the sketch to the chip in stand-alone mode is very simple: First select the Arduino board that we are using as a programmer (eg Arduino Duemilanove or UNO) , just as we do for normal use of Arduino. Then select the Arduino serial port (the COM for Windows users) and recall from the IDE the sketch ArduinoISP, execute this command by clicking the Upload button on the IDE. After several seconds of the three flashing LEDs and Arduino to the breadboard of course (at the moment is physically connected to pin 13 of Arduino that, as we know, check out one of the three LEDs on the board) on the IDE will come the message “done uploading “.

Arduino is ready to play the role of Programmer ISP, select, now, our board IDE “ATmega Stand Alone (w / Arduino as ISP)“, without changing the COM.

We load the sketch “blink” and execute it again by clicking the Upload button on the IDE: LEDs and Arduino breadboard flash again, this time for a much shorter period, after which the IDE will show the message again “Done uploading”.

So our ATmega328P chip was programmed without having to physically fit on Arduino and now lives its own life. It is then ready to be mounted in the circuit which it is intended.

Of course, the chip can be reprogrammed at will with any kind of sketch.

 

Troubleshooting

At this point we have to solve three types of problem that may occur when we send the sketch to the chip stand-alone. The problems of’extended_fuses and of autoreset may occur on either Arduino Duemilanove or Arduino UNO, without that you can establish a certain rule.We must also emphasize that the remedies that will illustrate to 100% solve the problems, but must be applied only if the problem occurs.

We start from the situation that may occur if we use a blank chip, the Atmel set the fuse to make the chip work at 1 MHz with the internal oscillator. If we send a sketch directly, happens that the chip in stand-alone ignores the external crystal and times will be staggered: for example, the LED blink with the sketch will last about 16 seconds instead of 1 second. Simply, we set the fuse, the operation can be done easily by loading the bootloader on the chip before sending the sketch.

Before explaining this simple maneuver quickly clarify two points: the bootloader is sent once a chip virgin and will only serve to set the fuse, then it will become useless and the sketch overwrite it, if we had to first load the sketch, noticing the error, and then load the bootloader, no problem: the chip is set and we just have to resubmit the sketch. The simple steps that are going to describe will return very useful for cases where we wanted to prepare a blank chip to work directly on Arduino; is a good idea to have in the house a spare chip with bootloader of our board, so if you were unfortunately damaged the original, a simple substitution solves this problem immediately.

Here are the steps to follow:

•               prepare and connect the Breadboard Arduino as discussed previously;

•               We open the IDE and select the model we are using Arduino and port to which it is connected;

•               upload the sketch ArduinoISP to Arduino;

•               now execute the command Tools->Burn Bootloader w / Arduino as ISP;

•               After about a minute we loaded into the stand-alone chip the bootloader of Arduino boards (you may have noticed that in the IDE we’ve set our Arduino board).

 

As mentioned, the chip can be quickly mounted to receive the Arduino sketch, or leave it on the breadboard and repeat/execute the operation of sending the sketch stand-alone, this time the Blink will work perfectly.

Of course, other errors may occur, do not worry, keep reading this section and of course everything will be resolved.

So let the problem of ’extended_fuses: the rows of our virtual board we expected a double value for this cast, because it can happen (even though it is quite rare) that some boards do not succeed in this program merged with the value 0×05. During the upload of the sketch on the chip with stand-alone mode, the IDE will display an error message (written in red on a black background) that will indicate the need to use the value 0×07, if it appears that in practice warning means that we must close the IDE, open the file boards.txt and activate the relevant line, simultaneously disabling the other (with 0×05), as explained above. At this point we can repeat the test. We clarify that if the error occurs on a given board will always occur on this board, so the variation of the files should be done only once and permanently.

And now we see the problem, more frequent, about autoreset. When the serial chip (FT232RL on Duemilanove or ATmega8U2 of UNO) receives a signal from the USB port, sends the reset pulse to ATmega328, who then prepares itself to receive Data. This operation corresponds to the one you make every time you press the button “RESET” on the Arduino.

If the data do not arrive or if the reset was made manually, the sketches in flash memory chip ATmega328 is executed. When Arduino is used as ISP Programmer can happen that, if the autoreset is sent too early, the upload operation fails. In this case the IDE returns the following error: ”avrdude:stk500_getsync (): not in sync: resp = 0×15“.

The problem is solved by blocking the Autoreset. The 120 ohm resistance must be connected between the RESET pin of Arduino and +5 V, while the 10µF capacitor is connected with the positive pole to the RESET of Arduino and negative to GND.

With a jumper cable connect on Breadboard the RESET signal of Arduino.

The methods described should be used only if absolutely necessary.

Important note: the need to connect these components only when needed, is dictated by the fact that to load a sketch on the Arduino should autoreset, otherwise the upload will fail and we will get the error avrdude: stk500_getsync (): not in sync: resp = 0×00 – avrdude: stk500_disable (): protocol error, expect = 0×14, resp = 0×51, so if you see this error, know that you just have to “liberate” the pin “RESET” Arduino from the link with the Anti- autoreset.

[Thanks to Michele Menniti]

Arduino RFID shield

This shield could be used as a stand-alone transponder key, or with Google’s servers to create a cloud-computing application.

 

It’s time to present you an application with RFID. We want to show you how to use the popular Arduino to produce a device capable of recognizing passive transponder (TAG). But this is not the usual RFID key, because the system can activate a relay if a recognised TAG is read, but also we took the opportunity to make an application that use cloud-computing. The basic version, which is a simple key relay consists of an Arduino (Duemilanove or UNO) and the RFID shield based on a ID-12 of Innovations: placing a transponder already learned, the relay is activated.
The extended version of our project uses an Arduino, the RFID Shield and the Ethernet Shield with which we can access the Internet and stored, using the Google Docs service, the transponder data.

The RFID shield
But before you see the applications in detail, we spend some words on the shield for Arduino that we need to capture data of passive TAG. It is a very simple circuit based on the form ID-12 , which contains a complete recognizer of passive transponders, in addition to a relay controlled by Arduino and a few other passive components. The buzzer, which allows you to set an audible alert, could be controlled by ID-12 or by Arduino.

The relay is powered by Vin Arduino (and the corresponding contact of the shield) and GND. The base of the transistor that controls RL1 is driven by the pin 9 of the Arduino. The lines 6 and 8 control the lighting of the LEDs.
In our case, the pin 7 of ID-12 is connected to ground, so the chip will only recognize ASCII coded tag and return its output in ASCII characters.

The component has a TTL level serial interface, accessible from it’s pins 9 and 8, then there is an output (pin 10) that pulses rapidly (at a frequency of 3 kHz) every time the module detects the code of a tag encoded and used to drive a buzzer or a light emitting diode.
All data are read from Arduino using the library NewsoftSerial that allows to emulate a serial port; in our case, the emulation is carried on lines 7.

How it works

Once you put power to the system, when the module ID-12 reads a tag, the pin 10 pulse at 3 kHz and the Arduino read s data; then microcontroller compares the code with those who has in memory.
If the transponder is one of those already learned the micro actives the relay and the green led. This relay will be used to control an electric lock, a gate, etc..
In bistable mode, the relay changes state each time the ID-12 reads a valid tag.
Clearly, the circuit can work well if in his memory there is at least a RFID tag.

To learn the code for a tag and then write it to EEPROM, you must press and hold button P1 for 3 seconds (max. 5), once that is done you have to pass a card and wait for the confirmation sound (given by buzzer) and light (provided by the green LED).
At any time you can remove a tag code from memory: must press the P1 button for 5 seconds or longer, until the red LED lights on. At this point you release the button and pass the tag to be deleted, if the LED turns off and on again, the card has been deleted.
To erase the entire EEPROM you must restart the Arduino, and during the reboot, hold down the button P1 for about one second; when the red LED lights up. Done this, Arduino is ready to read new tags.

R1: 330 ohm
R2: 330 ohm
R3: 4,7 kohm
R4: 10 kohm

LD1: Led 3 mm green
LD2: Led 3 mm red

BZ1: Buzzer

T1: BC547

RFID1: ID-12

RL1: Relé 12V

P1: Microswitch 90°

D1: 1N4007

Varie:
- Screw 3 poli
- Jumper (2 pz.)
- Strip male 3 via (2 pz.)
- Strip M/F 6 via (2 pz.)
- Strip M/F 8 via (2 pz.)


/* RFID shield key

 created 2011
 by Andrea Fainozzi

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

#include <EEPROM.h>
#include <NewSoftSerial.h>

#define PULSANTE   5               //pin relativo al pulsante da premere per entrare in modalità scrittura/cancellazione

#define DATA_PIN       7           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (7 | 
#define RELE_PIN       9           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (9 | 10)
#define BUZZ_PIN       3           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (3 | 11)
#define GREEN_LED_PIN  8           //pin relativo al led verde
#define RED_LED_PIN    6           //pin relativo al led rosso

//scegliere cosa fare quando viene letta una scheda

#define RELE     0                 //scegliere '1' per fare in modo che alla lettura di una scheda il relè venga attivato '0' per non fare nulla
#define BUZZER   1                 //scegliere '1' per fare in modo che alla lettura di una scheda il buzzer emetta un suono '0' per non fare nulla
#define LED      1                 //scegliere '1' per fare in modo che alla lettura di una scheda corretta venga acceso il led verde e per una scheda incorretta il led rosso '0' per non fare nulla

#define DURATA_RELE 1000          //scegliere il tempo per il quale deve rimanere acceso il relè (se viene inserito '0' il relè funzionerà in modo bistabile)

boolean check;                    //variabile con la quale eseguo tutti i controlli all'interno dello sketch
int on_off=0;                     //variabile che utilizzo per controllare lo stato del led in modalità bistabile

NewSoftSerial mySerial(DATA_PIN,1);    //inizializzo il pin sul quale leggere i dati trasmessi dall'ID-12
void setup() {

  if(DURATA_RELE>60000)                                                    //controllo che il tempo impostato per la durata di attivazione del relè sia inferiore a 1 minuto
    while(1){                                                              //in caso contrario stampo su seriale un messaggio di errore in un ciclo infinito
        delay(2000);
        Serial.print("Tempo relè non valido, troppo alto");
    }

  pinMode(PULSANTE,INPUT);                                                 //imposto il pin del pulsante in modalità input per verificare quando il pulsante viene premuto
  digitalWrite(PULSANTE,HIGH);                                             //e lo setto alto, in modo tale da attivare la resistenza di pull-up

  if(RELE)                                                                 //controllo se è stato scelto di attivare o meno il relè, nel primo caso, imposto il pin assegnatogli come output
    pinMode(RELE_PIN,OUTPUT);
  if(BUZZER)                                                               //controllo se è stato scelto di attivare o meno il buzzer, nel primo caso, imposto il pin assegnatogli come output
    pinMode(BUZZ_PIN,OUTPUT);
  if(LED){                                                                 //controllo se è stato scelto di attivare o meno i led, nel primo caso, imposto i pin assegnatogli come output
    pinMode(GREEN_LED_PIN,OUTPUT);
    pinMode(RED_LED_PIN,OUTPUT);
  }
  Serial.begin(9600);                                                      //Inizializzo la porta seriale sulla frequenza di 9600 baud
  mySerial.begin(9600);                                                    //inizializzo la seriale sulla quale leggo i dati delle schede a 9600 baud

  if(digitalRead(PULSANTE)==LOW) azzera();                                 //controllo che il il pulsante sia premuto in fase di accensione del dispositivo, in caso affermativo azzero tutta la memoria EEPROM
}

void loop () {

  byte val;                                                          //variabile che utilizzo per leggere i valori dalla tessera appena passata
  byte code[6];                                                      //vettore nel quale salvo il codice letto completo
  byte checksum;                                                     //variabile sulla quale calcolo e salvo il checksum
  byte bytesread;                                                    //variabile che viene utilizzata per per contare quanti byte sono stati letti
  byte tempbyte;                                                     //variabile che mi serve per memorizzare temporaneamente mezzo byte letto

  unsigned long int tempo=0;                                         //variabile che utilizzo per salvare il tempo attuale, per contare i millisecondi passati
  boolean scrivere=false;                                            //variabile che utilizzo per controllare se la tessera appena letta è da salvare o da controllare
  boolean controllo=false;                                           //variabile che utilizzo per controllare se la tessera appena letta è da cancellare oppure no

  if(digitalRead(PULSANTE)==LOW){                                    //controllo se il pulsante è premuto
     tempo=millis();                                                 //se lo è salvo gli attuali millisecondi passati dall'avvio del dispositivo
     while((digitalRead(PULSANTE)==LOW)&&(tempo+3000>millis()));     //quindi mando in esecuzione un ciclo che non fa nulla
     if(millis()>tempo+2999){                                        //controllo dopo la fine del ciclo se esso è stato in esecuzione per 3 secondi, confrontando il tempo iniziale + 3000 con il tempo attuale
       if(LED)
         digitalWrite(GREEN_LED_PIN,HIGH);                           //se così è, accendo il led verde
         Serial.println("Modalità registrazione");                   //e stampo sulla seriale che sono entrato in modalità registrazione
       if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //e faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
       }
         scrivere=true;                                              //e pongo a vero la variabile scrivere
     }
     if(digitalRead(PULSANTE)==LOW){                                 //se dopo ciò il pulsante è ancora premuto
       while((digitalRead(PULSANTE)==LOW)&&(tempo+5000>millis()));   //mando in esecuzione un altro ciclo nullo
       if(millis()>tempo+4999){                                      //se esso è stato in esecuzione per 2 secondi significa che sono entrato in modalita eliminazione
         Serial.println("Modalità eliminazione");                    //quindi lo scrivo sulla seriale
        if(LED){
         digitalWrite(RED_LED_PIN,HIGH);                             //accendo il led rosso
         digitalWrite(GREEN_LED_PIN,LOW);                            //spengo quello verde, precedentemente acceso
        }
        if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
        }
         while(digitalRead(PULSANTE)==LOW);                          //mando in esecuzione un ciclo finchè il pulsante non viene rilasciato
         controllo=true;                                             //e pongo a vero la variabile controllo
       }
     }
  }

//-------------------------------------------------------------------------------------inizio do-while------------------------------------------------------------------------------------------

  do{                                                                //inizio un ciclo che finirà solo quando verrà premuto nuovamente il pulsante

   val = 0;
   checksum = 0;                                                     //azzero le variabili precedentemente dichiarate
   bytesread = 0;
   tempbyte = 0;

  if(mySerial.available() > 0) {                                     //controllo se sulla mia seriale è presente qualche dato
    if((val = mySerial.read()) == 2) {                               //se così è leggo da essa il valore
      bytesread = 0;                                                 //e se è uguale a 2 (carattere di controllo) pongo a 0 la variabile bytesread
      while (bytesread < 12) {                                       //mando in esecuzione un ciclo per 12 volte, in modo da poter leggere tutti i 12 caratteri della tessera (5 byte del codice + 1 del cehcksum
      if( mySerial.available() > 0) {                                //controllo se i dati sono disponibili ad essere letti
          val = mySerial.read();                                     //quindi assegno a 'val' il valore dell'i-esimo carattere
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {     //se leggo un carattere 'header' o un carattere di stop
            break;                                                             // fermo la lettura
          }

          if ((val >= '0') && (val <= '9')) {
            val -= '0';
          }                                                                    //traduco in esadecimale il carattere appena letto
          else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          //ogni 2 caratteri letti, aggiungo il byte così creato al vettore 'code'

          if (bytesread & 1 == 1) {                                            //se ho letto un solo carattere fin'ora
            code[bytesread >> 1] = (val | (tempbyte << 4));                        //assegno alla seconda parte del byte in posizione bytesread-esima il valore esadecimale del carattere letto

            if (bytesread >> 1 != 5) {                                             //se ho letto l'ultimo byte della scheda calcolo il checksum
              checksum ^= code[bytesread >> 1];                                    //facendo la XOR sull'ultimo byte letto
            };
          } else {
            tempbyte = val;                                                    //altrimenti assegno il valore letto alla variabile tempbyte
          };

          bytesread++;                                                        //mi preparo a leggere il prossimo byte
        }
      }

     if (bytesread == 12) {                                                   //se ho letto tutti i 6 byte
        (code[5]==checksum) ? check = true : check = false ;                  //controllo che il checksum sia corretto
        if(check){                                                            //se lo è passo a controllare se devo salvare o cancellare
            check=false;                                                      //rimetto a false la variabile check per successivi utilizzi
            if(scrivere&&!controllo){                                         //controllo se devo scrivere
                  for(int i=0;i<1021;i+=5){                                   //in caso affermativo eseguo un ciclo che controlla tutta la EEPROM
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            check=true;                                        //se trovo il codice della tessera letta già salvato nella EEPROM metto a true la variabile 'check'
                            break;                                             //ed esco dal ciclo
                        }
                  }
                  if(check){                                                   //quindi controllo il valore della variabile check, se è vero, significa che la tessera è già stata registrata
                        Serial.print("Tessera già registrata!");               //quindi lo comunico su seriale
                        stampa_code(code);
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                        delay(50);
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        delay(50);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                      if(LED)
                        digitalWrite(RED_LED_PIN,LOW);
                  }

                  else{                                                        //se la tessera non è stata trovata
                      check=false;                                             //rimetto a false la variabile check per successivi utilizzi
                      for(int i=0;i<1021;i+=5){                                //quindi eseguo un ciclo che controlla tutta la EEPROM in cerca di 5 byte successivi liberi
                        if((EEPROM.read(i)==0xff)&&(EEPROM.read(i+1)==0xff)&&(EEPROM.read(i+2)==0xff)&&(EEPROM.read(i+3)==0xff)&&(EEPROM.read(i+4)==0xff)){
                          for(int j=i;j<i+5;j++)                               //una volta trovati, partendo dal primo, fino al quinto, ci salvo il valore della tessera
                              EEPROM.write(j,code[j-i]);                             //eseguendo un ciclo 5 volte
                          check=true;                                                //pongo a true la variabile check
                          break;                                               //ed esco dal ciclo
                        }
                      }
                      if(check){                                               //se la variabile check è vera, significa che ho salvato con successo, quindi
                          Serial.print("Tessera Salvata");                     //lo stampo su seriale
                          stampa_code(code);
                        if(BUZZER){
                          analogWrite(BUZZ_PIN,50);
                          delay(100);
                          digitalWrite(BUZZ_PIN,LOW);
                        }
                        if(LED){
                          for(int i=0;i<5;i++){
                           digitalWrite(GREEN_LED_PIN,HIGH);                   //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           delay(50);
                           digitalWrite(GREEN_LED_PIN,LOW);
                           delay(50);
                          }
                          digitalWrite(GREEN_LED_PIN,HIGH);
                        }
                      }
                      else{                                                    //se la variabile check non è vera, significa che ho controllato tutta la memoria senza trovare 5 byte sequenziali liberi
                           Serial.println("Memoria piena");                    //quindi spamo su seriale che la memoria è piena
                           for(int i=0;i<5;i++){
                           if(LED)
                             digitalWrite(RED_LED_PIN,HIGH);
                           if(BUZZER)
                             analogWrite(BUZZ_PIN,50);
                           delay(50);                                          //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           if(LED)
                             digitalWrite(RED_LED_PIN,LOW);
                           if(BUZZER)
                             digitalWrite(BUZZ_PIN,LOW);
                           delay(50);
                          }
                    }
                }
            }
            else if(scrivere&&controllo){                                      //se non bisogna salvare, controllo se bisogna eliminare una tessera
                  int posizione=-1;                                            //quindi inizializzo a -1 la variabile posizione, che mi servirà per salvare la posizione nella EEPROM della tessera
                  for(int i=0;i<1021;i+=5){                                    //ed eseguo un ciclo che controlla tutta la EEPROM per cercare il codice corrispondente
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            posizione=i;                                       //se viene trovato salvo la posizione del primo byte nella variabile posizione
                        break;                                                 //ed esco dal ciclo
                        }
                  }
                  if(posizione!=-1){                                           //quindi controllo che la variabile posizione sia diversa da -1 così da sapere se è stato trovato o meno il codice
                      for(int j=posizione;j<posizione+5;j++)                   //eseguo quindi un ciclo partendo dalla posizione 'posizione' nella EEPROM
                              EEPROM.write(j,0xff);                            //sovrascrivendo i 5 byte corrispondenti alla tessera, con il byte di default '0xff'
                      Serial.print("Scheda cancellata");                       //una volta fatto ciò, stampo su seriale l'avvenuta cancellazione
                      stampa_code(code);
                      if(LED){
                        digitalWrite(GREEN_LED_PIN,HIGH);
                        digitalWrite(RED_LED_PIN,HIGH);
                      }
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                      delay(250);
                      if(LED)
                        digitalWrite(GREEN_LED_PIN,LOW);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                  }
                  else{                                                        //se la variabile posizione vale -1 significa che non ha trovato in memoria la tessera letta
                      Serial.print("Impossibile cancellare la scheda, non è salvata");  //quindi lo comunico su seriale
                      stampa_code(code);
                      for(int x=0;x<10;x++){
                        if(LED)
                          digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER)
                          analogWrite(BUZZ_PIN,50);
                        delay(25);                                             //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        if(LED)
                          digitalWrite(RED_LED_PIN,LOW);
                        if(BUZZER)
                          digitalWrite(BUZZ_PIN,LOW);
                        delay(25);
                      }
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                    }

            }

            check=true;                                                        //rimetto a vero il valore della variabile check siccome il checksum è corretto
            }
            else{                                                              //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
                 if(LED)
                    digitalWrite(RED_LED_PIN,HIGH);
            }

     }
    }
  }
  }
  while((digitalRead(PULSANTE)==HIGH)&&(controllo||scrivere));

//-------------------------------------------------------------------------------------------fine do-while---------------------------------------------------------------------------------------

  if(LED){
    digitalWrite(GREEN_LED_PIN,LOW);                                          //spengo gli eventuali led accesi per conoscere la modalità nella quale ero all'interno del ciclo
    digitalWrite(RED_LED_PIN,LOW);
  }

  if (bytesread == 12) {                                                      //controllo di avere letto tutti i 6 byte della tessera
     if(check){                                                               //controllo che il checksum sia corretto
           if(!scrivere){                                                     //e controllo anche che non ci sia da salvare/scrivere una tessera
                  check=false;                                                //rimetto a false la variabile check per successivi utilizzi
                  for(int i=0;i<1021;i+=5)                                    //eseguo un ciclo che controlla tutta la EEPROM alla ricerca della tessera letta
                        if(EEPROM.read(i)==code[0]&&EEPROM.read(i+1)==code[1]&&EEPROM.read(i+2)==code[2]&&EEPROM.read(i+3)==code[3]&&EEPROM.read(i+4)==code[4]){
                            check=true;                                       //se viene trovata metto a true la variabile check
                            break;                                            //ed esco dal ciclo
                        }

                     if(check){                                               //quindi controllo il valore della variabile check
                       Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                    }
                      else{                                                    //se al contrario il valore è falso
                        Serial.print("Tessera non valida!");                   //significa che ho controllato tutta la memoria senza trovare la tessera, quindi lo comunico su seriale
                        stampa_code(code);
                        if(LED)
                            digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);                        //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                            delay(50);
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);
                        }
                     }
                    }
                    if(LED){
                      delay(500);
                      digitalWrite(GREEN_LED_PIN,LOW);                         //spegno gli eventuali led rimasti accesi
                      digitalWrite(RED_LED_PIN,LOW);
                    }
     }
     else{                                                                     //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
     }
    }
  bytesread=0;                                                                 //azzero la variabile bytesread per una prossima lettura
}

//--------------------------------------------------------------------------FUNZIONE PER AZZERARE LA MEMORIA EEPROM------------------------------------------------------------------------------

void azzera(){
  if(LED){
    digitalWrite(GREEN_LED_PIN,HIGH);
    digitalWrite(RED_LED_PIN,HIGH);
  }
  for(int i=0;i<1023;i++)
      EEPROM.write(i,0xff);
  Serial.println("Memoria Azzerata!");
  if(BUZZER)
    analogWrite(BUZZ_PIN,50);
  for(int i=0;i<5;i++)
    if(LED){
      digitalWrite(GREEN_LED_PIN,HIGH);
      delay(100);
      digitalWrite(GREEN_LED_PIN,LOW);
      digitalWrite(RED_LED_PIN,HIGH);
      delay(100);
      digitalWrite(RED_LED_PIN,LOW);
    }
  if(BUZZER)
    digitalWrite(BUZZ_PIN,LOW);
}

//--------------------------------------------------------------FUNZIONE PER STAMPARE IL CODICE DELLA TESSERA LETTA SU SERIALE-------------------------------------------------------------------

void stampa_code(byte * code){
        Serial.print(": <");
        for (int i=0; i<5; i++) {
          if (code[i] < 16) Serial.print("0");
          Serial.print(code[i], HEX);
          if(i!=4)
            Serial.print(" ");
        }
        Serial.println(">");
}

 

 

Send data to Google

Our system may be facing a network and on the web to secure the cooperation of the Google Docs service. It only works if we add an Ethernet Shield.
Our online application proposes to use a Google Spreadsheet document (spreadsheet on Google Docs, anyway …) in which Arduino transcribe the codes read from valid cards. The only condition for accessing the service has to be registered, or have a Google account (eg Gmail), if you have not, open it: it is free and gives you the opportunity to have a mail box and many other free services offered by Google.
In practice, our system does not directly access to the spreadsheet, but sends the data using a form (form). We write a post to explain how to connect Arduino to Google Docs. All the results of a module is imported in the corresponding sheet, from which can be viewed by authorized users, or by anyone in possession of the link, if we remove the protection.


/* RFID shield Google

 created 2011
 by Andrea Fainozzi

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

#include <EEPROM.h>
#include <NewSoftSerial.h>
#include <Ethernet.h>
#include <SPI.h>
#include <Client.h>

char formkey[] = "dDh11222222233333333344444444MQ"; //Chiave identificatrice del documento di google (SOSTITUIRE CON LA PROPRIA CHIAVE PRESA DIRETTAMENTE DALL'URL DI GOOGLE SPREADSHEET)
byte mac[] = { 0x90,0xA2,0xDA,0x00,0x55,0xA3};         //Mac addres della scheda ethernet dell'arduino (SOSTITUIRE CON IL MAC ADDRESS RIPORTATO SULLA SHIELD ETHERNET)
byte ip[] = { 192,168,0,99};                           //IP da assegnare alla scheda ethernet dell'arduino (SOSTITUIRE CON UNO SUPPORTATO DALLA PROPRIA RETE)
byte subnet[] = { 255,255,255,0};                      //Maschera di sottorete riferita alla propria connessione (SOSTITUIRE CON LA PROPRIA SUBNET MASK)
byte gateway[] = { 192,168,0,254};                     //Gateway del proprio modem/router (SOSTITUIRE CON IL PROPRIO GATEWAY PREDEFINITO)
byte server[] = { 209,85,229,101 };                    //IP del server di google spreadsheet

Client client(server, 80);                             //connettiamo il nostro arduino, come client al server di google spreadsheet

char buffer [33];                                      //vettore nel quale salvo temporaneamente vari caratteri che mi serviranno per leggere totalmente le tessere
char codice[13];                                       //stringa nella quale andremo a salvare il codice letto dalla tessera

#define PULSANTE   5               //pin relativo al pulsante da premere per entrare in modalità scrittura/cancellazione

#define DATA_PIN       7           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (7 | 
#define RELE_PIN       9           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (9 | 10)
#define BUZZ_PIN       3           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (3 | 11)
#define GREEN_LED_PIN  8           //pin relativo al led verde
#define RED_LED_PIN    6           //pin relativo al led rosso

//scegliere cosa fare quando viene letta una scheda

#define RELE     1                 //scegliere '1' per fare in modo che alla lettura di una scheda il relè venga attivato '0' per non fare nulla
#define BUZZER   1                 //scegliere '1' per fare in modo che alla lettura di una scheda il buzzer emetta un suono '0' per non fare nulla
#define LED      1                 //scegliere '1' per fare in modo che alla lettura di una scheda corretta venga acceso il led verde e per una scheda incorretta il led rosso '0' per non fare nulla
#define EEPROM_ON_OFF 1            //scegliere '1'(consigliato) per fare in modo che alla lettura di una tessera, il programma controlli che essa sia registrata per essere valida, '0' per fare in modo che una qualsiasi tessera con checksum valido sia considerata valida

#define DURATA_RELE 1000          //scegliere il tempo per il quale deve rimanere acceso il relè (se viene inserito '0' il relè funzionerà in modo bistabile)

boolean check;                    //variabile con la quale eseguo tutti i controlli all'interno dello sketch
int on_off=0;                     //variabile che utilizzo per controllare lo stato del led in modalità bistabile

NewSoftSerial mySerial(DATA_PIN,1);    //inizializzo il pin sul quale leggere i dati trasmessi dall'ID-12
void setup() {

  Serial.begin(9600);
  Ethernet.begin(mac, ip , gateway , subnet);

  if(DURATA_RELE>60000)                                                    //controllo che il tempo impostato per la durata di attivazione del relè sia inferiore a 1 minuto
    while(1){                                                              //in caso contrario stampo su seriale un messaggio di errore in un ciclo infinito
        delay(2000);
        Serial.print("Tempo relè non valido, troppo alto");
    }

  pinMode(PULSANTE,INPUT);                                                 //imposto il pin del pulsante in modalità input per verificare quando il pulsante viene premuto
  digitalWrite(PULSANTE,HIGH);                                             //e lo setto alto, in modo tale da attivare la resistenza di pull-up

  if(RELE)                                                                 //controllo se è stato scelto di attivare o meno il relè, nel primo caso, imposto il pin assegnatogli come output
    pinMode(RELE_PIN,OUTPUT);
  if(BUZZER)                                                               //controllo se è stato scelto di attivare o meno il buzzer, nel primo caso, imposto il pin assegnatogli come output
    pinMode(BUZZ_PIN,OUTPUT);
  if(LED){                                                                 //controllo se è stato scelto di attivare o meno i led, nel primo caso, imposto i pin assegnatogli come output
    pinMode(GREEN_LED_PIN,OUTPUT);
    pinMode(RED_LED_PIN,OUTPUT);
  }
  Serial.begin(9600);                                                      //Inizializzo la porta seriale sulla frequenza di 9600 baud
  mySerial.begin(9600);                                                    //inizializzo la seriale sulla quale leggo i dati delle schede a 9600 baud

  if(digitalRead(PULSANTE)==LOW) azzera();                                 //controllo che il il pulsante sia premuto in fase di accensione del dispositivo, in caso affermativo azzero tutta la memoria EEPROM
}

void loop () {

  byte val;                                                          //variabile che utilizzo per leggere i valori dalla tessera appena passata
  byte code[6];                                                      //vettore nel quale salvo il codice letto completo
  byte checksum;                                                     //variabile sulla quale calcolo e salvo il checksum
  byte bytesread;                                                    //variabile che viene utilizzata per per contare quanti byte sono stati letti
  byte tempbyte;                                                     //variabile che mi serve per memorizzare temporaneamente mezzo byte letto

  unsigned long int tempo=0;                                         //variabile che utilizzo per salvare il tempo attuale, per contare i millisecondi passati
  boolean scrivere=false;                                            //variabile che utilizzo per controllare se la tessera appena letta è da salvare o da controllare
  boolean controllo=false;                                           //variabile che utilizzo per controllare se la tessera appena letta è da cancellare oppure no
 if(EEPROM_ON_OFF){
  if(digitalRead(PULSANTE)==LOW){                                    //controllo se il pulsante è premuto
     tempo=millis();                                                 //se lo è salvo gli attuali millisecondi passati dall'avvio del dispositivo
     while((digitalRead(PULSANTE)==LOW)&&(tempo+3000>millis()));     //quindi mando in esecuzione un ciclo che non fa nulla
     if(millis()>tempo+2999){                                        //controllo dopo la fine del ciclo se esso è stato in esecuzione per 3 secondi, confrontando il tempo iniziale + 3000 con il tempo attuale
       if(LED)
         digitalWrite(GREEN_LED_PIN,HIGH);                           //se così è, accendo il led verde
         Serial.println("Modalità registrazione");                   //e stampo sulla seriale che sono entrato in modalità registrazione
       if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //e faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
       }
         scrivere=true;                                              //e pongo a vero la variabile scrivere
     }
     if(digitalRead(PULSANTE)==LOW){                                 //se dopo ciò il pulsante è ancora premuto
       while((digitalRead(PULSANTE)==LOW)&&(tempo+5000>millis()));   //mando in esecuzione un altro ciclo nullo
       if(millis()>tempo+4999){                                      //se esso è stato in esecuzione per 2 secondi significa che sono entrato in modalita eliminazione
         Serial.println("Modalità eliminazione");                    //quindi lo scrivo sulla seriale
        if(LED){
         digitalWrite(RED_LED_PIN,HIGH);                             //accendo il led rosso
         digitalWrite(GREEN_LED_PIN,LOW);                            //spengo quello verde, precedentemente acceso
        }
        if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
        }
         while(digitalRead(PULSANTE)==LOW);                          //mando in esecuzione un ciclo finchè il pulsante non viene rilasciato
         controllo=true;                                             //e pongo a vero la variabile controllo
       }
     }
  }
 }

//-------------------------------------------------------------------------------------inizio do-while------------------------------------------------------------------------------------------

  do{                                                                //inizio un ciclo che finirà solo quando verrà premuto nuovamente il pulsante

   val = 0;
   checksum = 0;                                                     //azzero le variabili precedentemente dichiarate
   bytesread = 0;
   tempbyte = 0;

  if(mySerial.available() > 0) {                                     //controllo se sulla mia seriale è presente qualche dato
    if((val = mySerial.read()) == 2) {                               //se così è leggo da essa il valore
      bytesread = 0;                                                 //e se è uguale a 2 (carattere di controllo) pongo a 0 la variabile bytesread
      while (bytesread < 12) {                                       //mando in esecuzione un ciclo per 12 volte, in modo da poter leggere tutti i 12 caratteri della tessera (5 byte del codice + 1 del cehcksum
      if( mySerial.available() > 0) {                                //controllo se i dati sono disponibili ad essere letti
          val = mySerial.read();                                     //quindi assegno a 'val' il valore dell'i-esimo carattere
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {     //se leggo un carattere 'header' o un carattere di stop
            break;                                                             // fermo la lettura
          }

          if ((val >= '0') && (val <= '9')) {
            val -= '0';
          }                                                                    //traduco in esadecimale il carattere appena letto
          else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          //ogni 2 caratteri letti, aggiungo il byte così creato al vettore 'code'

          if (bytesread & 1 == 1) {                                            //se ho letto un solo carattere fin'ora
            code[bytesread >> 1] = (val | (tempbyte << 4));                        //assegno alla seconda parte del byte in posizione bytesread-esima il valore esadecimale del carattere letto

            if (bytesread >> 1 != 5) {                                             //se ho letto l'ultimo byte della scheda calcolo il checksum
              checksum ^= code[bytesread >> 1];                                    //facendo la XOR sull'ultimo byte letto
            };
          } else {
            tempbyte = val;                                                    //altrimenti assegno il valore letto alla variabile tempbyte
          };

          bytesread++;                                                        //mi preparo a leggere il prossimo byte
        }
      }

     if (bytesread == 12) {                                                   //se ho letto tutti i 6 byte
        (code[5]==checksum) ? check = true : check = false ;                  //controllo che il checksum sia corretto
      if(EEPROM_ON_OFF){                                                      //se è stato scelto di untilizzare la EEPROM
        if(check){                                                            //e il checksum è corretto, passo a controllare se devo salvare o cancellare
            check=false;                                                      //rimetto a false la variabile check per successivi utilizzi
            if(scrivere&&!controllo){                                         //controllo se devo scrivere
                  for(int i=0;i<1021;i+=5){                                   //in caso affermativo eseguo un ciclo che controlla tutta la EEPROM
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            check=true;                                        //se trovo il codice della tessera letta già salvato nella EEPROM metto a true la variabile 'check'
                            break;                                             //ed esco dal ciclo
                        }
                  }
                  if(check){                                                   //quindi controllo il valore della variabile check, se è vero, significa che la tessera è già stata registrata
                        Serial.print("Tessera già registrata!");               //quindi lo comunico su seriale
                        stampa_code(code);
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                        delay(50);
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        delay(50);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                      if(LED)
                        digitalWrite(RED_LED_PIN,LOW);
                  }

                  else{                                                        //se la tessera non è stata trovata
                      check=false;                                             //rimetto a false la variabile check per successivi utilizzi
                      for(int i=0;i<1021;i+=5){                                //quindi eseguo un ciclo che controlla tutta la EEPROM in cerca di 5 byte successivi liberi
                        if((EEPROM.read(i)==0xff)&&(EEPROM.read(i+1)==0xff)&&(EEPROM.read(i+2)==0xff)&&(EEPROM.read(i+3)==0xff)&&(EEPROM.read(i+4)==0xff)){
                          for(int j=i;j<i+5;j++)                               //una volta trovati, partendo dal primo, fino al quinto, ci salvo il valore della tessera
                              EEPROM.write(j,code[j-i]);                             //eseguendo un ciclo 5 volte
                          check=true;                                                //pongo a true la variabile check
                          break;                                               //ed esco dal ciclo
                        }
                      }
                      if(check){                                               //se la variabile check è vera, significa che ho salvato con successo, quindi
                          Serial.print("Tessera Salvata");                     //lo stampo su seriale
                          stampa_code(code);
                        if(BUZZER){
                          analogWrite(BUZZ_PIN,50);
                          delay(100);
                          digitalWrite(BUZZ_PIN,LOW);
                        }
                        if(LED){
                          for(int i=0;i<5;i++){
                           digitalWrite(GREEN_LED_PIN,HIGH);                   //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           delay(50);
                           digitalWrite(GREEN_LED_PIN,LOW);
                           delay(50);
                          }
                          digitalWrite(GREEN_LED_PIN,HIGH);
                        }
                      }
                      else{                                                    //se la variabile check non è vera, significa che ho controllato tutta la memoria senza trovare 5 byte sequenziali liberi
                           Serial.println("Memoria piena");                    //quindi spamo su seriale che la memoria è piena
                           for(int i=0;i<5;i++){
                           if(LED)
                             digitalWrite(RED_LED_PIN,HIGH);
                           if(BUZZER)
                             analogWrite(BUZZ_PIN,50);
                           delay(50);                                          //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           if(LED)
                             digitalWrite(RED_LED_PIN,LOW);
                           if(BUZZER)
                             digitalWrite(BUZZ_PIN,LOW);
                           delay(50);
                          }
                    }
                }
            }
            else if(scrivere&&controllo){                                      //se non bisogna salvare, controllo se bisogna eliminare una tessera
                  int posizione=-1;                                            //quindi inizializzo a -1 la variabile posizione, che mi servirà per salvare la posizione nella EEPROM della tessera
                  for(int i=0;i<1021;i+=5){                                    //ed eseguo un ciclo che controlla tutta la EEPROM per cercare il codice corrispondente
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            posizione=i;                                       //se viene trovato salvo la posizione del primo byte nella variabile posizione
                        break;                                                 //ed esco dal ciclo
                        }
                  }
                  if(posizione!=-1){                                           //quindi controllo che la variabile posizione sia diversa da -1 così da sapere se è stato trovato o meno il codice
                      for(int j=posizione;j<posizione+5;j++)                   //eseguo quindi un ciclo partendo dalla posizione 'posizione' nella EEPROM
                              EEPROM.write(j,0xff);                            //sovrascrivendo i 5 byte corrispondenti alla tessera, con il byte di default '0xff'
                      Serial.print("Scheda cancellata");                       //una volta fatto ciò, stampo su seriale l'avvenuta cancellazione
                      stampa_code(code);
                      if(LED){
                        digitalWrite(GREEN_LED_PIN,HIGH);
                        digitalWrite(RED_LED_PIN,HIGH);
                      }
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                      delay(250);
                      if(LED)
                        digitalWrite(GREEN_LED_PIN,LOW);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                  }
                  else{                                                        //se la variabile posizione vale -1 significa che non ha trovato in memoria la tessera letta
                      Serial.print("Impossibile cancellare la scheda, non è salvata");  //quindi lo comunico su seriale
                      stampa_code(code);
                      for(int x=0;x<10;x++){
                        if(LED)
                          digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER)
                          analogWrite(BUZZ_PIN,50);
                        delay(25);                                             //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        if(LED)
                          digitalWrite(RED_LED_PIN,LOW);
                        if(BUZZER)
                          digitalWrite(BUZZ_PIN,LOW);
                        delay(25);
                      }
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                    }

            }

            check=true;                                                        //rimetto a vero il valore della variabile check siccome il checksum è corretto
            }

            else{                                                              //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
                 if(LED)
                    digitalWrite(RED_LED_PIN,HIGH);
            }

     }
     }
    }
  }
  }
  while((digitalRead(PULSANTE)==HIGH)&&(controllo||scrivere));

//-------------------------------------------------------------------------------------------fine do-while---------------------------------------------------------------------------------------

  if(LED){
    digitalWrite(GREEN_LED_PIN,LOW);                                          //spengo gli eventuali led accesi per conoscere la modalità nella quale ero all'interno del ciclo
    digitalWrite(RED_LED_PIN,LOW);
  }

  if (bytesread == 12) {                                                      //controllo di avere letto tutti i 6 byte della tessera
     if(check&&EEPROM_ON_OFF){                                                //controllo che il checksum sia corretto e che è stato scelto di utilizzare la EEPROM
           if(!scrivere){                                                     //e controllo anche che non ci sia da salvare/scrivere una tessera
                  check=false;                                                //rimetto a false la variabile check per successivi utilizzi
                  for(int i=0;i<1021;i+=5)                                    //eseguo un ciclo che controlla tutta la EEPROM alla ricerca della tessera letta
                        if(EEPROM.read(i)==code[0]&&EEPROM.read(i+1)==code[1]&&EEPROM.read(i+2)==code[2]&&EEPROM.read(i+3)==code[3]&&EEPROM.read(i+4)==code[4]){
                            check=true;                                       //se viene trovata metto a true la variabile check
                            break;                                            //ed esco dal ciclo
                        }

                     if(check){                                               //quindi controllo il valore della variabile check
                       Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       stampa_codice(code,codice);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                      google_send("entry.0.single",codice);
                    }
                      else{                                                    //se al contrario il valore è falso
                        Serial.print("Tessera non valida!");                   //significa che ho controllato tutta la memoria senza trovare la tessera, quindi lo comunico su seriale
                        stampa_code(code);
                        if(LED)
                            digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);                        //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                            delay(50);
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);
                        }
                     }
                    }
                    if(LED){
                      delay(500);
                      digitalWrite(GREEN_LED_PIN,LOW);                         //spegno gli eventuali led rimasti accesi
                      digitalWrite(RED_LED_PIN,LOW);
                    }
     }   

     else if(check&&!EEPROM_ON_OFF){
                             Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       stampa_codice(code,codice);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                      google_send("entry.0.single",codice);
     }

     else if(!check){                                                                     //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
     }
    }
  bytesread=0;                                                                 //azzero la variabile bytesread per una prossima lettura
}

//--------------------------------------------------------------------------FUNZIONE PER AZZERARE LA MEMORIA EEPROM------------------------------------------------------------------------------

void azzera(){
  if(LED){
    digitalWrite(GREEN_LED_PIN,HIGH);
    digitalWrite(RED_LED_PIN,HIGH);
  }
  for(int i=0;i<1023;i++)
      EEPROM.write(i,0xff);
  Serial.println("Memoria Azzerata!");
  if(BUZZER)
    analogWrite(BUZZ_PIN,50);
  for(int i=0;i<5;i++)
    if(LED){
      digitalWrite(GREEN_LED_PIN,HIGH);
      delay(100);
      digitalWrite(GREEN_LED_PIN,LOW);
      digitalWrite(RED_LED_PIN,HIGH);
      delay(100);
      digitalWrite(RED_LED_PIN,LOW);
    }
  if(BUZZER)
    digitalWrite(BUZZ_PIN,LOW);
}

//--------------------------------------------------------------FUNZIONE PER STAMPARE IL CODICE DELLA TESSERA LETTA SU SERIALE-------------------------------------------------------------------

void stampa_code(byte * code){
        Serial.print(": <");
        for (int i=0; i<5; i++) {
          if (code[i] < 16) Serial.print("0");
          Serial.print(code[i], HEX);
          if(i!=4)
            Serial.print(" ");
        }
        Serial.println(">");
}

//------------------------------------------------------------FUNZIONE PER INVIARE A GOOGLE SPREADSHEET IL VALORE DELLA TESSERA LETTA------------------------------------------------------------

void google_send(char *entry,char *val){

  char *submit = "&submit=Submit";
  if (client.connect()) {
    client.print("POST /formResponse?formkey=");
    client.print(formkey);
    client.println("&ifq HTTP/1.1");
    client.println("Host: spreadsheets.google.com");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.print("Content-Length: ");
    client.println(strlen(entry)+1+strlen(val)+strlen(submit),DEC);
    client.println();
    client.print(entry);
    client.print("=");
    client.print(val);
    client.print(submit);
    client.println();
  }
  delay(1000);
  client.stop();
}

//-----------------------------------------------------------FUNZIONE PER CONVERTIRE DA BYTE A CARATTERE IL VALORE DELLA TESSERA LETTA-----------------------------------------------------------

void stampa_codice(byte * code,char * codice){
   char tmp[3];
   codice[0]='\0';
   for(int i=0;i<5;i++){
   sprintf(tmp, "%02X", code[i]);
   strncat(codice,tmp,2);
   }
}

 

 

[Thanks to Andrea Fainozzi]

MMA7455L Three Axis Digital Output Accelerometer

 

 

This module integrates the sensor MMA7455L (produced by Freescale), able to detect the movement on three axes, and then in every direction. The chip offers the possibility to select three different sensitivity (± 2g, ± 4g, ± 8g) and makes available, on an SPI bus and the I ² C-Bus, the data detected by allowing a more easily read by a microcontroller. There are also two programmable interrupt lines to communicate a certain event, or to perform one or more actions when it detects a certain acceleration or when the module is stopped.

The accelerometer connections are carried out on a male strip pitch 2.54 mm, seven contacts, which allows the insertion in any dip socket, female strip or directly on the printed circuit. The module, powered with a DC voltage of 2.5 to 3.6 V, is suitable for be used in all systems that require the detection of movement, acceleration, such as an alarm systems for vehicle, laboratory analytical instruments, electrical equipment, machinery test and robots.

The module has extremely compact dimensions (10x18x3, 6mm).

Before using this module is necessary to establish (through jumper J1) which must be the voltage applied to pin VIO (Digital Power for I/O pads), levels of the I / O interface must be the same of micro. If the voltage applied between the pin + and – of the module is the same as the interface device is necessary to close J1, while if it is different (for example because the micro operates at 5V) the jumper must be open and the line VIO must be connects to the same supply voltage of the microcontroller. The I ² C-Bus module is assigned to 00111011. For more information on the chip MMA7455L consult the datasheet from the Internet site www.freescale.com.

To show the operation of the module I made a little demo with Arduino.

The connection to the microcontroller is very simple and the pin-out allows you to insert the module in the 6-pin for the analog inputs.
The low absorption permit to use the input pin A0 as level of communicationis (VIO) brought it to a high logic level (5V), while the pin A1 is set to 0, the mass for the MMA7455L.
The main supply voltage is provide from 3.3 V by Arduino.

Thanks to the library Wire.h pin A4 and A5 are used to communicate directly with the module.
The communication is very simple thank the library MMA_7455.h developed by Moritz Kemper.

// Example which uses the MMA_7455 library
// Moritz Kemper, IAD Physical Computing Lab
// moritz.kemper@zhdk.ch
// ZHdK, 20/11/2011

//Modified by Boris Landoni
//www.open-electronics.org

#include <Wire.h> //Include the Wire library
#include <MMA_7455.h> //Include the MMA_7455 library

const int vcc =  A0;
const int gnd =  A1; 

MMA_7455 mySensor = MMA_7455(); //Make an instance of MMA_7455

char xVal, yVal, zVal; //Variables for the values from the sensor
float x, y, z;

void setup()
{
  pinMode(gnd, OUTPUT);
  pinMode(vcc, OUTPUT);
  digitalWrite(gnd, LOW);
  digitalWrite(vcc, HIGH);
  delay (1000);

  Serial.begin(9600);
  Serial.println("start");

  // Set the sensitivity you want to use
  // 2 = 2g, 4 = 4g, 8 = 8g
  mySensor.initSensitivity(8);
  // Calibrate the Offset, that values corespond in
  // flat position to: xVal = -30, yVal = -20, zVal = +20
  // !!!Activate this after having the first values read out!!!
  mySensor.calibrateOffset(0, 0, 0);

}

void loop()
{
  long start = micros();
  //xVal = mySensor.readAxis('x'); //Read out the 'x' Axis
  //yVal = mySensor.readAxis('y'); //Read out the 'y' Axis
  //zVal = mySensor.readAxis('z'); //Read out the 'z' Axis
 /* Serial.print("x: ");
  Serial.print(xVal*0.016, 2);
  Serial.print("\t y: ");
  Serial.print(yVal*0.016, 2);
  Serial.print("\t z: ");
  Serial.println(zVal*0.016, 2);

  Serial.print("x: ");
  Serial.print(xVal,DEC);
  Serial.print("\t y: ");
  Serial.print(yVal,DEC);
  Serial.print("\t z: ");
  Serial.print(zVal,DEC);
  Serial.print("\t summ: ");
  Serial.println((abs(xVal)+abs(yVal)+abs(zVal)),DEC);*/
    if (Serial.available() > 0) {
    int inByte = Serial.read();
      if (inByte==0x01){
        Serial.print( average(5,'x')); //Serial.print( "\t" );
        Serial.print( average(5,'y')); //Serial.print( "\t" );
        Serial.print( average(5,'z')); //Serial.print( "\t" );
      }
    //Serial.print( micros() - start ); Serial.println();
  }
}

char average(int num, char axis){
  long tot=0;
  char val;
  for (int i=1; i<=num; i++){
    val=mySensor.readAxis(axis);
    tot += val;
   //Serial.print( val,DEC );Serial.print( " " );
   delay(2);
  }
  val=tot/num;
  //Serial.println( val );
  return(val);

}

 

The software written in Processing By IAN allows you to immediately verify the correct operation of Freescale chip. A cube will rotate like the movements of the sensor.
The applications of this sensor are different and I will show you just developed.

//This example reads in a single byte value from 0 to 255 and graphs it.

/////////////////////////////////////////
//Basic serial communication code
//by Chang Soo Lee
//ITP, NYU
//Created 11/27/2005
/////////////////////////////////////////

//Modified by Boris Landoni
//www.open-electronics.org

import processing.serial.*;
Serial myPort;
int serial = 1;
byte s8=1, x8=0, y8=0, z8=0, cnt=0;
PFont font;
int numH = 370;  

// This will contain the pixels used to calculate the fire effect
int[][] fire;

// Flame colors
color[] palette;
float angle;
int[] calc1,calc2,calc3,calc4,calc5;

PGraphics pg;

void setup () {
    size(1500, 1000, P2D);

  // Create buffered image for 3d cube
  pg = createGraphics(width, height, P3D);

  calc1 = new int[width];
  calc3 = new int[width];
  calc4 = new int[width];
  calc2 = new int[height];
  calc5 = new int[height];

    colorMode(HSB);

  fire = new int[width][height];
  palette = new color[255];

  // Generate the palette
  for(int x = 0; x < palette.length; x++) {
    //Hue goes from 0 to 85: red to yellow
    //Saturation is always the maximum: 255
    //Lightness is 0..255 for x=0..128, and 255 for x=128..255
    palette[x] = color(x/3, 255, constrain(x*3, 0, 255));

  }

  // Precalculate which pixel values to add during animation loop
  // this speeds up the effect by 10fps
  for (int x = 0; x < width; x++) {
    calc1[x] = x % width;
    calc3[x] = (x - 1 + width) % width;
    calc4[x] = (x + 1) % width;
  }

  for(int y = 0; y < height; y++) {
    calc2[y] = (y + 1) % height;
    calc5[y] = (y + 2) % height;
  }

  //size(270, 440);
  println(Serial.list());
  myPort = new Serial(this, Serial.list()[15], 9600);
  // Load the font. Fonts must be placed within the data
  // directory of your sketch. Use Tools > Create Font
  // to create a distributable bitmap font.
  // For vector fonts, use the createFont() function.
  hint(ENABLE_NATIVE_FONTS);
  //font = loadFont("ArialMT-48.vlw");
  smooth();
    myPort.write(0x01);

}

void draw () {
  if (myPort.available() > 0) {
    serial = (myPort.read());
    s8=0;
    s8+=serial;
    switch(cnt) {
      case 0:
        x8=s8;
         break;
      case 1:
        y8=s8;
         break;
      case 2:
        z8=s8;
         break;
      default:
        cnt=0;
        break;
    }
    if(cnt<2){
      cnt++;
      return;
    }
    cnt=0;
    serialEvent();
  }
  //serial=50;
        //rect(120,numH-serial, 20, serial);
  angle = angle + 0.05;

  // Rotating wireframe cube
  pg.beginDraw();
  pg.translate(width >> 1, height >> 1);
  pg.rotateZ(radians((-x8)));
  pg.rotateX(radians(y8));
  pg.background(0);
  pg.stroke(128);
  pg.scale(80);
  pg.noFill();
  pg.box(4);
  pg.endDraw();

  loadPixels();

  int counter = 0;
    // Do the fire calculations for every pixel, from top to bottom
  for (int y = 0; y < height; y++) {
    for(int x = 0; x < width; x++) {
      // Add pixel values around current pixel

      fire[x][y] =
          ((fire[calc3[x]][calc2[y]]
          + fire[calc1[x]][calc2[y]]
          + fire[calc4[x]][calc2[y]]
          + fire[calc1[x]][calc5[y]]) << 5) / 129; 

      // Output everything to screen using our palette colors
      pixels[counter] = palette[fire[x][y]];

      // Extract the red value using right shift and bit mask
      // equivalent of red(pg.pixels[x+y*w])
      if ((pg.pixels[counter++] >> 16 & 0xFF) == 128) {
        // Only map 3D cube 'lit' pixels onto fire array needed for next frame
        fire[x][y] = 128;
      }
    }
  }
  //updatePixels();

}

void serialEvent(){

   background(255);
  line(70,70,70,370);
  line(70,270,200,270);
  line(70,370,200,370);
  fill(0);
  //textFont(font, 11);
  text("Sensor\nValue",22,80);
  text("Analog Input", 95, 390);

  noFill();

  println(x8+" "+y8+" "+z8);

  rect(100,270, 20, x8);
  rect(140,270, 20, y8);
  rect(180,270, 20, z8);
    text(s8,25,110);
        myPort.write(0x01);

}

Arduino WiFi Shield

 

The shield most used in practice are those that expand the communication of the Arduino board and in particular those that allow to add a network connection to a TCP / IP.
The first shield of this kind were those based on Ethernet technology, which helps the Arduino to connect to a LAN based on Ethernet TCP / IP, and so to Internet.
The convenience of Wi-Fi is now known to all: no more cables to spread (which increases the cost and time of construction of any plant) and full freedom in the positioning of the different nodes of the wireless network.

One of the first companies to focus on Wi-Fi was the AsyncLabs, who proposed a famous WiFi shield, including the appropriate libraries.
What we propose is a new solution for Wi-Fi: this is a shield that the hardware was inspired by that of AsyncLabs, but in addition, we have provided a slot for microSD memory.

The basic component of the shield that we have made is a Wi-Fi module MRF24WB0MA manufactured by Microchip.
The device is a Wi-Fi IEEE 802.11 RF transceiver, with a data rate between 1 and 2 Mbps, and with an internal antenna.
The WiFi shield supports both types of wireless networks infrastructure (BSS) and ad-hoc (IBSS) and is also allowed to connect to secure networks (cryptographers and are supported 64 and 128-bit WEP, WPA/WPA2 and TKIP, AES and PSK).

In our project is using the SPI connection for communication with the WiFi controller through the SDO, SCK and SDI (pin 32, 34 and 35) and, if necessary, can be reset using a button (P1 in the diagram).
Peculiarities of our shield is that it has a SD card slot (SD1 signed in the schematic), managed by Arduino always through the SPI port.
There is also a LED (LD1 signed) used to indicate whether the Wi-Fi is active or not, its management is implemented through a hardware port, so you usually can not be used by software. In the event that was needed precisely this port, you still have a jumper that, when opened, making it available again disconnect the LED pin I / O.
Finally, to complete the hardware of the shield there is a section dedicated to the power, consists of a 3.3 V voltage regulator (indicated with U2).

BOM

R1: 4,7 kohm (0805)
R2: 4,7 kohm (0805)
R3: 4,7 kohm (0805)
R4: 4,7 kohm (0805)
R5: 1 kohm (0805)
R6: 4,7 kohm (0805)
R7: 2,2 kohm (0805)
R8: 1 kohm (0805)
R9: 2,2 kohm (0805)
R10: 1 kohm (0805)
R11: 2,2 kohm (0805)
R12: 330 ohm (0805)

C1: 220 µF 6,3 VL (D)
C2: 220 µF 6,3 VL (D)
C3: 100 nF (0805)
C4: 100 nF (0805)
C5: 100 nF (0805)

LD1: Led (0805)

U1: MRF24WB0MA/RM
U2: TC1262-3.3 (SOT-223)

SD1: µSD-Card (MICROSDSOCK2)

P1: switch SMD

Varie:
- headers  male 2 via
- headers  M/F 6 via(2 pz.)
- headers  M/F 8 via(2 pz.)
- headers  M/F 3 via(2 pz.)
- Jumper
- PCB

The library supports various operating modes, which are Web Server, Web Client, Socket, UDP and WiServer.

The library is constantly evolving, so we have provided a space where they will be published on code.google.com various versions available.

Code Example for WiFi shield

 Web Client

/******************************************************
 SoftwareDemo2WebClientWiFi
 Esempio codice Web Client tramite Wi-Fi
 Autori: Ingg. Tommaso Giusto e Ing. Alessandro Giusto
 Email:  tommro@libero.it
******************************************************/

// Inclusione Libreria per Server Web WiFi
#include <WiServer.h>

// Definizione Parametri Rete Wireless
#define WIRELESS_MODE_INFRA	1  // Infrastrutturata (basata su Access Point)
#define WIRELESS_MODE_ADHOC	2  // Ad-hoc (senza Access Point)

unsigned char local_ip[] = {192, 168, 1, 250};      // Indirizzo IP
unsigned char gateway_ip[] = {192, 168, 1, 91};	    // Indirizzo gateway IP
unsigned char subnet_mask[] = {255, 255, 255, 0};   // Subnet Mask
const prog_char ssid[] PROGMEM = {"Sitecom"};	    // SSID access point

// Selezione tipo di cifratura rete Wireless
unsigned char security_type = 0;  // 0 -> nessuna cifratura
                                  // 1 -> cifratura WEP
                                  // 2 -> cifratura WPA
                                  // 3 -> cifratura WPA2

// Password cifratura per WPA/WPA2 (max. 64 cratteri)
const prog_char security_passphrase[] PROGMEM = {"12345678"};

// Password cifratura per WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Selezione tipo di rete Wireless infrastrutturata
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

// Variabili per lunghezza SSID e password di cifratura
unsigned char ssid_len;
unsigned char security_passphrase_len;

// Definizione Parametri Google Search
// Indirizzo IP per server www.google.it
uint8 google_ip[] = {209, 85, 148, 106};

// Richiesta GET verso GOOGLE
GETrequest getGoogleSearch (google_ip, 80, "www.google.it", "/search?q=ElettronicaIn");

// Inizializzazione Scheda
void setup() {
  // Inizializzo WiServer (NULL indica non dobbiamo servire pagine Web)
  WiServer.init (NULL);
  // Inizializzo porta seriale
  Serial.begin (9600);
  WiServer.enableVerboseMode (false);

  // Inizializzazione richiesta GET (parametro indica funzione a cui verra' passata la risposta)
  getGoogleSearch.setReturnFunc (Gestione_Risposte_Web);
}

// Variabile memorizzazione riavvio (millisecondi) di esecuzione ricerca
long updateSearch = 0;

// Programma Principale
void loop() {
  // Se passato periodo di attesa esecuzione ricerca
  if (millis() >= updateSearch) {
    // Eseguo ricerca
    getGoogleSearch.submit();
    // Aggiorno tempo di riavvio (attensa di 1 ora)
    updateSearch = updateSearch + (1000 * 60 * 60);
  }

  // Avvio WiServer
  WiServer.server_task();

  // Attesa
  delay(10);
}

// Gestione diverse risposte provenienti dal WEB
void Gestione_Risposte_Web (char* data, int len) {
  // Stampo la risposta proveniente dal WEB su porta seriale
  int i;

  // Stampo i singoli caratteri della risposta proveniente dal WEB su porta seriale
  for (i = 0; i < len; i++) {
    Serial.print(*(data));
    data++;
  }
}

Web Server

/******************************************************
 SoftwareDemo1WebServerWiFi
 Esempio codice Web Server tramite Wi-Fi
 Autori: Ingg. Tommaso Giusto e Ing. Alessandro Giusto
 Email:  tommro@libero.it
******************************************************/

// Inclusione Libreria per Server Web WiFi
#include <WiServer.h>

// Definizione pin INPUT/OUTPUT
int Pin_Led_Rosso = 7;  // Led rosso uscita digitale 7

// Definizione Variabili Globali Stato Led
byte Stato_Led_Rosso = 0;  // Stato led rosso

// Definizione Parametri Rete Wireless
#define WIRELESS_MODE_INFRA	1  // Infrastrutturata (basata su Access Point)
#define WIRELESS_MODE_ADHOC	2  // Ad-hoc (senza Access Point)

unsigned char local_ip[] = {192, 168, 1, 250};      // Indirizzo IP
unsigned char gateway_ip[] = {192, 168, 1, 91};	    // Indirizzo gateway IP
unsigned char subnet_mask[] = {255, 255, 255, 0};   // Subnet Mask
const prog_char ssid[] PROGMEM = {"Sitecom"};	    // SSID access point

// Selezione tipo di cifratura rete Wireless
unsigned char security_type = 0;  // 0 -> nessuna cifratura
                                  // 1 -> cifratura WEP
                                  // 2 -> cifratura WPA
                                  // 3 -> cifratura WPA2

// Password cifratura per WPA/WPA2 (max. 64 cratteri)
const prog_char security_passphrase[] PROGMEM = {"12345678"};

// Password cifratura per WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Selezione tipo di rete Wireless infrastrutturata
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

// Variabili per lunghezza SSID e password di cifratura
unsigned char ssid_len;
unsigned char security_passphrase_len;

// Inizializzazione Scheda
void setup() {
  // Inizializzo pin usati come INPUT/OUTPUT
  pinMode (Pin_Led_Rosso, OUTPUT);

  // Inizializzo WiServer (Gestione_Richieste_Web per creare/trasmettere pagine HTML)
  WiServer.init (Gestione_Richieste_Web);
  // Inizializzo porta seriale
  Serial.begin (9600);
  WiServer.enableVerboseMode (false);

  // Spengo led rosso
  Led_Rosso_OFF();
}

// Programma Principale
void loop() {
  // Avvio WiServer
  WiServer.server_task();
}

// Gestione diverse richieste provenienti dal WEB
// INPUT:   URL pagina web richiesta
// OUTPUT:  Flag URL riconosciuto/non riconosciutoo
boolean Gestione_Richieste_Web (char* URL) {
  // Se URL richieso corrisponde a "/" (pagina index)
  if (strcmp (URL, "/") == 0) {
    // Secondo gli I/O creo e invio le pagine Web
    Invia_Pagina_Web();

    // Ritorno URL è stato riconosciuto
    return (true);
  }    // Chiusura if URL richieso corrisponde a "/" (pagina index)

  // Se URL richieso corrisponde a "?OPERATION=ACCENDI_ROSSO
  if (strcmp (URL, "/?OPERATION=ACCENDI_ROSSO") == 0) {
    // Accendo led rosso
    Led_Rosso_ON();
    Stato_Led_Rosso = 1;

    // Secondo gli I/O creo e invio le pagine Web
    Invia_Pagina_Web();

    // Ritorno URL è stato riconosciuto
    return (true);
  }    // Chiusura if URL richieso corrisponde a "?OPERATION=ACCENDI_ROSSO"

  // Se URL richieso corrisponde a "?OPERATION=SPEGNI_ROSSO"
  if (strcmp (URL, "/?OPERATION=SPEGNI_ROSSO") == 0) {
    // Spengo led rosso
    Led_Rosso_OFF();
    Stato_Led_Rosso = 0;

    // Secondo gli I/O creo e invio le pagine Web
    Invia_Pagina_Web();

    // Ritorno URL è stato riconosciuto
    return (true);
  }    // Chiusura if URL richieso corrisponde a "?OPERATION=SPEGNI_ROSSO"

  // Ritorno URL non riconosciuto
  return (false);
}

// Funzione che, secondo gli I/O, crea e invia le pagine Web
void Invia_Pagina_Web() {
  // Usando le funzioni WiServer.print trasmette al pagina Web da visualizzare
  WiServer.print ("<html>");
  WiServer.print ("<head>");
  WiServer.print ("<meta http-equiv=""refresh"" content=""10;url=http://");
  WiServer.print (local_ip[0], DEC);
  WiServer.print (".");
  WiServer.print (local_ip[1], DEC);
  WiServer.print (".");
  WiServer.print (local_ip[2], DEC);
  WiServer.print (".");
  WiServer.print (local_ip[3], DEC);
  WiServer.print ("/"" />");
  WiServer.print ("</head>");
  WiServer.print ("<p align=""center"">");
  WiServer.print ("Hello World!<br>");
  WiServer.print ("Esempio Web Server tramite librerie WiShield<br>");
  WiServer.print ("By Ingg. Tommaso Giusto e Ing. Alessandro Giusto<br>");
  WiServer.print ("(tommro@libero.it)<br>");

  // Se led rosso spento
  if (Stato_Led_Rosso == 0) {
    WiServer.print ("<form>Led rosso spento<br>");
    WiServer.print ("<method=GET>");
    WiServer.print ("<input type=submit name=OPERATION value=ACCENDI_ROSSO></form><br>");
  }    // Chiusura if led rosso spento
  // Se led rosso acceso
  else {
    WiServer.print ("<form>Led rosso acceso<br>");
    WiServer.print ("<method=GET>");
    WiServer.print ("<input type=submit name=OPERATION value=SPEGNI_ROSSO></form><br>");
  }    // Chiusura if led rosso acceso

  // Termino pagina HTML
  WiServer.print ("</html>");
}

// Accende il led rosso
void Led_Rosso_ON() {
  digitalWrite (Pin_Led_Rosso, LOW);
}

// Spegne il led rosso
void Led_Rosso_OFF() {
  digitalWrite (Pin_Led_Rosso, HIGH);
}

 

 

 

 

TiDiGino, the Arduino-based GSM remote control

 

Using an ATmega 2560 and therefore the heart of Arduino, we have developed a universal remote control with GSM. This allows  to control 2IN/2OUT, DTMF key, gate control and GSM thermostat activated remotely.

We have already presented several remote control with different functions.
But now we want to present the best remote control ever made with Arduino.
The remote control is easier, thanks to the availability of several libraries that allow you to do anything to the Arduino microprocessor; if there is not really a specific library, you can modify an existing one. Thus was born TiDiGino, based on the chip ATmega 2560 used in Arduino Mega. Our system has connectors S.I.L. to mount any shield, each of them is in the same location where you would be in the original development platform, which enables the use of commercial and in any case the standard shield.
We said that the functions of our remote control, ie 2IN/2OUT, gate opener, key DTMF GSM and thermostat can be achieved by using special firmware, well, we could write these ourselves, but we wanted to offer our readers who know the Arduino environment do them. This is the sense of TiDiGino Contest, which you could follow our blog and that has just ended, as promised, we publish the hardware of the remote control and a few routines.

The circuit

The TiDiGino is based on a ATmega 2560 chip, some pins are used to manage GSM functionality, corresponding to ports that are not used in the original Arduino MEGA. For this reason it is necessary to replace the file pins_arduino.c located under the folder C:\ProgramFiles\arduino-0022\hardware\arduino\cores\arduino that is created by downloading the Arduino IDE, with that we made available with the library, otherwise it is possible to manage all’ATmega 2560 lines of I/O provided by the platform Arduino MEGA.

This choice was intended to leave some I/O free for use by any shield. Therefore you can use the sketches already made to control a specific shield with the original Arduino board, even on TiDiGino.
In compliance with the open-source philosophy we have made available on our site libraries to operate the main blocks of the TiDiGino.
To test the circuit we made four sketches, each of which allows you to use a section of the system. The sketches are all contained in the file GSM_TDGINO.zip, downloadable from the development page of Google, which contains the library that allows you to manage the GSM of TDGINO.
This library comes from the one developed by HWKitchen, but has been adapted to our hardware, as, for example, use the second serial dell’ATMEGA2560 to manage the GSM module of Simcom SIM900. Decompressing the zip in the folder of the Arduino libraries (eg C:\ProgramFiles\arduino-0022\libraries) the library is immediately usable.
By copying the library, are also automatically installed the examples we have developed to manage the various sections, in order to test these examples must be connected to the USB port TDGINO and provide an external power supply circuit of about 12 VDC (1 A of current).
This creates a virtual COM will be used to program the remote control. Select the Board “Arduino Mega 2560″ and from File-> Examples-> GSM_TDGINO, choose the example that you want to upload to the remote control.

 

 

The hardware

The I/O used for the expansions are PB4÷PB7, PE3÷PE5, PG5, PH3÷PH6, then there are PE0 and PE1 that are, respectively, RXD and TXD of the first internal UART to the microcontroller.
Now we see the lines of I/O used to manage the devices necessary to implement the functions of remote control, starting from PE6 and PE7 configured as input (pull-up R38 and R39) used to read the status of the optically isolated inputs, each of which detects the presence of a dc voltage (from a minimum of 3 to a maximum of about 35 volts) and AC (from a minimum of 2.5 to a maximum of 30 Vrms) applied to IN1 (circuit U4) and IN2 (circuit U5).
The command of the relay output is obtained with PC0 and PC1, initialized as outputs, each relay is controlled by an NPN transistor.
The GSM in the circuit diagram is not the GSM module, but a circuit (TDGGSM_900 - Store) that mounts it.
There is also a EEPROM memory 24FC256-SN to store user data.
For the management of the temperature sensor, used for the feature “Thermostat GSM”, the ATmega use the pin PK1 initialized as two-way line, the remote temperature sensor used in the Dallas DS1820 is capable of measuring temperatures in the range -5 to 150 ° C with an accuracy of ± 0.5 ° C (-10 to 85 ° C).
The DTMF section use the U7 (a MT8870, SMD): capable to decode standards tone thanks to a complex pattern of active filters agreed by the clock signal generated from its oscillator.
The USB interface circuit uses the integrated U8: the classic FT232RL. The pins 3 (TX) and 2 (RX) correspond to the first UART, since they are essentially used to program TiDiGino thanks the bootloader.
P1 is the button to reset the circuit, which also DTR is forced, by the computer when we want to load the firmware in the micro, exploiting the bootloader.
Well, we conclude the analysis with the power, which is a DC voltage, even non-stabilized (applied to the points + and – PWR) in value between 7 and 32 V, this voltage is filtered downstream of the protection diode reverse polarity (D1) by the capacitors C1 and C2, the fuse F1 allows us to protect the circuit and the source of power in an integrated circuit in the controller below and that we need to derive the 4 volts required to make run the rest of the circuit.

BOM

R1: 0,1 ohm 1W (1206)
R2: 2,2 kohm (0805)
R3: 1 kohm (0805)
R4: 100 kohm (0805)
R5: 4,7 kohm (0805)
R6: 4,7 kohm (0805)
R7: 330 ohm (0805)
R8: 330 ohm (0805)
R9: 4,7 kohm (0805)
R10: 10 kohm (0805)
R11: 4,7 kohm (0805)
R12: 10 kohm (0805)
R13: 330 ohm (0805)
R14: 330 ohm (0805)
R15: 1,5 kohm (0805)
R16: 1,5 kohm (0805)
R17: 330 ohm (0805)
R18: 4,7 kohm (0805)
R19: 4,7 kohm (0805)
R20: 100 ohm (0805)
R21: 4,7 kohm (0805)
R22: 4,7 kohm (0805)
R23: 330 kohm (0805)
R24: 39 kohm (0805)
R25: 56 kohm (0805)
R26: 100 kohm (0805)
R27: 100 kohm (0805)
R28: 4,7 kohm (0805)
R29: 4,7 kohm (0805)
R30: 4,7 kohm (0805)
R31: 0 ohm (0805) *
R32: 0 ohm (0805) *
R33: 4,7 kohm (0805)
R34: 470 ohm (0805)
R35: 470 ohm (0805)
R36: 10 ohm (0805)
R37: 10 ohm (0805)
R38: 4,7 kohm (0805)
R39: 4,7 kohm (0805)

C1: 100 nF (0805)
C2: 220 µF 35 VL (F)
C3: 100 pF (0805)
C4: 100 nF (0805)
C5: 100 µF 16 VL (D)
C6: 100 nF (0805)
C7: 100 nF (0805)
C8: 470 µF 6,3 VL (D)
C9: 22 pF (0805)
C10: 22 pF (0805)
C11: 47 µF 16 VL (D)
C12: 47 µF 16 VL (D)
C13: 100 nF (0805)
C14: 470 µF 6,3 VL (D)
C15: 470 µF 6,3 VL (D)
C16: 470 µF 6,3 VL (D)
C17: 10 pF (0805)
C18: 100 nF (0805)
C19: 10 pF (0805)
C20: 100 nF (0805)
C21: 100 nF (0805)
C22: 4,7 µF 6,3 VL  (R)
C23: 100 nF (0805)
C24: 100 nF (0805)
C25: 100 nF (0805)

Q1: Quartz 16 MHz (C7S)
Q2: Quartz 3,579545 MHz (HC49/4H SMX)

U1: MC34063AD
U2: DS18B20+
U3: 24FC256-SN
U4: TLP181
U5: TLP181
U6: ATMEGA2560-16AU
U7: MT88L70AS
U8: FT232RL
U9: TC1262-3.3 (SOT-223)
GSM: TDGGSM_900

D1: GF1M-E3
D2: MBRS140TRPBF
D3: GF1M-E3
D4: GF1M-E3

T1: BC817
T2: BC817

LD1: LED 3 mm red
LD2: LED 3 mm red
LD3: LED 3 mm yellow
LD4: LED 3 mm yellow
LD5: LED 3 mm green
LD6: LED yellow(0805)
LD7: LED red (0805)

L1: coil 22 µH

RL1: relay 5V 2 vias
RL2: relay 5V 2 vias

P1: Microswitch
P2: Microswitch 90°

F1: Fuse 2 A (1206)

- screw 2 vias(2 pz.)
- screw 3 vias (2 pz.)
- Mini-USB
- Plug
- Jumper
- Strip male 2 poli
- Strip male 3 poli (2 pz.)
- Strip male 4 poli
- Strip female 3 poli
- Strip female 6 poli (2 pz.)
- Strip female 8 poli (2 pz.)
- Strip female 16 poli
- PCB

Functions

There are several sketches to handle the remote control, all came through TiDiGino contest.
These files can be downloaded from Google, where you will find the library and files created by various readers.
Basically all the sketches perform the same functions.
Summarize here the common features.

The remote can be operated by commands sent by SMS, but you can also control it via the serial port (connected to USB converter).
Each command is followed by a response (via SMS) directly to the sender, but the answer may be disabled. In addition there is an alarm function, as the automatic sending of SMS or voice calls, based on conditions on each of the two inputs.
The circuit can also be used as a gate control, calling the SIM in the TiDiGino: the system recognize the calling number and if this number is stored the relay will switch on. In the DTMF mode, the remote control can be controlled by a multi-frequency telephone tone.
In addition, the circuit can operate as a thermostat, running an air conditioning system.

In summary, there are the following features:

• Remote alarm
• Gate control
• GSM termostat
• Remote control with DTMF

Library and sketch

Download the latest sketch for this GSM remote control.

Design

 

Lighted plexiglass Christmas ornaments (Arduino version)

In the previous post we showed you how to make small Christmas shapes using an RGB LED and a small circuit based on PIC.
The designs were obtained working with the CNC some acrylic sheets.
But our CNC can do much more … Therefore we decided to make the greatest figure and design a new driver that mounts more LEDs.

Just because we do not like things simple we recreated all using a system based on Arduino.
This allows you to create an open source system easy to modify.
The microcontroller is an Atmega328 preprogrammed with the bootloader of Arduino UNO. The programming can be done via a USB / TTL (eg FTDI5V of SparkFun).
The circuit operation is very similar to that of the smallest model: here we find the photocell that allows to verify the amount of light present in the environment, but in this case, you can adjust the sensitivity of the circuit by a trimmer.

BOM

R1: 10 kohm
R2: 820 ohm
R3: 820 ohm
R4: 1 kohm
R5: 820 ohm
R6: 820 ohm
R7: 1 kohm
R8: 820 ohm
R9: 820 ohm
R10: 1 kohm
R11: 820 ohm
R12: 820 ohm
R13: 1 kohm
R14: 820 ohm
R15: 820 ohm
R16: 1 kohm
R17: 820 ohm
R18: 820 ohm
R19: 1 kohm
R20: 820 ohm
R21: 820 ohm
R22: 1 kohm
R23: 820 ohm
R24: 820 ohm
R25: 1 kohm
R26: 820 ohm
R27: 820 ohm
R28: 1 kohm
R29: 10 kohm
R30: 4,7 kohm
R31: 10 kohm
R32: 4,7 kohm
R33: 4,7 kohm
R34: 10 kohm
R35: 4,7 kohm
R36: 10 kohm
R37: 4,7 kohm
R38: 10 kohm
R39: Trimmer 4,7 kohm MV

C1: 100 nF
C2: 470 µF 25 VL
C3: 470 µF 25 VL
C4: 100 nF
C5: 15 pF
C6: 15 pF
C7: 100 nF
C8: 100 µF 25 VL

T1: BC547
T2: BC547
T3: BC547

LD1: LED 5 mm RGB c.a.
LD2: LED 5 mm RGB c.a.
LD3: LED 5 mm RGB c.a.
LD4: LED 5 mm RGB c.a.
LD5: LED 5 mm RGB c.a.
LD6: LED 5 mm RGB c.a.
LD7: LED 5 mm RGB c.a.
LD8: LED 5 mm RGB c.a.
LD9: LED 5 mm RGB c.a.

U1: 7805
U2: ATMEGA328P-PU (with bootloader)

Q1: 16 MHz

LDR1: photoresistor 2÷20 kohm

- Terminal 2 via (3 pz.)
- Socket 14+14
- Battery 12V/2A
- Strip male 6 via
- Plug
- Switch

Comparing the value read from the A/D converter connected to the photoresistor with that connected to trimmer R39, the micro decides whether to start the sequence of fading, or whether turn off the LEDs. RGB LEDs are driven by the transistor; this choice permit to control with a single line of microcontroller, more LEDs in order to create large luminous figures.

As you can see, we use a line dell’ATmega for each of the primary colors of red, green and blue, so it is clear that all the diodes will do the same play of light. Of course isn’t required to mount all the LEDs provided in the circuit: you mount those who need to obtain a good visual effect on the size of the pattern in the Plexiglass. Note that there are three terminals on the PCB: one to connect the power switch (ON / OFF) a second (BATT) to apply to the circuit power supply and a third (CHARGE) for a possible battery charger lead or a small 12-volt solar panel, which already incorporates the charging circuit. These solutions allow you to use the figures lack the power grid. In this regard, an analog input of the microcontroller is dedicated to control the battery voltage: when it drops below 10 V, the circuit will emit flashes to warn that the energy is about to end.

This circuit is evidently intended to be used externally (provided it is properly isolated) and will turn on and off independently, thanks to the ambient light sensor, which will illuminate the figures in the evening to let off in the morning. In short, is a solution to decorate the garden or backyard.

Building shapes
The materials chosen for this application are clear polycarbonate (or methacrylate) or Plexiglas, which can give the shape you want. Then we need to affect, deep enough (half or two thirds the thickness of the plate) the drawing or writing that you want to appear bright.

The Sketch

//****************************************************************
//*  Name    : RGB controller for common anode led               *
//*  Author  : Landoni Boris                                     *
//*  www.open-electronics.org                                    *
//*  blog.elettronicain.it                                       *
//*  www.futurashop.it                                           *
//****************************************************************

int red = 9;    // RED LED connected to PWM pin 3
int green = 10;    // GREEN LED connected to PWM pin 5
int blue = 11;    // BLUE LED connected to PWM pin 6
int photo = A4;    // BLUE LED connected to PWM pin 6
int trim = A5;    // BLUE LED connected to PWM pin 6
int volt = A2;    // BLUE LED connected to PWM pin 6
int r=50; int g=100; int b=150;
int rup; int gup; int bup;
int fader=1;
int inc=10;
void setup()
{
      Serial.begin(9600);
      Serial.println("Serial READY");
      rgb(r, g, b);
      r = random(0,255);
      g = random(0,255);
      b = random(0,255);

} 

void loop()  {

  Serial.print("trim  ");
  Serial.println(analogRead(trim)*2);  

  Serial.print("photo ");
  Serial.println(analogRead(photo)); 

  Serial.print("volt ");
  Serial.println(analogRead(volt));
  if (analogRead(volt)<600){
      Serial.println("low battery");
      rgb(0, 0, 0);
      delay(500);
      rgb(255, 255, 255);
  }

  if ((analogRead(trim)*2)>analogRead(photo)){
      Serial.println("trim > photo  -  off");
      rgb(0, 0, 0);
      fader=0;
  }
  else
  {
    if (fader==0){
      r = random(0,255);
      g = random(0,255);
      b = random(0,255);
    }
    fader=1;

  }
  //delay(2000);

  if (fader==1){
    funcfader();
  }
}

void funcfader(){
    Serial.println("fader");
    if (rup==1){r+=1;}
    else{r-=1;}
    if (r>=255){rup=0;}
    if (r<=0){rup=1;}

    if (gup==1){g+=1;}
    else{g-=1;}
    if (g>=255){gup=0;}
    if (g<=0){gup=1;}

    if (bup==1){b+=1;}
    else{b-=1;}
    if (b>=255){bup=0;}
    if (b<=0){bup=1;}

    delay(inc*2);
    rgb(r, g, b);
}

void rgb(int r, int g, int b)
{
  Serial.print("RGB: ");
  Serial.print(r);
  Serial.print(" ");
  Serial.print(g);
  Serial.print(" ");
  Serial.println(b);
  if (r>255) r=255;
  if (g>255) g=255;
  if (b>255) b=255;
  if (r<0) r=0;
  if (g<0) g=0;
  if (b<0) b=0;
  analogWrite(red, r);
  analogWrite(green, g);
  analogWrite(blue, b);
}

 

Star
Reindeer
Santa Claus
Tree

How to connect a weather station WS2355 (or WS2300) to Weather Underground with Arduino

Our weather station LIVE

 

There are several softwares that enable the publication of the weather data of a professional weather station, but they all work on PC, so we should connect the weather station to a computer and leave it on, the idea is not good because the computer takes up space and consumes a lot. At a time when we should spare the energy, its not a good thing.
The project we’re talking about instead operates as a stand-alone application and allows you to publish the weather station data independently on http://www.wunderground.com, “forgetting” the PC consumption and even the desk space.

Arduino controls the dialogue with the weather station to acquire the data and also the Ethernet interface to transfer them, by making the necessary connection to the Internet via ADSL, passing by a router pointing to the IP address of the Weather Underground site and transferring information using the TCP / IP.

 

Our project

This circuit reads data from a weather station with serial interface and upload the data collected on http://www.wunderground.com.
Not all stations are equal, therefore, our circuit can not be universal but it is indicated specifically for stations La Crosse WS2355, WS2300 or WS2350.

The choice of weather station WS23xx was dictated primarily by a consideration: it has a convenient serial interface to connect and dialogue with a microcontroller such as Arduino.
We chose www.wunderground.com site because it allows anyone to upload their weather data, but also to monitor the temperature, humidity, pressure, wind etc. on line. Also on this site there are many widgets that allow you to integrate data in website or blog.
An example is the Widget for the home page of Google.
The data sent by users are publicly available, then from the home page we can specify the geographic area that interests us and we will see a screen that lists all of the corresponding stations.

How does it work?

The system has two circuit: one is the famous Arduino UNO and the other is a shield that integrates the Ethernet module WIZnet (you may, of course, use the the original Ethernet Shield), as well as a TTL/RS232 logic level converter MAX238 type. The converter allows you to adapt the serial levels of weather station to the TTL levels of Arduino.
Please be aware that the communication port of the weather station is not a simple RS232, because it has no ground reference. The DTR line must have a negative voltage while the RTS must be positive. The lack of common ground leads to the hypothesis (remember that there is no official document) that these two lines are taken as a reference of logic levels used in communication. It is a system that not only allows the use of serial connections relatively long, but also gives the opportunity to agree devices with different voltage levels on the serial port.
To communicate with La Crosse, the speed of the serial device (in our case, the Arduino module) must be set to 2,400 bps, with blocks of 8 bits, no parity and one stop bit (2400-8-N-1).
The memory map of the weather station, like many other unofficial information on the WS2355 is on the site http://www.lavrsen.dk/foswiki/bin/view/Open2300/WebHome.

 

The hardware

The jumpers on the lines T3IN and R3OUT (respectively RS232/TTL converter output and RS232/TTL converter input) let you choose which lines use for Arduino communication: we give you the opportunity to choose if use the serial hardware TXD and RXD or the two I/O digital D2 and D3 emulating a serial port with the appropriate library that can be downloaded from the website http://arduiniana.org/libraries/newsoftserial.

 

R1: 470 ohm
C1: 1 µF 100 VL
C2: 1 µF 100 VL
C3: 1 µF 100 VL
C4: 1 µF 100 VL
U1: WIZNET
U2: MAX238CNG
LD1: led 3 mm red

- socket 12+12
- Strip male 3 via (2 pz.)
- Jumper (2 pz.)
- Strip female/male 6 via (2 pz.)
- Strip female/male 8 via(2 pz.)
- Strip female 10 via (4 pz.)
- DB9 male
- PCB


 

 

The sketch

/*

****************************************************************
*  Name    : Personal Weather Station to wunderground.com      *
*  Author  : Landoni Boris                                     *
*  www.open-electronics.org                                    *
*  blog.elettronicain.it                                       *
*  www.futurashop.it                                           *
****************************************************************

http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol#Example_URL

action [action=updateraw] -- always supply this parameter to indicate you are making a weather observation upload
ID [ID as registered by wunderground.com]
PASSWORD [PASSWORD registered with this ID, case sensative]
dateutc - [YYYY-MM-DD HH:MM:SS (mysql format)] In Universal Coordinated Time (UTC) Not local time
winddir - [0-360 instantaneous wind direction]
windspeedmph - [mph instantaneous wind speed]
humidity - [% outdoor humidity 0-100%]
tempf - [F outdoor temperature]
rainin - [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min
indoortempf - [F indoor temperature F]
indoorhumidity - [% indoor humidity 0-100]
softwaretype - [text] ie: WeatherLink, VWS, WeatherDisplay

windgustmph - [mph current wind gust, using software specific time period]
windgustdir - [0-360 using software specific time period]
windspdmph_avg2m  - [mph 2 minute average wind speed mph]
winddir_avg2m - [0-360 2 minute average wind direction]
windgustmph_10m - [mph past 10 minutes wind gust mph ]
dewptf- [F outdoor dewpoint F]
dailyrainin - [rain inches so far today in local time]
baromin - [barometric pressure inches]
weather - [text] -- metar style (+RA)
clouds - [text] -- SKC, FEW, SCT, BKN, OVC
soiltempf - [F soil temperature]
 * for sensors 2,3,4 use soiltemp2f, soiltemp3f, and soiltemp4f
soilmoisture - [%]
* for sensors 2,3,4 use soilmoisture2, soilmoisture3, and soilmoisture4
leafwetness  - [%]
+ for sensor 2 use leafwetness2
solarradiation - [W/m^2]
UV - [index]
visibility - [nm visibility]

http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=KCASANFR5&PASSWORD=XXXXXX&dateutc=2000-01-01+10%3A32%3A35&winddir=230&windspeedmph=12&windgustmph=12&tempf=70&rainin=0&baromin=29.1&dewptf=68.2&humidity=90&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw

mappa ws2300

Command	Hex Digit	  	Command	Hex Digit
82	 0	  	 A2	 8
86	 1	  	 A6	 9
8A	 2	  	 AA	 A
8E	 3	  	 AE	 B
92	 4	  	 B2	 C
96	 5	  	 B6	 D
9A	 6	  	 BA	 E
9E	 7	  	 BE	 F

*/

#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>
#include <NewSoftSerial.h>

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,0,145 };
byte server[] = { 38,102,136,125 }; // http://weatherstation.wunderground.com/

#define UPDATE_INTERVAL            300000    // if the connection is good wait 60 seconds before updating again - should not be less than 5
unsigned long update=0;

NewSoftSerial mySerial(2, 3);   //NewSoftSerial mySerial(rx,tx);

const int ledPin = 6; // the pin that the LED is attached to
const int rts = 4;
const int dtr = 5;
String id = "xxxxxxx";
String PASSWORD = "xxxxxxx";
boolean upload=1;
boolean leggicontinuo=0;

Client client(server, 80);

void setup() {
  Ethernet.begin(mac, ip);

  digitalWrite(ledPin, LOW);
  // initialize serial communication:
  Serial.begin(2400);
  Serial.println("Goodmorning WS2300!");
  // set the data rate for the NewSoftSerial port
  mySerial.begin(2400);

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(rts, OUTPUT);
  pinMode(dtr, OUTPUT);

  digitalWrite(rts, HIGH);
  digitalWrite(dtr, LOW);
  delay(2000);
  digitalWrite(rts, LOW);
  digitalWrite(dtr, HIGH);

  for (int i=0;i<10;i++){
    digitalWrite(ledPin, HIGH);
    delay(200);
    digitalWrite(ledPin, LOW);
    delay(200);
  }

}

void loop() {

  int incomingByteSer;      // a variable to read incoming serial data into
  // see if there's incoming serial data:
  if (Serial.available() > 0) {
    // read the oldest byte in the serial buffer:
    incomingByteSer = Serial.read();
    // if it's a capital H (ASCII 72), turn on the LED:
    Serial.flush();
    if (incomingByteSer == 'o') {
      String data=getTime();
      Serial.print("ora ");
      Serial.println(data);
    }  

    if (incomingByteSer == 'd') {
      String data=getDay();
      Serial.print("giorno ");
      Serial.println(data);
    }
    if (incomingByteSer == 't') {
      String data=getTemp(1);
      Serial.print("temperatura interna F ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'T') {
      String data=getTemp(0);
      Serial.print("temperatura esterna F ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'h') {
      String data=getHum(1);
      Serial.print("umidità interna ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'H') {
      String data=getHum(0);
      Serial.print("umidità esterna ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'p') {
      String data=getPress(1);
      Serial.print("pressione hPa ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'P') {
      String data=getPress(0);
      Serial.print("pressione Hg ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'w') {
      String data=getWind(0);
      Serial.print("wind speed mph ");
      Serial.println(data);     

    } 

    if (incomingByteSer == 'W') {
      String data=getWind(1);
      Serial.print("wind dir ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'r') {
      String data=getRain(1);
      Serial.print("rain 1 ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'R') {
      String data=getRain(0);
      Serial.print("rain 24 ");
      Serial.println(data);
    }  

    if (incomingByteSer == 'e') {
      String data=getDew();
      Serial.print("dew point ");
      Serial.println(data);
    } 

    if (incomingByteSer == 'U') {
      readws();
    } 

    if (incomingByteSer == 'u') {
      pubblica();
    }

    if (incomingByteSer == 'a') {
      if (upload==1){
        upload=0;
        Serial.println("Disattivo l'upload automatico ");
      }
      else
      {
        upload=1;
        Serial.println("Attivo l'upload automatico ");
      }
    }

    if (incomingByteSer == 'A') {
      if (leggicontinuo==1){
        leggicontinuo=0;
        Serial.println("Disattivo lettura continua ");
      }
      else
      {
        leggicontinuo=1;
        Serial.println("Attivo lettura continua ");
      }
    }

    // if it's an L (ASCII 76) turn off the LED:
    if (incomingByteSer == 'L') {
      digitalWrite(ledPin, LOW);
    }
  }

  if (upload==1){
    if (millis() < update) update = millis();
      if ((millis()% 1000) < 2){
        delay (100);
        Serial.print(".");
      }
        if ((millis() - update) > UPDATE_INTERVAL){
            update = millis();
            readws();
            pubblica();
            Serial.println("tempo impiegato per fare la pubblicazione: ");
            Serial.println(millis()-update);
        }
  }

  if (leggicontinuo==1){
    if (millis() < update) update = millis();
      if ((millis()% 1000) < 2){
        delay (100);
        Serial.print(".");
      }
        if ((millis() - update) > UPDATE_INTERVAL){
            update = millis();
            readws();
        }
  }

}

void pubblica()
{

  int timeout=0;
  int skip=0;
  String inString="";
  digitalWrite(ledPin, HIGH);
  Serial.print("connecting  ");

  if (client.connect()) {

    Serial.println("connected");
    //client.println("GET / HTTP/1.0");
    Serial.print("GET /weatherstation/updateweatherstation.php?");//modificare qua.
    client.print("GET /weatherstation/updateweatherstation.php?");//modificare qua.
    pubbws();
    client.println(" HTTP/1.0");
    Serial.println(" HTTP/1.0");

    Serial.print("HOST: ");
    client.print("HOST: ");
    client.println("http://www.wunderground.com");
    Serial.println("http://www.wunderground.com");
    client.println();
  } else {
    Serial.println("connection failed");
  }
  while (!client.available() && timeout<50)
  {
    timeout++;
    Serial.print("Time out ");
    Serial.println(timeout);
    delay(100);
  }

  while (client.available())
  {
        char c = client.read();
          if ((inString.length())<150){ inString.concat(c);}
  }         

  client.flush();

      if ((inString.length())>5)
      {
              Serial.print("Risposta ");
              Serial.print(inString);
      }              

   if (!client.connected())
   {
        Serial.println("disconnecting.");
        client.stop();
        delay (1000);
   }
   digitalWrite(ledPin, LOW);

}

void readws(){

      Serial.println("URL ");
      Serial.print("http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?");
      String temp =getDay();
      String temp1=getTime();
      if ((temp.length()>6) && (temp1.length()>4)){
        Serial.print("ID=");
        Serial.print(id);
        Serial.print("&PASSWORD=");
        Serial.print(PASSWORD);
        Serial.print("&dateutc=");
        Serial.print(temp);
        Serial.print("+");
        Serial.print(temp1);
        scrivimem(temp,0);
        scrivimem(temp1,20);
      }
      else
      {
        Serial.println("Lettura data/ora non riuscita torno");
        return;
      }
      temp=getWind(1);
      if (temp.length()>1){
        Serial.print("&winddir=");
        Serial.print(temp);
        scrivimem(temp,40);
      }
      temp=getWind(0);
      if (temp.length()>2){
        Serial.print("&windspeedmph=");
        Serial.print(temp);
       scrivimem(temp,60);
      }
      temp=getTemp(0);
      if (temp.length()>3){
        Serial.print("&tempf=");
        Serial.print(temp);
        scrivimem(temp,80);
      }
      temp=getRain(1);
      if (temp.length()>2){
        Serial.print("&rainin=");
        Serial.print(temp);
        scrivimem(temp,100);
      }
      temp=getRain(0);
      if (temp.length()>2){
        Serial.print("&dailyrainin=");
        Serial.print(temp);
        scrivimem(temp,120);
      }
      temp=getHum(0);
      if (temp.length()>1){
        Serial.print("&humidity=");
        Serial.print(temp);
        scrivimem(temp,140);
      }
      temp=getDew();
      if (temp.length()>1){
        Serial.print("&dewptf=");
        Serial.print(temp);
        scrivimem(temp,160);
      }
      temp=getPress(0);
      if (temp.length()>1){
        Serial.print("&baromin=");
        Serial.print(temp);
        scrivimem(temp,180);
      }
}

void pubbws(){
      String temp =leggimem(0);
      String temp1=leggimem(20);
      if ((temp.length()>6) && (temp1.length()>4)){
        Serial.print("ID=");
        Serial.print(id);
        Serial.print("&PASSWORD=");
        Serial.print(PASSWORD);
        Serial.print("&dateutc=");
        Serial.print(temp);
        Serial.print("+");
        Serial.print(temp1);
        client.print("ID=");
        client.print(id);
        client.print("&PASSWORD=");
        client.print(PASSWORD);
        client.print("&dateutc=");
        client.print(temp);
        client.print("+");
        client.print(temp1);
      }
      else
      {
        Serial.println("Lettura data/ora non riuscita torno");
        return;
      }
      temp=leggimem(40);
      if (temp.length()>1){
        Serial.print("&winddir=");
        Serial.print(temp);    

        client.print("&winddir=");
        client.print(temp);
      }    

      temp=leggimem(60);
      if (temp.length()>2){
        Serial.print("&windspeedmph=");
        Serial.print(temp);        

        client.print("&windspeedmph=");
        client.print(temp);
      }   

      temp=leggimem(80);
      if (temp.length()>3){
        Serial.print("&tempf=");
        Serial.print(temp);

        client.print("&tempf=");
        client.print(temp);
      }   

      temp=leggimem(100);
      if (temp.length()>2){
        Serial.print("&rainin=");
        Serial.print(temp);       

        client.print("&rainin=");
        client.print(temp);
      }   

      temp=leggimem(120);
      if (temp.length()>2){
        Serial.print("&dailyrainin=");
        Serial.print(temp);       

        client.print("&dailyrainin=");
        client.print(temp);
      }   

      temp=leggimem(140);
      if (temp.length()>1){
        Serial.print("&humidity=");
        Serial.print(temp);        

        client.print("&humidity=");
        client.print(temp);
      }   

      temp=leggimem(160);
      if (temp.length()>1){
        Serial.print("&dewptf=");
        Serial.print(temp);        

        client.print("&dewptf=");
        client.print(temp);        

      }   

      temp=leggimem(180);
      if (temp.length()>1){
        Serial.print("&baromin=");
        Serial.print(temp);        

        client.print("&baromin=");
        client.print(temp);        

      } 

        Serial.print("&windgustmph=0.00");
        client.print("&windgustmph=0.00");
        Serial.print("&action=updateraw");
        client.print("&action=updateraw");

}

void scrivimem(String dataStr, int pos){

  for (int i=0; i<dataStr.length();i++)
  {
    EEPROM.write((pos+i),dataStr[i]);
  }
  EEPROM.write((pos+dataStr.length()),'#');
  for (int i=pos;i<(pos+50);i++)
  {
    if (EEPROM.read(i)=='#')
    {
      break;
    }
  }

}

String leggimem(int pos){
  int lung=0;
  char dataStr[15];

  for (int i=0;i<15;i++)
  {
    dataStr[i]=0;
  }
  for (int i=pos;i<(pos+20);i++)
  {
    lung++;
    if (EEPROM.read(i)=='#')
    {
      break;
    }
    char c=EEPROM.read(i);
    dataStr[i-pos]=(c); 

  }
  dataStr[lung]='\0';
  return(dataStr);
}

String Leggi (int mem[]) {
    String inString;
    char inChar [3];
    int incomingByte=0;      // a variable to read incoming serial data into
    int time=0;
    String chk;
     while ((incomingByte!=2) && (time<20)){
          time++;
          mySerial.print(byte(06));
          delay(20); 

            if ((mySerial.available() > 0) && (time<20)) {
              delay(30);
              time++;
              incomingByte = mySerial.read();
              inString.concat(incomingByte);
            }
      }

     inString="";
     time=0;
     inString.concat("00"); //aggiungo due cifre
     mySerial.flush();
     if (time>18){
          return("0\0");
     }  

      for (int i=0; i<2; i++){

          if (inString.length()>8){
            chk=(inString.substring(4,8));
          }
          inString="";
          inString.concat("00"); //aggiungo due cifre
          for (int tmp=0; tmp<5; tmp++){
            mySerial.print(byte(mem[tmp]));
            while ((mySerial.available() == 0) && (time<100)){
             delay(30);
             time++;
            }
            if (time>98){
              return("0\0");
              break;  

            }        

            if (mySerial.available() > 0) {
              incomingByte = mySerial.read();
            }

            time=0;
           //delay(200);
               while ((mySerial.available() > 0) && time<200 ) {
                    time++;
                    delay(20);
                    incomingByte = mySerial.read();
                    if (tmp<4){
                      if (tmp!=((incomingByte & B11110000)/B10000)){
                          return("0\0");
                          break;
                      }
                    }
                    if (tmp==4){
                      sprintf(inChar, "%02X", incomingByte);
                      inString.concat(inChar);
                    }
               }
           }

      }
        if (chk!=(inString.substring(4,8)))
        {
          return("0\0");

        }
        inString=inString.trim();
        if (inString.length()>16){
          inString=(inString.substring(0,15));
        }
        return(inString);
}

String getTime(){

      String dataStr="";
      int my_array[] = {0x82,0x8A,0x82,0x82,0xDA};  //0200
      String inString;

        for (int ritenta=0; ritenta<10; ritenta++){
           dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                //data= inString.substring(4,6);  //estraggo i decimali della temperatura
                dataStr.concat(inString.substring(6,8));  //estraggo l'ora
                dataStr.concat(":");
                dataStr.concat(inString.substring(4,6));  //estraggo i minuti
                dataStr.concat(":");
                dataStr.concat(inString.substring(2,4));  //estraggo i secondi
                if (((inString.substring(6,8))<23 && (inString.substring(6,8))>=0)&&((inString.substring(4,6))<60 && (inString.substring(4,6))>=0) && ((inString.substring(2,4))<60 && (inString.substring(2,4))>=0)) {
                    break;
                }
                else {
                  dataStr="";
                }

             }
             else
             {
                 delay(500);
             }
        }
      return(dataStr);
}

String getDay(){
      String inString;
      String dataStr="";
      int my_array[] = {0x82,0x8A,0x8E,0xAE,0xEE};
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                dataStr.concat("20");
                dataStr.concat(inString.charAt(13));
                dataStr.concat(inString.charAt(10));
                dataStr.concat("-");
                dataStr.concat(inString.charAt(11));
                dataStr.concat(inString.charAt(8));
                dataStr.concat("-");
                dataStr.concat(inString.charAt(9));
                dataStr.concat(inString.charAt(6));
                if (((inString[13]<='9' && inString[13]>='0')&&(inString[10]<='9' && inString[10]>='0')) && ((inString[11]<='1' && inString[11]>='0')&&(inString[8]<='9' && inString[8]>='0')) && ((inString[9]<='3' && inString[9]>='0')&&(inString[6]<='9' && inString[6]>='0'))) {
                    break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
               delay(500);
           }
        }
      return(dataStr);
}

String getTemp(int dato){
      String inString;
      String dataStr="";
      //String dataStr;
      char cdata [10];
      int lung=0;
      char buff[10];
      int my_array[6];

      if (dato==1){
        my_array[0] = (0x82);
        my_array[1] = (0x8E);
        my_array[2] = (0x92);
        my_array[3] = (0x9A);
        my_array[4] = (0xFA);
      }
       else
      {
        my_array[0] = (0x82);
        my_array[1] = (0x8E);
        my_array[2] = (0x9E);
        my_array[3] = (0x8E);
        my_array[4] = (0xFA);
      }
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                (inString.substring(4,6)).toCharArray(buff,3);
                dataStr.concat((atoi(buff))-30);
                dataStr.concat(".");
                dataStr.concat(inString.substring(2,4));  //estraggo le decine e unità della temperatura
               if (((inString[4]<='9' && inString[4]>='0')&&(inString[5]<='9' && inString[5]>='0')) && ((inString[2]<='9' && inString[2]>='0')&&(inString[3]<='9' && inString[3]>='0'))) {
                   break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
              delay(500);
           }
        }
      if (dataStr.length()>2)
      {

        dataStr.toCharArray(cdata, dataStr.length()+1);
          float fdata=(atof(cdata)*1.800+32.000);
          if (fdata<1000){lung=7;}
          if (fdata<100){lung=6;}
          if (fdata<10){lung=5;}
          dtostrf(fdata,lung,3,cdata);
          dataStr=cdata;
      }
      else
      {
        dataStr="";
      }

      return(dataStr);
}

String getHum(int dato){
      String dataStr="";
      String inString;
      int my_array[6];
      if (dato==1){
        my_array[0] = (0x82);
        my_array[1] = (0x8E);
        my_array[2] = (0xBE);
        my_array[3] = (0xAE);
        my_array[4] = (0xDA);
      }
       else
      {
        my_array[0] = (0x82);
        my_array[1] = (0x92);
        my_array[2] = (0x86);
        my_array[3] = (0xA6);
        my_array[4] = (0xDA);
      }
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                dataStr.concat(inString.substring(2,4));  //estraggo le decine e unità della temperatura
               if ((inString[2]<='9' && inString[2]>='0')&&(inString[3]<='9' && inString[3]>='0')) {
                   break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
               delay(500);
           }
        }
      return(dataStr);
}

String getPress(int dato){
      String dataStr="";
      String inString;
      int my_array[6];
      if (dato==1){
        my_array[0] = (0x82);
        my_array[1] = (0x96);
        my_array[2] = (0xBA);
        my_array[3] = (0x8A);
        my_array[4] = (0xD6);
      }
       else
      {
        my_array[0] = (0x82);      //press hg
        my_array[1] = (0x96);
        my_array[2] = (0xB6);
        my_array[3] = (0xB6);
        my_array[4] = (0xD6);
      } 

        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                dataStr.concat(inString.charAt(7));
                dataStr.concat(inString.charAt(4));
                dataStr.concat(inString.charAt(5));
                if (dato==1){
                  dataStr.concat(inString.charAt(2));
                  dataStr.concat(".");
                  dataStr.concat(inString.charAt(3));
                }
                else
                {
                  dataStr.concat(".");
                  dataStr.concat(inString.charAt(2));
                  dataStr.concat(inString.charAt(3));
                }

                if ((inString[7]<='9' && inString[7]>='0')&&(inString[4]<='9' && inString[4]>='0') && (inString[5]<='9' && inString[5]>='0')&&(inString[2]<='9' && inString[2]>='0') && (inString[2]<='9' && inString[2]>='0')) {
                  break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
              delay(500);
           }
        }
      return(dataStr);

}

String getWind(int dato){
      String dataStr="";
      char cdata [10];
      int lung=0;
      String inString;
      char buff[10];
      int my_array[] = {0x82,0x96,0x8A,0x9E,0xF2};
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
              if (dato==0){
                 dataStr.concat(inString.charAt(7));
                 buff[0]=inString[4];
                 buff[1]=inString[5];
                 int tmp=(strtol(buff,NULL,16));
                 if (tmp<=9){
                   dataStr.concat("0");
                 }

                 dataStr.concat(tmp); // converts a HEX string to long
                 dataStr.concat(dataStr.charAt(2));
                 dataStr.setCharAt(2, '.');
                if ((inString[4]<='9' && inString[4]>='0')&&(inString[5]<='9' && inString[5]>='0')) {
                  break;
                }
                else {
                  dataStr="";
                }
              }
              else
              {
                 buff[0]=inString[6];
                 buff[1]=0;
                 int tmp=((strtol(buff,NULL,16))*22.5);
                 dataStr.concat(tmp);
                if ((tmp>=0)&&(tmp<=360)) {
                  break;
                }
                else {
                  dataStr="";
                  ritenta=0;
                }
              }
           }
           else
           {
               delay(500);
           }
        }

      if (dato==0){    //se richiedo la velocità convertoin miglia orarie    

           if (dataStr.length()>2)
           {
                  dataStr.toCharArray(cdata, (dataStr.length()+1));
                  float fdata=(atof(cdata)*2.23);
                  if (fdata<1000){lung=6;}
                  if (fdata<100){lung=5;}
                  if (fdata<10){lung=4;}
                  dtostrf(fdata,lung,2,cdata);
                  dataStr=cdata;
          }
          else
          {
            dataStr="";
          }
      }

      return(dataStr);
}

String getRain(int dato){
       String dataStr="";
      char cdata [10];
      int lung=0;
      String inString;
            int my_array[6];
      if (dato==1){      //pioggia 1 ora
        my_array[0] = (0x82);
        my_array[1] = (0x92);
        my_array[2] = (0xAE);
        my_array[3] = (0x92);
        my_array[4] = (0xDA);
      }
       else
      {
        my_array[0] = (0x82);      //0497
        my_array[1] = (0x96);
        my_array[2] = (0xA6);
        my_array[3] = (0x9E);
        my_array[4] = (0xD6);
      }
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){
                dataStr.concat(inString.substring(6,8));
                dataStr.concat(inString.substring(4,6));
                if ((inString[6]<='9' && inString[6]>='0')&&(inString[7]<='9' && inString[7]>='0') && (inString[4]<='9' && inString[4]>='0')&&(inString[5]<='9' && inString[5]>='0') && (inString[2]<='9' && inString[2]>='0')&& (inString[3]<='9' && inString[3]>='0')) {
                  break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
               delay(500);
           }
        }

         if (dataStr.length()>2)
      {  

          dataStr.toCharArray(cdata, (dataStr.length()+1));
            //Serial.print("cdata ");
            //Serial.println(cdata);
          float fdata=(atof(cdata)*2.54);  //in pollici
          if (fdata<1000){lung=6;}
          if (fdata<100){lung=5;}
          if (fdata<10){lung=4;}
          dtostrf(fdata,lung,2,cdata);
          dataStr=cdata;
      }
      else
      {
        dataStr="";
      }

      return(dataStr);
}

String getDew(){

      String inString;
      String dataStr="";
      char cdata [10];
      int lung=0;
      char buff[10];

      //Serial.println("leggo pioggia 1h ");
      int my_array[] = {0x82,0x8E,0xB2,0xBA,0xFA};
        for (int ritenta=0; ritenta<10; ritenta++){
            dataStr="";
            inString=Leggi(my_array);
            if (inString.length()>5){            

                (inString.substring(4,6)).toCharArray(buff,3);
                dataStr.concat((atoi(buff))-30);
                dataStr.concat(".");
                dataStr.concat(inString.substring(2,4));  //estraggo le decine e unità della temperatura
               if (((inString[4]<='9' && inString[4]>='0')&&(inString[5]<='9' && inString[5]>='0')) && ((inString[2]<='9' && inString[2]>='0')&&(inString[3]<='9' && inString[3]>='0'))) {
                   break;
                }
                else {
                  dataStr="";
                }
           }
           else
           {
              delay(500);
           }
        }

      if (dataStr.length()>2)
      {

          dataStr.toCharArray(cdata, dataStr.length()+1);
          float fdata=(atof(cdata)*1.800+32.000);
            if (fdata<1000){lung=7;}
            if (fdata<100){lung=6;}
            if (fdata<10){lung=5;}
            dtostrf(fdata,lung,3,cdata);

          dataStr=cdata;
            }
      else
      {
        dataStr="";
      }

      return(dataStr);
}

For the connection we uses the serial port pins 2 and 3 of module Arduino for this reason we have used the library NewSoftSerial that lets you emulate a UART using the generic contact I/O such as serial lines.
Periodically, the Arduino microcontroller polls the weather station and stores the data for the date, time, outside temperature, outside humidity, wind speed and direction, rain fell in one hour and 24 hours, the atmospheric pressure and dew point. The constant UPDATE_INTERVAL defines after how many seconds Arduino public the data collected on the site www.wunderground.com.
In order to publish the data of the control unit on this site, as already mentioned, you must have an account, once registered, there is assigned an ID that will be introduced during the connection to the site in order to proceed with publication.
In the sketch for the Arduino you must enter your ID and password, so that the publication will be successful, otherwise our system will point to the site but will not get access.
For the publication of data is sufficient to recall the page http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php,
passing data to the URL. For example, you have to compose a string like this:

http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=KCASANFR5&PASSWORD=XXXXXX&dateutc=2000-01-01+10&winddir=230&windspeedmph=12&windgustmph=12&tempf=70&rainin=0&baromin=29.1&dewptf=68.2&humidity=90&weather=&clouds=&softwaretype=vws%20versionxx&action=updateraw.

As you see, the user ID and password are inserted in the string. The data temperature should be expressed in Fahrenheit degrees and the wind speed must be in mph (miles per hour). The conversion of the data read by the control unit is made directly from the sketch, so as to spare you the burden to proceed with the manual calculation.

The use of the site www.wunderground.com for the publication of meteorological data is free and subject only to the rules of the provider, there are also advanced features, including the addition of photos and images from a webcam filming on location is the weather station and sent through the Internet.