Chiarimenti da principiante sulle funzioni.

Scusate forse la domanda banale ma cercando e cercando non ho trovato nulla che mi chiarisca le idee:
allego il listato completo su cui ho il problema
si tratta di un progetto trovato in rete (che sto faticosamente adattando alle mie esigenze) che tramite Ardu1 ed ethernet shield permette di creare una pagina web da dove visualizzare due valori di altrettanti sensori e di accendere e spegnere un carico.

#include <String.h>
#include <SPI.h>
#include <Ethernet.h>
#include "EEPROM.h"

 
/* ***
COMPILARE CON ARDUINO 1.0 o successive
controllare un attuatore via web
con sensori di temperatura e luce

*** */
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC address
byte ip[] = { 193, 206, 154, 108}; // ip statico del server
byte gateway[] = { 192, 168, 128, 1 }; // ip del router  
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask 
EthernetServer server(80);
 
int outPin = 3; // pin attuatore
String readString;
int LEDON = 0; // flag status attuatore
int lastbuttonState = 0;
 
/*termistore*/
float temp; // variabile da calcolare
float volt; // variabile da calcolare sul sensore di temperatura
float tempPin = 1;   // pin analogico IN temperature sensor
int ledPintemp = 13; // pin led termistore
float tempreg = 25.0; // temperatura di controllo in celsius
/*fine termistore*/
 
/*fotoresistore*/
int light; // variabile da calcolare
int ledPinlux = 12; // pin led fotoresistenza
int photoresistor = 0; // pin analogico IN fotoresistore
/*fine fotoresistore*/
 
void setup(){
Ethernet.begin(mac, ip, gateway, subnet);
pinMode(outPin, OUTPUT);
pinMode(ledPinlux, OUTPUT);
Serial.begin(9600);
}
 
