La mia prima volta

La mia prima volta in C++
tutto è nato da una richiesta che sembra volere un albero di natale:
https://forum.arduino.cc/index.php?topic=614683.msg4165864#msg4165864
dopo un po' di discussioni avevo ottenuto una cosa decente (almeno secondo me) con strutture e array e for e tutto il circo
poi qualcuno (quasi più bravo di me) mi ha "rubato" 12 byte di variabili
e adesso, per non sporcare il trhead (si scriverà così?)
per non sporcare la discussione, come consigliato, apro questa nuova discussione con una proposta di programma, che fa uso di strutture, array, cicli e...

(rullo di tamburi...) Super trooper puntati su di me , grazie

una funzione dentro una struttura

(mamme, allontanate i bambini, sta arrivando l'anticristo, l'imperatore Palpatine, il cattivo definitivo...
Sarò dannato per l'eternità, ho scritto roba C++, pur se "truccata" da 'C'

// di Nelson StandardOil
// Idea da sviluppare:
// 6 luci casuali

typedef struct
{
    byte pin; // pin associato alla luce
    unsigned long int tempo; // ultimo tempo di commutazione
    unsigned int periodo; // intervallo per commutare
    void lampeggia(void)
    {
        // per sapere se deve lampeggiare
        if (millis() - tempo > periodo && periodo)
        {
            tempo = millis();
            digitalWrite(pin , !digitalRead(pin)) ;
        }
    }
} Luce; // la struttura che descrive il singolo canale di luci

Luce luci[] = {{2, 0, 0}, {3, 0, 0}, {4, 0, 0}, {5, 0, 0}, {6, 0, 0}, {7, 0, 0}};
#define LUCI  sizeof(luci) / sizeof(luci[0]) //era #define LUCI 6 
#define PUL 8 // pulsante

void setup(void)
{
    for (byte i = 0; i < LUCI; i++)
    {
        pinMode(luci[i].pin, OUTPUT);
    }
}

void loop(void)
{
    if (digitalRead(PUL))
    {
        randomSeed(millis());

        for (byte i = 0; i < LUCI; i++)
        {
            luci[i].periodo = random(50, 700);
        }
    }

    for (byte i = 0; i < LUCI; i++)
    {
        luci[i].lampeggia();
    }
}
Lo sketch usa 1526 byte (4%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 55 byte (2%) di memoria dinamica, lasciando altri 1993 byte liberi per le variabili locali. Il massimo è 2048 byte.

sono passato al lato oscuro.....
Che K&R abbiano pietà della mia tastiera................

Non sapevo che si potesse inserire una funzione all'interno di una struct in c++, ho imparato qualcosa :wink:

Faccio una riflessione poi non so come il linguaggio e compilatore si comporta.
Ho un array di strutture contenente una funzione, se il linguaggio si comporta con le funzioni come un comune altro campo, vuol dire che in memoria la funzione è ripetuta per il numero degli elementi "non so se sia cosi effettivamente".

Allora penso che si potrebbe usare una comune funzione con parametri, alla normale funzione passo il pin e il periodo della struct.

Sì puoi usare una comune funzione, ma il programma usa 2 byte in più, non so perché
In cpp struct e classi sono come in c array e puntatori: due facce della stessa medaglia
Per il poco che ne so io ho creato una classe, con una funzione membro
Ma la ho "vestita" da C
Sono comunque sicuro che le funzioni membro di strutture non sono duplicate
Sarebbe duplicato un membro puntatore a funzione, ma non è quello che ho scritto
Poi aspettiamo gente che il cpp lo conosce meglio di me

Cioè tu sei passato al lato oscuro per soli due byte?
Ma quanto costa la sram dalle tue parti?

Questa era la mia soluzione:

#define countItem(x) (sizeof(x) / sizeof(x[0]))
#define btnPin 8

struct led {
  byte pin;
  bool state;
  unsigned int interval;
  unsigned long previous;
};

struct led leds[] = {
  {2, 0, 0, 0},
  {3, 0, 0, 0},
  {4, 0, 0, 0},
  {5, 0, 0, 0},
  {6, 0, 0, 0},
  {7, 0, 0, 0}
};

void setup() {
  for (byte i = 0; i < countItem(leds); i++) {
    pinMode(leds[i].pin, OUTPUT);
  }
}

void loop() {
  unsigned long current = millis();

  if (digitalRead(btnPin) == HIGH) {
    randomSeed(current);
    for (byte i = 0; i < countItem(leds); i++) {
      leds[i].interval = random(100, 700);
    }
  }

  for (byte i = 0; i < countItem(leds); i++) {
    if (current - leds[i].previous > leds[i].interval && leds[i].interval) {
      leds[i].previous = current;
      leds[i].state = (leds[i].state == LOW ? HIGH : LOW);
    }
    digitalWrite(leds[i].pin, leds[i].state);
  }
}

anche se è più corto del tuo :wink:

Lo sketch usa 1596 byte (4%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.
Le variabili globali usano 61 byte (2%) di memoria dinamica, lasciando altri 1987 byte liberi per le variabili locali. Il massimo è 2048 byte.

È il membro booleano che ti frega 6 byte di ram
Io non lo ho usato
Per il resto, diversa formattazione a parte, sembrano scritti dalla stessa persona
Io ne sono contento, dato che non sono un professionista come te

Standardoil:
Per il poco che ne so io ho creato una classe, con una funzione membro

Non conosco bene C/C++, ma se la struct (come in Net) è "simile" ad una classe, allora hai effettivamente creato una classe con un metodo (la funzione).

In C# sarebbe qualcosa del genere:

  public struct persona
  {
    public string cognome;
    public string nome;
    public string getNomeCompleto()
    {
      return nome + " " + cognome;
    }
  }

Standardoil:
È il membro booleano che ti frega 6 byte di ram

Proverò ad ottimizzare, grazie

Standardoil:
Per il resto, diversa formattazione a parte, sembrano scritti dalla stessa persona

E no, qui sono un Newbie, ma sto migliorando :slight_smile:

Struct e classi sono esattamente la stessa cosa in C++. L'unica differenza riguarda la visibilità di default, che è private per le classi e public per le struct.

Ovviamente il codice non viene replicato in RAM (anche perché sta in flash...), visto che comunque è uguale per tutte le istanze della classe, mentre i dati possono essere diversi.

Il C++ è un linguaggio complicato e poco adatto ai microcontrollori. Tuttavia, usarlo cum grano salis (cosa nemmeno poi difficile, visto che non si hanno a disposizione STL e Boost, su Arduino), può giovare (= far risparmiare risorse e/o scrivere codice più pulito e mantenibile) in parecchie situazioni.

Per sukko
Stl so cosa che è
Ma boost?
Per Federico invece
Io non ho usato il membro bool perché leggo lo stato del piedino, ma è uno sporco trucco che funziona solo su alcune macchine e solo se al piedino è collegato solo un carico puro, non cose pullupate o anche pulsanti o cose strane, giusto un led

La libreria più pesante del mondo.

Standardoil:
Io non ho usato il membro bool perché leggo lo stato del piedino, ma è uno sporco trucco che funziona solo su alcune macchine e solo se al piedino è collegato solo un carico puro, non cose pullupate o anche pulsanti o cose strane, giusto un led

infatti mi stavo interrogando su questa riga, e volevo appunto testarla

digitalWrite(pin , !digitalRead(pin)) ;

grazie per l'info

SukkoPera:
La libreria più pesante del mondo.

infatti ho aperto il link, e l'improvviso aumento di peso mi ha strappato di mano il furbofono...

Proseguo qui, per non sporcare più la discussione gemella
Per chi mi avesse seguito, la maniera di far partire da spente le luci, fino alla prima pressione del pulsante, la prima pensata intendo,
Non era un test, ma semplicemente inizializzare i tempi di avvio a una miliardata di secondi
Pur se formalmente il timer corre, a tutti gli effetti pratici è bloccato spento
Per fare questo non servono conoscenze di programmazione, non stavo bullizzando nessuno.
È solo un modo di pensare laterale

Con un ulteriore effetto benefico, calcolando il tempo medio di anticipo di preparazione dell'albero e il limite massimo di millis, dovresti arrivare che se non pigi mai start e non spegni mai il trespolo, le luci si avviano automaticamente la sera della vigilia :wink:

È il membro booleano che ti frega 6 byte di ram

Già, potrebbe risparmiare 1 byte per led se usasse un solo byte per salvare pin e stato.
Stato pin
bit-7 bit-0÷6

ma dovrebbe usare una union o bitfield oppure semplicemente bitwise.

Il prossimo passo è di vedere cosa si guadagna a non usare digitalRead e digitalWrite, le due dovrebbero sparire da dentro il firmware riducendone la dimensione, però per ogni pin serve indirizzo (16bit) e bit (8 bit), quindi 3 byte per led.

Ciao.

Maurotec:
Già, potrebbe risparmiare 1 byte per led se usasse un solo byte per salvare pin e stato.
Stato pin
bit-7 bit-0÷6
ma dovrebbe usare una union o bitfield oppure semplicemente bitwise.

Avevo pensato a bitwise, ma non c'era sentore di gara, quindi o scelto la semplicità :slight_smile:
Magari dopo provo.

Mi state leggendo nel pensiero, non vale, anche io pensavo a condensare usando i bit :wink:

Senza bitshit (o era bitshift?) ne bitwise ne bitfield (a me i bit mi stanno sulle...)
per comandare il led
DigitalWrite (pin/2 , pin%2)
per cambiare lo stato
Pin =pin+!(pin%2)
Edit non va
Ci ripenso dopo pappa
Pensato ci ho
Pin = pin -(pin%2) + !(pin%2)

Ma questo è un esercizio di ottimizzazione fine a sé stesso o pensate veramente che abbia senso fare cose di questo genere? :confused: