Inizializzazione pin arduino

Salve a tutti, oggi vi pongo una domanda davvero niubbissima, come sempre giusto per capire. Vedendo gli sketch presenti in rete ho notato che i pin di arduino vengono inizializzati in maniera differente anche se sostanzialmente credo la funzione sia sempre la stessa ad esempio:

const int ledPin = 13;
int ledPin = 13;
#define ledPin 13

Che differenza c'è nell'usare le tre varianti proposte?

solo lo spazio dedicato nella ram a quella variabile ma tutte e 3 i modi assegnano il numero 13 alla variabile, il migliore e #define ledPin 13

ciao

solo int ledPin = 13 alloca 2bytes di ram, gli altri 2 sono "gratis"

la documentazione è in fase di aggiornamento per adottare
const int ledPin = 13; come standard

abbiamo abbandonato #define perchè ha una sintassi un po' ostica per un principiante

m

Per correttezza d'informazione:

nessuno degli esempi postati definisce un pin di Arduino ma solo una variabile o costante che, per convenzione, ne indica l'indirizzo fisico (il numero del pin). Potrei benissimo chiamare il pin "Pippo", assegnargli un valore e poi utilizzarlo per definire il modo di utilizzo del pin fisico interessato. Es:

const char Pippo = 13;
void setup() {
** pinMode(Pippo, OUTPUT); // sets the digital pin as output**
}

Nel contesto di Arduino la migliore definizione del pin di fatto sarebbe questa:

pinMode( 13, OUTPUT);

in questo caso non c'è alcun utilizzo di ram ma solo un byte nella memoria di programma di Arduino (sempre che la funzione pinMode() sia stata definita correttamente come pinMode(char pin, char mode) e non pinMode(int pin, int mode). Cosa ignota in quanto gli amici del gruppo di Arduino, forse per evitare "sintassi troppo ostiche per un principiante", hanno preferito non usare la buona norma di indicare nella documentazione ufficiale anche i prototipi di funzione... )

L'utilizzo di:

int ledPin = 13;

e di:

const int ledPin = 13;

sono deprecabili per i seguenti motivi:

  • il primo vede l'uso non necessario di 2 byte in rom e 2 byte in ram, e, a meno che la variabile ledPin non venga riassegnata nel programma, risulta un'inutile spreco di ram (perchè di fatto inutilizzata);

  • Il secondo vede l'uso di 2 byte in rom quando ne è sufficiente uno solo.

Per chi non lo sapesse: il definire una variabile con il suffisso const (costante) determina che la variabile viene definita come valore immodificabile posto nella memoria rom (ovvero quella dove risiedono le istruzioni del programma). Questo fa si che non sia duplicata inutilmente la stessa informazione anche in ram.
Questo accorgimento risulta molto utile in quanto Arduino è molto scarso di memoria ram (sopratutto nella sua versione "originale" che utilizza l'mpu ATMega328 che ha 32768 byte di memoria Flash (ROM) e 2048 byte di RAM), che è quella utilizzata per tutte le variabili definite nel programma e per ogni chiamata a una funzione (incluse le librerie pre installate e quelle caricate nel progetto).

Personalmente, rifacendomi alle specifiche ufficiale del C ANSI, preferisco la seguente definizione:

#define ledPin 13

in quanto specifica semplicemente una direttiva al preprocessore (la fase di precompilazione) indicando "ledPin" come valore costante e quindi implicitamente parte integrante del codice programma (e quindi con l'utilizzo ottimale in rom).

Concludo con un pensiero personale (e quindi soggettivo :wink: )

Il voler "risparmiare" al principiante la comprensione dei concetti base del C può servire sì a "semplificare" l'uso del sistema, ma con lo svantaggio di non fornire le informazioni basilari dell'uso di un linguaggio ufficiale. Se non si vuole che il principiante "vada troppo in confusione" forse sarebbe meglio implementare un linguaggio più semplice ed intuitivo come il Basic (come del resto qualcuno ha già fatto con i PIC, con tutte le limitazioni che ne conseguono...)

Molto interessante, mi permetto di aggiungermi e chiedo un chiarimento giusto per capire. Il C mi piace moltissimo,ma a volte c'è "troppa roba".
Ma con il define non si crea semplicemente un valore che il preprocessore sostituisce e quindi di fatto non si dovrebbe occupare nessuna memoria aggiuntiva nel programma?
Cioè durante la compilazione la "scritta" nel programma ledPin viene sostiuita con 13, quindi non mi è chiaro quel riferimento all'utilizzo ottimale in rom.
Grazie :slight_smile:

EDIT: fantastico ci sono arrivato da solo ;D

@DrAma78:

certo, il define è il modo per comunicare al compilatore (cioè al processo che traduce il codice programma direttamente nel linguaggio macchina del processore utilizzato) una serie di direttive che non fanno parte del programma vero e proprio. Nel caso del #define XX val altro non è che un assegnare ad un valore (val) un’etichetta mnemonica (XX) che serve solo al programmatore per comprendere meglio quello che sta facendo, ma dal punto di vista del programma questo non ha alcuna influenza.

Di fatto si tratta di un modo per rendere più semplice all’ “umano” la programmazione… ::slight_smile:

Il riferimento all’uso ottimale della rom è perchè il preprocessore sceglie in modo automatico il formato ideale del dato che viene definito in fase di dichiarazione (#define) che, nel nostro caso essendo < 256, diventa naturalmente un byte, e quindi l’ideale per consumare il meno possibile memoria senza doversi preoccupare della cosa (= ottimizzazione “trasparente” delle risorse :wink: )

Grande... era proprio questo.
Grazie

Grazie per le abbondanti spiegazioni ragazzi, non si finisce mai di imparare. A volte è bello vedere che dietro una semplice domanda c'è in realtà molto da scoprire.

alla fine cosa dobbiamo usare?
const xx val
define xx val
xx val

se rimane costante è indifferente fra le tue due prime scritture
se pensi di variarlo devi usare la terzache però è così
int yy = x;
dove yy è il nome che dai al pin e x il numero

per quelli costanti:
const int yy = x;
#define yy x

@milionario:

const xx val ti dovrebbe restituire un errore di sintassi, in quanto const non definisce il tipo di variabile ma solo se il valore risiede in rom, così come l'assenza del simbolo di assegnazione non è tollerato nel codice ma solo con #define

la definizione corretta sarà quindi:
const int xx = val;

Anche se, come ho già scritto sopra, l'uso di un int al posto di un char (o byte) corrisponde a buttar via un byte in memoria in quanto il tipo int occupa 2 byte mentre il char ne occupa uno solo!.

Ricordarsi sempre che nelle istruzioni al preprocessore (quelle precedute dal simbolo di cancelletto, ovvero: #) la sintassi è leggermente differente dal codice C!

P.S. volevo riportare qui tabella dei vari tipi e delle corrispondenti dimensioni in bit relative al C ANSI, ma inserire una tabella con l'editor di questo forum è una cosa da matti! :-/

la cosa migliore e fare direttamente pinMode(13, OUTPUT) :wink:

Ciao camba192
Sono d' accordo.
Il svantaggio é comunque quando usi i pin in tanti posti nel sketch e devi cambiare il pin devi cambiare il numero in tanti posti. Mentre se definisci una costante o una variabile basta modificarlo solo in un posto.
Il dare un nome aiuta anche a capire cosa fa il pin.
Ciao Uwe

si anche quello puo essere vero ma sui micro la ram e la memoria programma sono davvero limitate sempre meglio andare a risparmio :wink:

camba192

usare il numero del pin direttamente nella funzione non è la cosa migliore.

Dare un nome simbolico ai piedini è ottimo per diverse ragioni:

  1. il codice è più leggibile
  2. il tuo cervello non deve contiuamente cercare di ricordarsi a cosa corrispondono i numeri (specialmente se riprendi in mano il codice dopo settimane che non lo guardi)
  3. se vuoi spostare la connessione su un'altro piedino basta cambiare un numerino.. (ho visto decine di studenti fare un Search & Replace ed incasinare il codice)
  4. è piu facile adattare il codice se cambi scheda (dalla 2009 alla mega etc)

m

Visto che c'è ancora qualcuno con parecchi dubbi (e forse anche a causa della mia precisazione che ne può aver provocato qualcuno :wink: ), desidero indicare qual'è il mio personale metodo (e che considero il "migliore"), ovvero:

#define ledPin 13 // questo è un pin di uscita per il mio led
#define velocita 1000 // tempo di attesa nel lampeggio in milli secondi, + è grande e + è lento
void setup() {
pinMode(ledPin, OUTPUT); // imposto il pin di uscita per il led da far lampeggiare
}
void loop() //faccio lampeggiare il led
{
** digitalWrite(ledPin, HIGH); // accendo il LED facendo uscire corrente dal pin**
** delay(velocita); // aspetto del tempo**
** digitalWrite(ledPin, LOW); // spengo il LED togliendo la corrente dal pin**
** delay(velocita); // aspetto del tempo**
}

In questo modo non si consuma inutilmente memoria ed abbiamo il vantaggio di raggruppare tutte le definizioni dei vari pin e delle altre costanti in un'unica zona (all'inizio del programma), cosa che, come indicato giustamente da Uwe e Massimo, permette di verificare ed eventualmente modificare l'impostazione generale del programma ed in particolare quella hardware in brevissimo e senza possibilità di scordarsi un qualche riferimento all'interno del codice.

La cosa più importante comunque è sempre quella di commentare il più possibile il codice quando lo si scrive, perchè:

  • è uno sforzo minimo se lo si fa mentre si inserisce il codice;
  • aiuta a capire meglio la logica di quello che si sta facendo;
  • se si va a rileggere il codice dopo molto tempo o lo si vuol far utilizzare a qualcun'altro, la comprensione risulta molto aiutata (e quindi si risparmia poi tanto tempo);
  • i commenti non occupano alcun spazio in memora ad Arduino in quanto restano nel sorgente (ovvero nel file di testo memorizzato sul vostro computer).