Ottimizzazione del codice

Sto scrivendo questo sketch per una centralina pirotecnica che funziona a distanza tramite il modulo nrf24l01.
Considerando che ho già utilizzato il 70% dello spazio dedicato alle variabili e ancora non ho implementato nulla per la comunicazione tra il modulo di trasmissione e quello di ricezione e detonazione, non so se mi basterà lo spazio.
Considerando che sono circa 10 giorni che ho messo le mani su Arduino credo che questo codice possa essere ottimizzato per risparmiare spazio, se qualcuno saprebbe indicarmi come gli sarei molto grato.

#include <RF24.h>
#include <SPI.h>
#include <nRF24L01.h>

RF24 radio(7,8);
const byte address[6] = "00001";
char c;
String stringa;
String password = "123456";


//variabili canali detonazione
int c1 = 0;
int c2 = 0;
int c3 = 0;
int c4 = 0;
int c5 = 0;
int c6 = 0;
int c7 = 0;
int c8 = 0;

void reset(){

  c1 = 0;
  c2 = 0;
  c3 = 0;
  c4 = 0;
  c5 = 0;
  c6 = 0;
  c7 = 0;
  c8 = 0;
}

void detonazione(){
  while (!Serial.available()){
    delay(1000);//attesa di valori seriale  
  }
      if (Serial.available()) {
        stringa = ""; 
        do {
          if(Serial.available()){
            c=Serial.read();
            if(c != '\n')
            stringa +=c;
          }
        }while(c != '\n');
      //Serial.println(stringa);

    if (stringa == "c1" && c1 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c1 = 1;
      delay(2000);
      
    }

    else if(stringa == "c1" && c1 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c1 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c2" && c2 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c2 = 1;
      delay(2000);
      
    }

    else if(stringa == "c2" && c2 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c2 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c3" && c3 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c3 = 1;
      delay(2000);
      
    }

    else if(stringa == "c3" && c3 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c3 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c4" && c4 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c4 = 1;
      delay(2000);
      
    }

    else if(stringa == "c4" && c4 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c4 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }


    if (stringa == "c5" && c5 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c5 = 1;
      delay(2000);
      
    }

    else if(stringa == "c5" && c5 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c5 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c6" && c6 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c6 = 1;
      delay(2000);
      
    }

    else if(stringa == "c6" && c6 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c6 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c7" && c7 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c7 = 1;
      delay(2000);
      
    }

    else if(stringa == "c7" && c7 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c7 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }

    if (stringa == "c8" && c8 == 0){
      Serial.println("");
      Serial.println("Detonazione in corso...");
      Serial.println("");
      Serial.println("");
      c8 = 1;
      delay(2000);
      
    }

    else if(stringa == "c8" && c8 == 1){
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione sul canale c8 già eseguita!!");
      Serial.println("");
      Serial.println("");
    }


}
}
void pass(){
  Serial.println("********************CENTRALINA PROTETTA DA PASSWORD******************** ");
  Serial.println("");
  Serial.println("");
  while(stringa != password){
    Serial.println("Inserire password: [6 caratteri]");
    Serial.println("");
    while (!Serial.available()){
      delay(1000);//attesa di valori seriale  
    }
        if (Serial.available()) {
          stringa = ""; 
          do {
            if(Serial.available()){
              c=Serial.read();
              if(c != '\n')
              stringa +=c;
            }
          }while(c != '\n');
        //Serial.println(stringa);
        
      if(stringa != password){
      Serial.println("Password errata!!");
      Serial.println("");
      }

    }
  }
  if(stringa == password){
    Serial.println("Password corretta");
    Serial.println("");
    Serial.println("");
    Serial.println("********************CENTRALINA PIROTECNICA A 8 CANALI********************");
    Serial.println("");
    Serial.println("");
  }

  
}


void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
  reset();
  pass();
  
}
void menup(){

  Serial.println("********************MENÙ********************");
  Serial.println("1)Modalità detonazione");
  Serial.println("2)Resoconto detonazioni");
  Serial.println("3)Resetta detonazioni");
    
  
}

void resoconto(){
  Serial.println("");
  Serial.print("Canale 1 (c1) ");
  Serial.print(c1);
  Serial.println("");
  Serial.print("Canale 2 (c2) ");
  Serial.print(c2);
  Serial.println("");
  Serial.print("Canale 3 (c3) ");
  Serial.print(c3);
  Serial.println("");
  Serial.print("Canale 4 (c4) ");
  Serial.print(c4);
  Serial.println("");
  Serial.print("Canale 5 (c5) ");
  Serial.print(c5);
  Serial.println("");
  Serial.print("Canale 6 (c6) ");
  Serial.print(c6);
  Serial.println("");
  Serial.print("Canale 7 (c7) ");
  Serial.print(c7);
  Serial.println("");
  Serial.print("Canale 8 (c8) ");
  Serial.print(c8);
  Serial.println("");
  Serial.println("");
  Serial.println("");
  

}
void loop() {
  menup();
  while (!Serial.available()){
    delay(1000);//attesa di valori seriale  
  }
  if (Serial.available()) {
    stringa = ""; 
    do {
      if(Serial.available()){
        c=Serial.read();
        if(c != '\n')
        stringa +=c;
      }
    }while(c != '\n');
      //Serial.println(stringa);
    if(stringa == "1"){
      Serial.println("");
      Serial.println("");
      Serial.println("********************MENÙ DI DETONAZIONE********************");
      Serial.println("");
      Serial.println("");
      Serial.println("Per avviare la detonazione inserisci la lettera c seguita dal numero del canale(c1,c2...)");
      detonazione();

  
    }
    else if(stringa == "2"){
      Serial.println("");
      Serial.println("");
      Serial.println("********************MENÙ DETONAZIONI GIÀ ESEGUITE********************");
      Serial.println("");
      Serial.println("");
      Serial.println("Detonazione già eseguita = 1");
      Serial.println("");
      Serial.println("Detonazione da eseguire = 0");
      resoconto();
    }
    else if(stringa == "3"){
      Serial.println("");
      Serial.println("");
      Serial.println("Sei sicuro di voler resettare?(s/n)");
      Serial.println("");
    
      while (!Serial.available()){
        delay(1000);//attesa di valori seriale  
      }
      if (Serial.available()) {
        stringa = ""; 
        do {
          if(Serial.available()){
            c=Serial.read();
            if(c != '\n')
            stringa +=c;
          }
        }while(c != '\n');
        //Serial.println(stringa); 

         

      if(stringa =="s" || stringa == "S"){
        reset();
        Serial.println("");
        Serial.println("Detonazioni resettate");
        Serial.println("");
        Serial.println("");
      }
      
      }
    }
  }
}



Buongiorno e benvenuto nella sezione Italiana del forum,

cortesemente, come prima cosa, leggi attentamente il REGOLAMENTO di detta sezione, (... e, per evitare future possibili discussioni/incomprensioni, prestando molta attenzione al punto 15), dopo di che, come da suddetto regolamento (punto 16.7), fai la tua presentazione NELL'APPOSITA DISCUSSIONE (... quello che vedi in blu è un link, fai click su di esso per raggiungere la discussione) spiegando bene quali esperienze hai in elettronica e programmazione, affinché noi possiamo conoscere la tua esperienza ed esprimerci con termini adeguati.

Grazie,

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposita discussione, nel rispetto del succitato regolamento nessuno ti risponderà (eventuali risposte o tuoi ulteriori post, verrebbero temporaneamente nascosti), quindi ti consiglio di farla al più presto. :wink:

Buongiorno, mi era sfuggita la presentazione :sweat_smile:.
Ho appena provveduto a farla.

Stai usando una gran quantità di "literal string" che scritte in questo modo vengono tutte inutilmente caricate nella poca SRAM disponibile.

Se usi la macro F() le stringhe invece verranno caricate dalla memoria flash e liberi molte risorse che al momento sono inutilmente impegnate.

Serial.println("********************CENTRALINA PIROTECNICA A 8 CANALI********************");

diventa

Serial.println(F("********************CENTRALINA PIROTECNICA A 8 CANALI********************"));

Serial.println("") è equivalente nel risultato a Serial.println() ed eviti di creare una variabile string vuota (ammesso che non ci pensi già il compilatore ad ottimizzare).

In linea generale, stai usando il microcontrollore soprattutto per stampare sulla seriale delle informazioni di debug che a progetto finito con tutta probabilità non ti serviranno più a nulla.

In questi casi l'approccio più comune è inserire delle macro che vengono risolte in fase di compilazione. In questo modo quando hai finito con i vari test, ti basta disabilitare il debug ed il codice relativo non verrà più inserito nel tuo compilato.

#define DEBUG_ENABLE true
#define DEBUG_PORT Serial

