funzioni su Arduino

#4/1 – Codice su Arduino: Istruzioni Semplici

Adesso che conosciamo come memorizzare informazione nel codice, andiamo a vedere come utilizzarla grazie alle istruzioni disponibili in Arduino.

Come vedremo tra breve, le funzioni sono frammenti di codice, e come tali sono composte da istruzioni (semplici e/o altre funzioni). Per affrontarle, ovviamente prima dovremo conoscere le tipologie di istruzioni semplici e il loro utilizzo: ritorniamo quindi alla distinzione tra istruzioni semplici e composte.

Le istruzioni semplici

Le istruzioni semplici sono i “mattoncini” con cui andremo a costruire le nostre funzioni.

Sono istruzioni che il nostro microcontrollore esegue in una singola “mossa” (anche se vedremo che non è proprio così in articoli più avanzati), e sono:

Gli assegnamenti

Per riempire una variabile, occorre fare quello che viene chiamato “assegnamento“:

//I commenti non vengono eseguiti, ma servono al programmatore per spiegare il codice. Iniziano con //
n = 100; //Scrivo 100 nella variabile chiamata n
c = 'a'; //Scrivo il carattere a nella variabile chiamata c

L’assegnamento copia il valore a destra dell’uguale, nel “contenitore” a sinistra.

Viceversa, se vogliamo leggere il valore di una variabile per metterlo in un’altra:

nuova_variabile = vecchia_variabile; //Copio il valore di vecchia_variabile in nuova_variabile

Quando dichiariamo una variabile, possiamo già anche inizializzarla, ovvero assegnarle un valore iniziale. Per farlo, semplicemente basta mettere un assegnamento di fianco alla dichiarazione:

int n = 10;
char c = 'a';
//Vale anche per gli array
int numero[3] = {1,2,3};

Per le matrici, l’inizializzazione è molto simile:

int matrice[3][3] = { 
  {1, 2, 3}, 
  {4, 5, 6}, 
  {7, 8, 9} 
};
/*   Rappresenta
 *     1  2  3
 *     4  5  6
 *     7  8  9
 *   
 *   Ad esempio: matrice[1][2] == 6, matrice[2][0] == 7
 */

Negli array e nelle matrici, è possibile accedere e scrivere l’elemento desiderato, conoscendo il suo indice:

int numeri[3] = {1,2,3};
/* Rappresentazione di numeri all'inizio
 *    1  2  3
 */
numeri[0] = 9; //Cambio il primo elemento
numeri[1] = 4; //Cambio il secondo elemento
/* Rappresentazione di numeri dopo gli assegnamenti
 *    9  4  3
 */
//Per le matrici, ricordarsi che si hanno due o più indici
int matrice[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };
/* Rappresentazione
 *    1  2  3
 *    4  5  6
 *    7  8  9
 */
matrice[0][2] = 10; //Cambio il valore alla prima riga, terza colonna
/* Rappresentazione
 *    1  2  10
 *    4  5  6
 *    7  8  9
 */

Le operazioni algebriche

Ovviamente, non potevano mancare le operazioni algebriche. Tra queste abbiamo a disposizione: + ,, * , / , %.

//Esempio di Somma
int a,b,c;
b = 3;
c = 4;
a = b + c; //Dopo averla eseguita, in a avremo il valore 7
//Per sommare un numero alla stessa variabile, possiamo scrivere anche
a += c; //=> a = a + c;
//Esiste un modo ancora più sintetico se alla variabile in questione voglio sommare o sottrarre 1
a++; //a = a + 1
a--; //a = a - 1
//Esempio di prodotto
int a,b,c;
b = 3;
c = b * 4; //Dopo averla eseguita, in c avremo il valore 12
a = b * c; //Dopo averla eseguita, in a avremo il valore 36
//Per calcolare a^2
a *= a; //=> a = a * a;
Particolarità delle operazioni con numeri interi

Quando entrambi gli operandi sono interi, come abbiamo già accennato, le operazioni vengono svolte in modo più efficiente. Quello che non abbiamo ancora considerato, è che il risultato di ogni operazione che li riguarda è a sua volta intero.

Mentre questa affermazione è scontata per le operazioni di somma e differenza, e anche di prodotto, non lo è per le divisioni.

Eseguendo una divisione tra due operandi interi, in cui il primo non è multiplo intero del secondo, non possiamo avere cifre decimali. Le divisioni intere sono svolte approssimando il risultato per troncamento.

Se ci interessa non perdere le cifre decimali, almeno uno dei due operandi deve essere di tipo float. Vedremo come fare parlando di cast di variabili.

Anche gli assegnamenti di numeri a variabili intere, vengono svolte approssimando per troncamento.

Operatore Modulo
//Operatore Modulo: restituisce 0 se il primo numero è multiplo del secondo, 1 altrimenti
int a,b;
b = 10;
a = b % 2; //Dopo averla eseguita c conterrà il valore 0 perché 10 è multiplo di 2

In realtà l’operatore modulo restituisce il resto della divisione euclidea:

13 % 3 == 1 perché 13/3 = 4 resto 1, dato che 13 - 3*4 = 1

Gli operatori logici

Gli operatori logici sono fondamentali, come vedremo tra qualche articolo, per controllare il flusso di esecuzione. Sono:

< (minore) , > (maggiore), == (uguale), >= (maggiore o uguale), <= (minore o uguale), != (diverso).

Quando vengono eseguite (diremo “valutate“), restituiscono 1 se il confronto è valido, 0 altrimenti.

int a,b;
b = 10;
a = (b == 10); //a conterrà 1, poiché b è uguale a 10
a = (b > 5); //a conterrà 1, poiché b è maggiore di 5

ATTENZIONE: ‘=’ assegna il contenuto di destra a sinistra, mentre ‘==’ restituisce 1 se i due contenuti sono uguali!

Nel caso in cui dovesse servire rendere esplicito l’ordine di valutazione degli operatori, è possibile farlo utilizzando le parentesi tonde:

risultato = (a != 3) && ( a == 4 || b != 5);

Gli operatori booleani

Sono gli operatori che utilizzeremo di più in assoluto. Si rendono necessari per legare gli operatori logici (che creano quelle che chiameremo condizioni) tra di loro, e creare condizioni complesse per le future istruzioni che vedremo (vedi controllo di flusso).

Sono: && (AND), || (OR), ! (NOT).

Per chi non conosce le basi della logica booleana (o Algebra di Boole), introduciamo una piccola spiegazione qui sotto. Per gli altri, è possibile saltare direttamente al prossimo paragrafo.

Abbiamo appena visto che gli operatori di confronto ci danno come risultato 1 oppure 0. Utilizziamo gli operatori booleani per combinare tra di loro questi risultati, secondo questa tabella (chiamate tabella di verità):

Condizione1Condizione2Codizione1 && Condizione2Condizione1 || Condizione2!Condizione1!Condizione2
000011
010110
100101
111100
Tabella di verità per le operazioni AND, OR, NOT

In breve, utilizziamo:

  • AND, se vogliamo che le due o più condizioni si verifichino contemporaneamente per avere valutazione 1
  • OR, se ci basta che una delle due o più condizioni si verifichi per avere valutazione 1
  • NOT, se vogliamo avere valutazione 1 quando non si verifica quella condizione

Il loro utilizzo pratico diventerà evidente nell’articolo sul controllo di flusso.

Gli operatori binari

Sono operatori che si utilizzano per manipolare direttamente i dati binari, e sono: & (and) , << (bitshift left), >> (bitshift right) , ^ (bitwise xor), |(bitwise or), ~ (bitwise not).

Il loro utilizzo lo vedremo nel dettaglio successivamente, quando ci occuperemo di manipolazione binaria. Nel mentre, i lettori più curiosi possono guardare qui.

Adesso che conosciamo le istruzioni semplici, andiamo a tuffarci nelle funzioni, che sono l’aspetto più critico della programmazioni.

7 comments

  1. alex

    all’inizio mi piaceva come guida , poi però ha cominciato, secondo me, a perdere di vista l’obiettivo di essere comprensibile per un neofita.
    discorsi complessi per un principiante, banali per un programmatore

    1. Andrea Aspesi

      Sono d’accordo con te Alex.
      L’obiettivo di questi articoli è però quello di essere una traccia per un neofita, per permettergli di orientarsi tra i centinaia di video/articoli che può trovare online. Per questioni di tempo mi sarebbe impossibile fornire una guida completa sotto tutti gli aspetti.
      Alla luce di questo, se però secondo te ci sono concetti poco chiari in questi articoli, scrivimi pure che quando avrò tempo da dedicarci li sistemo

  2. Maurizio Samuele

    Un conto è guidare una bicicletta altra cosa è guidare uno space shuttle, nel momento che Hai deciso di programmare un microcontroller accetta le difficoltà e cerca di mettere a frutto quello che persone come Andrea Aspesi, dedicando il proprio tempo, cercano di divulgare, le altenative sono programmi fatti da if a == x …. che proseguono all’infinito. La programmazione non è cosa semplice io sono nato con l’asm e ne so qualcosa. Buon lavoro.

  3. Giovanni

    Buongiorno a tutti
    tra tutte le guide che ho letto on line secondo me e forse la migliore e proprio per questo penso che come scrive Alex parte chiara per poi complcarsi rapidamente
    e vero quello che dice Samuele che la programmazione non e una cosa semplice
    ma e anche vero che tutto il difficile diventa semplice una volta compreso il funzionamento
    pertanto penso che il signor Andrea Aspesi che reputo un buon istruttore che dovrebbe soffermarsi un pò di piu sugli argomenti man mano che diventano piu complessi in modo da far capire meglio le funzioni e come vengono usate
    questa e una mia opinione personale
    e ripeto e forse la migliore guida che ho trovato di programmazione

    1. Andrea Aspesi

      Nelle prossime settimane modificherò l’articolo aggiungendo molto altro materiale, magari dividendolo in più articoli per non rendere troppo lunga la lettura. Vi invito a segnalarmi qui sotto tutti gli argomenti che avete trovato poco chiari (es. array, parametri delle funzioni, chiamate a funzioni, etc).
      Stay tuned!

  4. Roberto

    vorrei sapere per cortesia quale è il carattere sulla tastiera per indicare
    la funzione OR .
    grazie

    1. Andrea Aspesi

      Ciao Roberto, l’OR si scrive in C affiancando due barrette verticali. Se hai una tastiera con il layout italiano, la trovi nella posizione indicata dall’immagine. Ovviamente bisogna usare in combinazione il tasto SHIFT.
      OR keyboard layout

Comments are closed.