void loop(){
 
  /*inizio calcolo temperatura*/
  temp = ((5 * analogRead(tempPin) * 100.0 ) / 1024) - 50; // Codice ottimizzato
  /*
  volt = ( analogRead(tempPin) * 5) / 1024; // calcolo il valore letto e lo trasformo in valore di tensione
  temp = (volt - 0.5) * 100; // conversione MCP9700A
  */
  /*fine calcolo temperatura*/
 
  /*inizio luce*/
  light = analogRead(photoresistor);
  light = constrain(light, 0, 1023); // limiti dei valori tra 0 e 100
  light = map(light, 0, 150, 255, 0);
  /*fine luce*/
 
 /*inizio client*/
 EthernetClient client = server.available();
 if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
       char c = client.read();
       readString.concat(c); //memorizzo ogni carattere della stringa
        if (c == '\n' && currentLineIsBlank) { //se richiesta HTTP conclusa
          if(readString.indexOf("L=1") > 0) {  // lettura del valore se il LED si deve accendere
           digitalWrite(outPin, HIGH); // accendo il led
           LEDON = 1;
          }
          else {
           digitalWrite(outPin, LOW); //spengo il led
           LEDON = 0;
          }
          /* Salvataggio stato ledPin in EEPROM*/
          int lettura = digitalRead(outPin);
          if (lettura == 1 && lastbuttonState == 0) {
           EEPROM.write(0,1);// salvo stato ON
           delay(40); 
           lastbuttonState = lettura; // aggiorno variabili   
          }

          if(lettura == 0 && lastbuttonState == 1) { 
           EEPROM.write(0,0);// salvo stato OFF
           delay(40);
           lastbuttonState = lettura; // aggiorno variabili              
          }
          /* Fine alvataggio stato ledPin in EEPROM*/

          /* Console di verifica*/
          Serial.print("lastbuttonState = ");
          Serial.println(lastbuttonState);
          Serial.print("EEPROM = ");
          Serial.println (EEPROM.read(0));
          Serial.print ("outPin = ");
          Serial.println (digitalRead(outPin));
          /* Fine console di verifica*/

          client.println("HTTP/1.1 200 OK....."); // COSTRUZIONE PAGINA HTML
          client.println("Content-Type: text/html");
          client.println();

          client.print("<html><head><title>ARDUINO Controllo Led via WEB</title><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' ></head><div align='center'><body><body text='blue'>");
          //client.println("<div style='width:360px; height:640px;'>"); risoluzione per nokia 5800 640x360
          client.println("<h1>STATUS SENSORI</h1><hr />");

          client.println("<p>TEMPERATURA = "); //Scrive sul browser il valore del termistore
          client.print(temp);
          client.println(" C 
</p>");

          if (temp < tempreg) { // Scrive sul web caldo/freddo se il valore del termistore è alto/basso
           client.print("<p><strong>FREDDO</strong></p>");
          }
          else {
           client.print(" <p><strong>CALDO</strong></p>");
          }

          client.println("<p>LUCE = "); //Scrive sul browser il valore della fotoresistenza
          client.print(analogRead(light));
          client.println("
</p>");

          if (light < 150) { // Scrive sul web luce/buio se il valore della fotoresistenza è alto/basso
           client.print("<p><strong>LUCE</strong></p>");
          }
          else {
           client.print(" <p><strong>BUIO</strong></p>");
          }

          client.print("<h2>AGGIORNA SENSORI: <a href=''>CHECK</a></h2><hr />"); // link per aggiornare pagina e valori
          client.println("<h1>CONTROLLO ATTUATORI REMOTI</h1>");
          client.println("<hr/>");
          client.print("<h1>USCITA n. ");
          client.print(outPin);
          client.println("</h1>");
          client.println("
");

          client.print("<font size='5'>STATO: ");//Scrivo il LED status
          if (LEDON) {
            client.println("<span style='color:green; font-weight:bold;'>ON</span></font>");
          }
          else {
           client.println("<span style='color:grey; font-weight:bold;'>OFF</span></font>");
          }
          client.print("<h2><a href='/?L=1'>ACCENDI</a> | <a href='/?L=0'>SPEGNI</a></h2>");
          client.println("</body></div></html>");

          readString=""; // Pulisco la stringa per la successiva lettura
          client.stop(); //Fermo il client
        } //if c == /n
      } // if client available
    } // while client connesso
  } // Fine if client
 
  if (temp < tempreg) { // accendo/spengo un led se la temperatura è più bassa/alta di quella di controllo
   digitalWrite(ledPintemp, HIGH);
  }
  else {
   digitalWrite(ledPintemp, LOW);
  }
 
  if (light < 150) { // Accendo/spengo un led se la non/c'è luce
   digitalWrite(ledPinlux, HIGH);
  }
  else {
   digitalWrite(ledPinlux, LOW);
  }
} // fine loop

Quello che proprio non riesco a capire è come creare una funzione da poter richiamare che mi permetta di rendere più leggibile il listato.
Il blocco di codice incriminato è il seguente:

/* Salvataggio stato ledPin in EEPROM*/
          int lettura = digitalRead(outPin);
          if (lettura == 1 && lastbuttonState == 0) {
           EEPROM.write(0,1);// salvo stato ON
           delay(40); 
           lastbuttonState = lettura; // aggiorno variabili   
          }

          if(lettura == 0 && lastbuttonState == 1) { 
           EEPROM.write(0,0);// salvo stato OFF
           delay(40);
           lastbuttonState = lettura; // aggiorno variabili              
          }
          /* Fine alvataggio stato ledPin in EEPROM*/

Di fatto sono entrato da poco in questo universo e sto cercando di imparare ma alle volte gli esempi generici non bastano… abbiate pazienza…
Grazie

Mi pare che tutte le variabili siano dichiarate all'inizio (globali) perciò puoi fare una cosa molto semplice, spostare tutto quel codice in una funzione void a cui dai il nome che vuoi e al posto dov c'era quel codice scrivi solo il nome di quella funzione.

void SalvaStato()
{  /* Salvataggio stato ledPin in EEPROM*/
          int lettura = digitalRead(outPin);
          if (lettura == 1 && lastbuttonState == 0) {
           EEPROM.write(0,1);// salvo stato ON
           delay(40); 
           lastbuttonState = lettura; // aggiorno variabili   
          }

          if(lettura == 0 && lastbuttonState == 1) { 
           EEPROM.write(0,0);// salvo stato OFF
           delay(40);
           lastbuttonState = lettura; // aggiorno variabili              
          }
          /* Fine alvataggio stato ledPin in EEPROM*/
}