#if DEBUG_ENABLE
  #define debug_begin(x) DEBUG_PORT.begin(x)
  #define debug_print(x) DEBUG_PORT.print(x)
  #define debug_println(x) DEBUG_PORT.println(x)
#else
  #define debug_begin(x)
  #define debug_print(x) 
  #define debug_println(x)
#endif

1 Like

ci sono alcune cose che non sono ideali
oltre alla grande quantità di stampe, che consumano molta ram

tu gestisci 6 pulsanti con 6 set di operazioni uguali su 6 set di variabili
usa un set di array di dimensione 6 e ciclali in un singolo for
risparmierai codice, variabili di stampa e renderai il programma più leggibile, meno prono a problemi e più manutenibile
se ti interessa ti faccio un esempio

1 Like

Grazie per il tuo consiglio sulla macro F() e per Serial.println(), riscrivendo il codice così sono passato da un 70% di memoria occupato al 14%!!
Però non ho ben capito cosa intendevi alla fine per le informazioni di debug , se potresti spiegarmelo meglio te ne sarei davvero grato, chissà potrebbe tornarmi utile in futuro.

Se mi potessi fare un esempio te ne sarei davvero grato perché non ho ben capito cosa intendi :sweat_smile:

Parlo delle stringhe che stai stampando sul monitor seriale.
Saranno utili anche a progetto completato, oppure le stai usando solo adesso nella fase di sviluppo per capire cosa succede?

1 Like

Servono nel progetto finale per ricordare all'utente quali canali sono già stati detonati.

Io, solo come indicazione, userei un metodo del genere, molto più diretto
non va, non è completo ne compilabile, ma vale come esempio

rispetto al tuo ho:
usato define inveee di costanti
usato variabili byte per numeri interi piccoli
usato un array di canali, invece di uno sbordello di variabili singole
usato un for per leggere e ripetere la stessa azione su tanti canali
semplificato il comando di lancio (un solo carattere invece di 2)
l'uso di array implica che il primo canale è 0, abituati, vale sempre in C

se ti ispiri a questo puoi facilmente ridurre il programma e le variabili

il controllo di password ed eventualmente l'aggiunta di un pre-comando di lancio (c1,invece di 1 e basta) è semplice, se hai capito l'idea

#include <RF24.h>
#include <SPI.h>
#include <nRF24L01.h>

RF24 radio(7, 8);
#define ADRESS "00001" //invece di consumare ram per costanti, usare il precompilatore
char c;
//String stringa; mai usare string
#define PASSWORD "123456" // se la vuoi costante
char password[] = "123456"; // se la vuoi modificabile


//variabili canali detonazione
byte channel[8]; // usare array, e usare byte per contenere numeri piccoli


void reset()
{
   for (byte i = 0; i < sizeof channel / sizeof channel[0]; i++)
   {
      channel[i] = 0
   }
}

void detonazione()
{
   /* //while (!Serial.available())
      {
      // delay(1000);//attesa di valori seriale // ci sono metodi migliori e più affidabili, questa parte la devi ristudiare ex-novo
      }

      if (Serial.available())
      {
       stringa = "";

       do
       {
          if (Serial.available())
          {
             c = Serial.read();

             if (c != '\n')
             {
                stringa += c;
             }
          }
       }
       while (c != '\n');

       //Serial.println(stringa);
   */
   // ad esempio
   if (Serial.available())
   {
      char c = serial.read();

      if (c >= '0' && c <= '9')
      {
         c = c - '0';

         for (byte i = 0; i < sizeof channel / sizeof channel[0]; i++)
         {
            if (i == c)
            {
               Serial.print("detonazione sul canale: ");

               if (!c)
               {
                  Serial.println();
                  Serial.print(c + '0');
                  Serial.println(" in corso");
                  c = 1;
               }
               else
               {
                  Serial.print(c - '0');
                  Serial.println(" gia' eseguita")

                  // assicuriamoci di svuotare la seriale
                  while (Serial.available())
                  {
                     Serial.read();
                  }

                  delay(2000)
               }
            }
         }
      }
   }
}
void pass()
{
   Serial.println("********************CENTRALINA PROTETTA DA PASSWORD******************** ");
   Serial.println("");
   Serial.println("");

   // anche qui ti devi studiare un meccanismo differente

   while (stringa != password)

Ti ringrazio dei tuoi consigli, nei prossimi giorni proverò a riscrivere il codice :slightly_smiling_face:

concorquoto (TM) in pieno

inoltre mi permetto una piccola disquisizione teorica sui cicli per ciclare gli array
premetto subito che su Arduino non abbiamo spazio per vector e altri container tipici di C++
però alcuni automatismi di C++ esistono
in particolare per scorrere automaticamente gli array
basta usare il "foreach loop" chiamato anche "range-based for loop"

una cosa così:

byte impulso[] = {1, 3, 5};

void setup(void)
{
   pinMode(13, OUTPUT);
   Serial.begin(9600);
}

void loop(void)
{
   for (auto i : impulso)
   {
      Serial.println(i);
.
.
.

noterete che il serialprint stampa il valore dell'element dell'array e non il suo indice
e che non serve conoscere la dimensione dell'array, ma solo il suo nome

ora questa cosa non è molto adatta al nostro caso di attuale di oggi, perchè non ci permette di stampare il "numero" del canale acceso

vero è che si potrebbe usare una struttura, o meglio un array di strutture, che contenga come membro il "numero ordinale" della singola struttura, ma è un overkill

e allora ho tirato fuori dalla mia libreria privata di macro utili una macro utile (lapalissiano)

la macro foreach(nome_indice, nome_array)

che fa quasi la stessa cosa del "range based for", ma ci permette di avere accesso all'indice di scorrimento dello array (e non crea una variabile temporanea di tipo pari al tipo base dell'array, se vi serve ve la create voi con un "auto nome array[indice]")

eccola, la miracolosa macro del $prode cavaliere$

#define foreach(indice, vettore) for (byte indice; indice < sizeof vettore / sizeof vettore[0]; indice++)

come vedete, siccome sia il nome dell'indice che il nome dell'array sono passati come parametro permette di conoscere il valore dell'indice attuale E, molto importante questo, anche di usarla nidificata in se stessa, per ciclare e sotto_ciclare più array o anche array multidimensionali

ecco un esempio d'uso, piuttosto base
che mostra come usare l'indice dell'array e anche l'elemento "attualmente ciclato" dell'array

#define foreach(indice, vettore) for (byte indice; indice < sizeof vettore / sizeof vettore[0]; indice++)

byte impulso[] = {1, 3, 5};

void setup(void)
{
   pinMode(13, OUTPUT);
   Serial.begin(9600);
}

void loop(void)
{
   for (auto i : impulso)
   {
      Serial.println(i);

      for (byte j = 0; j < i; j++)
      {
         digitalWrite(13, 1);
         delay(75);
         digitalWrite(13, 0);
         delay(75);
      }

      delay(350);
   }

   foreach (i, impulso)
   {
      Serial.print(i);
      Serial.print(" ");
      Serial.println(impulso[i]);

      for (byte j = 0; j < impulso[i]; j++)
      {
         digitalWrite(13, 1);
         delay(75);
         digitalWrite(13, 0);
         delay(75);
      }

      delay(350);
   }
}

copiatevi la macro da qualche parte, che potrebbe esservi utile

cosa ne dite, sono di nuovo il mago delle macro?

PS
Per i moderatori:
Mi riaprite "la pappa è fatta"?

Che la aggiungo
Grazie

Ciao, ho letto tutti i post e credo che la soluzione per questa applicazione sia un shell seriale.
Cioè una interfaccia a comandi simile a questa su wokwi:

Per testarla nella console seriale in basso inserisci il comando:
srv,15 e premi invio.
Il servo si sposterà alla posizione di 15°

Nota che ci sono altri post sul forum sull'argomento e basta cercare sercmd di @gpb01.

Ciao.

C'è un intero thread dedicato alla libreria ... QUI. :slight_smile:

La si trova su ovviamente anche su GitHub.

Guglielmo

Fatto :slight_smile:

Guglielmo

P.S.: ... però, usa il @gpb01 ... perché così ricevo una notifica ... altrimenti, se non vedevo il tuo post, non ne sapevo nulla :wink:

Non reputavo valesse la pena di disturbarti apposta...

... ma dato che, più o meno, l'unico moderatore rimasto di lingua Italiana è il sottoscritto ... se non mi chiami in causa rischi che io non noto il post e ... campa cavallo ... :wink:

Guglielmo

Tempo fa cercavate alternative

Mai trovate ?

... caduto tutto nel dimenticatoio :roll_eyes:

Guglielmo

Guglielmo, tu sei preciso equilibrato e giustamente intransigente, quindi nessuno si sente sufficientemente qualificato e all'altezza quando viene confrontato con te😁