Dove c'era questo codice metti solo:

...
  SalvaStato();        //richiama la SalvaStato
...

Ti ringrazio per la "solitaria" risposta :slight_smile:

Ho provato e funziona a meraviglia ma ora vorrei capire, se hai la pazienza di spiegarmelo, se io avessi avuto una variabile non globale ma locale.
P.es se la variabile

int lastbuttonState = 0;

che ho definito come globale ma di fatto serve solo a questo blocco di codice l'avessi definita solo all'interno della funzione?
Mi avrebbe dato errore sicuramente dato che c'è una riga che richiama questa variabile e precisamente quella nella riga 3

          /* Console di verifica*/
          Serial.print("lastbuttonState = ");
          Serial.println(lastbuttonState);
          Serial.print("EEPROM = ");
          Serial.println (EEPROM.read(0));
          Serial.print ("outPin = ");
          Serial.println (digitalRead(outPin));
          /* Fine console di verifica*/

Lo scopo è quello di capire il meccanismo per creare delle funzioni che essendo magari ripetitive non "sporchino" il codice con una valanga di dichiarazioni che andrebbero a complicare la lettura gia di per se (nel mio caso) un po' faticosa...

Se una variabile serve solo all’interno di quel blocco, allora la puoi dichiarare nella funzione e quindi toglierla dalle dichiarazioni iniziali.
Se quella variabile però serve anche ad altri punti del programma allora NON può essere locale.

  • Una variabile locale ha visibilità solo nella funzione e vita solo nella funzione (nasce quando viene richiamata la funzione e muore quando la funzione finisce).
  • Una variabile globale ha visibilità ovunque nel programma e vita legata al programma.

Eventualmente si può usare il passaggio di parametri alle funzioni (ma fossi in te affronterei questo argomento successivamente, è un argomento che può creare confusione).

Quindi nel mio esempio un' ulteriore strada oltre a quelle percorse è quella con il passaggio dei parametri alla funzione... E' questo aspetto che cercavo di capire ma non pretendo che tu mi faccia un corso... grazie comunque. :wink:

Franchellio:
Quindi nel mio esempio un’ ulteriore strada oltre a quelle percorse è quella con il passaggio dei parametri alla funzione… E’ questo aspetto che cercavo di capire ma non pretendo che tu mi faccia un corso… grazie comunque. :wink:

Non c’e’ problema. Io però ti consiglierei prima di capire come organizzare il codice “spezzandolo” in più funzioni senza parametri.

Per i parametri, di base, c’e’ solo un piccolo particolare molto importante da tenere in considerazione; la variabile che gli passi, la nella funzione la usi solo (quindi è solo in lettura) oppure la devi anche modificare e fare in modo che venga modificata “per tutti” ?
Questo è una differenza fondamentale. Normalmente le variabili numeriche (char, byte, int, long, float) vengono passate alla funzione come copia, quindi non puoi modificare il valore globale della variabile all’interno della funzione stessa.

infatti sto cercando proprio di fare quello che dici tu ma avevo bisogno di una visione più generale del problema che devo affrontare.
Le variabili passate in "ingresso" sono unidirezionali mentre il risultato della funzione deve essere scritto in una variabile esterna che va dichiarata prima. È giusto?

Quasi. Le variabili in ingresso sono unidirezionali ma si possono eventualmente fare anche bidirezionali usando i puntatori (per ora lascia stare).

Una funzione può avere un valore di ritorno ma non è obbligatorio.

void MyFunzA() {}
int  MyFunzB() {  return 0; }

In questo pezzo di codice, 2 funzioni la A non ritorna nulla perciò quel void.
La funzione B invece deve ritornare un valore (attraverso il comando return). In questo esempio ho deciso di far “uscire” dalla funzione un valore numerico intero e perciò davanti ho messo int.