Arduino

Arduino semplice - Lez 2 - Il primo programma

// inizializzazione - funzione eseguita una sola volta all'inizio
void setup() {

}

// funzione chiamata di continuo
void loop() {

}

Nella funzione di setup metteremo ad esempio le inizializzazioni (se un PIN è in ingresso o in uscita, tramite l'istruzione pinMode), mentre nella funzione loop il programma vero e proprio.

Lo sketch è sostanzialmente costituito da due sezioni:

  • la funzione setup(): viene eseguita una sola volta, all'accensione o dopo il caricamento della sketch, oppure dopo la pressione del pulsante Reset di Arduino; contiene tra parentesi graffe le istruzioni pinMode() per impostare lo stato (input o output) dei pin, le inizializzazioni delle librerie utilizzate, l'apertura della porta seriale per il Serial Monitor ...;

  • la funzione loop(): contiene tra parentesi graffe il corpo del programma che deve essere eseguito ciclicamente, specificando quali azioni deve compiere Arduino;

Facciamo un semplice programma per l'accensione del led interno collegato al pin I/O 13.

int LED = 13;  // PIN 13 è per azionare il LED interno

void setup() {
    pinMode(LED, OUTPUT);   // imposta il pin 13 come uscita
}

void loop() {
    digitalWrite(LED, HIGH);  // accendi LED
    delay(1000);   // attendi per 1000 ms = 1 sec
    digitalWrite(LED, LOW); // spegni LED
    delay(1000); // attendi per 1000 ms = 1 sec   
}

Lez 3 - Accensione di un LED esterno

Il generatore interno di Arduino è di 5 V ma il diodo led ha bisogno di una tensione di 1,5 V e funziona con una corrente di 20 mA, bisogna quindi mettere una resistenza che va dimensionata correttamente: chiamiamo VRV_R la caduta di tensione del resistore, quindi in base alla legge di Ohm:

R=VRIR = \frac {V_R} I

per calcolare la resistenza del resistore. In questo caso:VRd\frac {V_R} d

R=5V−1.5V20 mA=3.5V20 mA≈170 OhmR = \frac {5V - 1.5V} {20\ mA} = \frac {3.5V} {20\ mA} \approx 170\ Ohm

Limiti di Arduino per non sovraccaricare i PIN e bruciare la scheda - riferimenti:

Singolo PIN -> max 40 mA (buona norma farlo lavorare sotto 20 mA)

Massimo complessivo -> 200 mA

Il codice per far lampeggiare il diodo led esterno è uguale a quello utilizzato per il diodo led interno (quello del pin 13): ora invece colleghiamo il nostro diodo tramite breadboard e resistore al diodo led 10.

Circuito LED esterno
int LED = 10;

void setup() {
    pinMode(LED, OUTPUT);   // imposta il pin 10 come uscita
}

void loop() {
    digitalWrite(LED, HIGH);  // accendi LED
    delay(1000);   // attendi per 1000 ms = 1 sec
    digitalWrite(LED, LOW); // spegni LED
    delay(1000); // attendi per 1000 ms = 1 sec   
}

Soluzione:

In questo esempio il Periodo T, tempo per fare un ciclo, è di 2 secondi in quanto 1 sec ON e 1 sec OFF:

Drawing

La Frequenza, quanti cicli fa in un secondo è l'inverso del Periodo. Quindi:

F=1T=12sec=0.5HzF = \frac 1 T = \frac 1 {2 sec} = 0.5 Hz

che vuol dire mezzo ciclo al secondo.

Periodo, si misura in secondi ed è il tempo per fare un ciclo di un segnale periodico

La Frequenza, si misura in Herz, ed è quanti cicli vengono compiuti in un secondo.

1 Herz corrisponde a un ciclo al secondo.

Se invece il delay nel codice fosse di 500 ms cioè mezzo secondo, il Periodo sarebbe di 1 sec (non più due secondi) e la frequenza aumenterebbe a 1 Hz cioè un ciclo al secondo (e non più mezzo ciclo al secondo corrispondente a 0,5 Hz)

Lez 4 - Input e output digitali - Accensione led con interruttore (deviatore), collegamenti hardware

Utilizzo di un deviatore per controllare un LED.

Drawing
Utilizziamo un DEVIATORE al posto di un INTERRUTTORE

Deviatore che comanda un LED:

  • quando il deviatore è su 5V (stato logico 1) voglio che il LED si accenda;

  • quando il deviatore è su GND (stato logico 0) voglio che il led si spenga;

Vediamo le funzioni che utilizziamo:

  • digitalWrite(pin, stato) -> si usa per fornire lo stato logico in uscita (OUTPUT) se lo stato è HIGH il Pin si porta a 5V (1 logico) se è LOW (0 logico) il pin si porta a 0V;

  • digitalRead(pin) -> si usa per acquisire uno stato in ingresso (INPUT), se applichiamo 5V il Pin si porta allo stato logico 1, se applichiamo 0V il pin si porta allo stato logico 0;

// C++ code
//

int LED=10;
int DEVIATORE=2;

void setup()
{
  pinMode(DEVIATORE, INPUT);
  pinMode(LED, OUTPUT);
}

void loop()
{
  int StatoDeviatore = digitalRead(DEVIATORE);
  
  if (StatoDeviatore == HIGH)
     digitalWrite(LED, HIGH);
  else
     digitalWrite(LED, LOW);  
}

Soluzione:

Lez 5a - Accensione led con pulsante, resistenza pull down, struttura if-else

Facciamo il controllo del LED con un pulsante: Vogliamo che quando il pulsante è premuto il LED cambi stato e rimanga in tale stato anche dopo il rilascio del pulsante. Quando poi ripremiamo il pulsante cambi a questo punto lo stato.

In figura il flow chart del codice:

La variabile StatusNow a ogni loop contiene il valore letto dal pin collegato all'interruttore se in stato LOW o HIGH, mentre StatusPrevious contiene il valore dello stato precedente del loop (alla fine del loop, StatusPrevious viene aggiornato a StatusNow).

Il pulsante non può essere collegato direttamente al pin che legge lo stato del pulsante, altrimenti ci sarebbe cortocircuito. Per evitare questo dobbiamo mettere una resistenza. (In PULL-DOWN o in PULL-UP).

Vediamo il caso del collegamento del pulsante sulla breadboard con una resistenza di PULL-DOWN.

Ora disegnamo la soluzione:

Soluzione con pulsante e resistenza PULL-DOWN
// C++ code
//
#define PULSANTE 3
#define LED 8

int StatoPulsantePrevious = 0;
int StatoLED = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(PULSANTE, INPUT);
  pinMode(LED, OUTPUT);
}

void loop()
{
  int StatoPulsante = digitalRead(PULSANTE);
  if (StatoPulsante != StatoPulsantePrevious) {
    Serial.print("StatoPulsante CHANGED = ");
  	Serial.println(StatoPulsante);
    if(StatoPulsante == 1 && StatoLED == 0) {
      StatoLED = 1;
      digitalWrite(LED, HIGH);
    } else if (StatoPulsante == 1 && StatoLED == 1) {
      StatoLED = 0;
      digitalWrite(LED, LOW);
    }
    
    Serial.print("StatoLED: ");
    Serial.println(StatoLED);
    StatoPulsantePrevious = StatoPulsante;
  } 
  
}

Soluzione:

Lez 5b - Input digitali, collegamento pulsante, resistenze di pull-down e pull-up.

Con la resistenza di PULL-DOWN:

Utilizzo della RESISTENZA DI PULL-DOWN

Con la resistenza di PULL-UP:

Utilizzo della RESISTENZA DI PULL-UP

Con la resistenza di PULL-UP abbiamo la logica invertita rispetto alla PULL-DOWN.

Si può evitare di mettere una resistenza esterna, perché all'interno di Arduino ci sono anche delle resistenze interne che si possono richiamare tramite il codice.

Esiste come resistenza interna, in Arduino, solo la resistenza di PULL-UP non quella di PULL-DOWN

// Some code// C++ code
//

const int pulsante = 2;
const int led = 12;

bool statoPulsante = HIGH;

void setup()
{
  pinMode(led, OUTPUT);
  pinMode(pulsante, INPUT_PULLUP);
}

void loop()
{
  statoPulsante = digitalRead(pulsante);
  
  if(statoPulsante == HIGH)
    digitalWrite(led, LOW);
  else 
  	digitalWrite(led, HIGH);
}

Soluzione:

Lez 6 - Monitor seriale

SERIAL MONITOR: Si tratta di una comunicazione seriale che consente di inviare dati al PC o di ricevere dati dalla scheda verso il PC attraverso i pin 0 e 1 (RX e TX).

Per questo motivo i pin 0 e 1 è meglio non utilizzarli se non è strettamente necessario.

SERIAL MONITOR

  • Per utilizzare la porta seriale è necessario inizializzarla nel setup con la funzione Serial.begin(9600)

  • 9600 è la velocità di trasmissione tra Pc e Arduino:

  • Questa velocità si misura in baud. Quindi 9600 vuol dire che trasmetteremo 9600 simboli al secondo;

  • Attenzione a non confondere baud con bps o bit/s perché un simbolo è composto di più bit;

Lez 7 - Ingressi analogici (utilizzo del potenziometro)

ANALOGICO

Il termine analogico si riferisce ad una grandezza (generalmente di tipo elettronico sotto forma di tensione) che è analoga ad una grandezza di riferimento che si vuole acquistare o controllare.

Un tipico esempio di grandezza analogica è ad esempio la temperatura.

DIGITALE

  • Il termine digitale deriva dall'inglese digit (vuol dire cifra);

  • In elettronica le grandezze digitali utilizzano il sistema binario;

  • Abbiamo due soli numeri 0, 1;

  • ALTO, BASSO - HIGH, LOW;

  • ACCESO, SPENTO - ON, OFF;

Convertitore A/Digitale e D/Analogico

Drawing

ADC - Convertitore Analogico Digitale (interno ad Arduino)

  • Convertitore analogico-digitale (ADC)

  • Caratteristiche del convertitore

    • 6 ingressi analogici

    • Risoluzione: 10 bit

    • Tempo di conversione: 13 - 260 us

    • Tensione in ingresso tra 0 e 5V

Conversione analogico - digitale:

VIN:n=VMAX:(2N−1)V_{IN} : n = V_{MAX} : (2^N - 1)

risolvendola rispetto a n troviamo:

n=VINVMAX∗(2N−1)n = \frac {V_{IN}} {V_{MAX} } * (2^N - 1)

Su Arduino la tensione massimo, VMAXV_{MAX}, è 5 V e N = 10. Si ottiene quindi:

n=VIN5∗1023n = \frac {V_{IN}} 5 * 1023

Vediamo i potenziometri per generare valori analogici.

POTENZIOMETRO: è semplicemente un resistore variabile. Utilizzato per produrre valori analogici.

Il potenziometro con ha solo due terminali A e B come il resistore ma anche un terzo terminale C (terminale mobile) che mi permette di variare la resistenza: se io la resistenza la prendo tra C e A: quando porto C su A sto prendendo la resistenza 0 mentre quando porto C su B sto prendendo la resistenza massimo.

Lo inizieremo ad utilizzare come regolatore di tensione - partitore di tensione.

Sul terminale C, se C = A, allora la tensione VxV_x sarà 5 V (che è la tensione della batteria è 5V)

Sul terminale C, se C = B, allora la tensione VxV_x sarà 0 V.

Nei punti intermedi, il valore di VxV_x sarà un valore tra 0 e 5V, al esempio 2,7V, in base a come spostate il terminale C tra A e B: quanto più vi avvicinate ad A più tende a 5V viceversa avvicinandosi a B tende a 0V.

A questo punto collego C a un pin di imput analogico, come A0.

Funzione analogRead(pinAnalogico) per la lettura di valori discreti nel range tra 0 e 1023 (= 210−12^{10} - 1).

int valore = analogRead(A0);

Utilizzo dell'esempio di lettura da potenziometro:

/*
acquisizione dal canale A0  
*/
void setup() {
    // inizializzazione della comunicazione seriale
    Serial.begin(9600);
}

// funzione chiamata di continuo
void loop() {
    int n = analogRead(A0);
    Serial.print("Valore numerico acquisito su A0 --> n = ");
    Serial.println(n);
    float Vin = (float) n * 5 /1023;
    Serial.print("Vin = ");
    Serial.print(Vin);
    Serial.println(" Volt");
    Serial.println("");
    
    delay(2000);
}

Soluzione:

Lez 8 - Uscite analogiche PWM

Regolazione della luminosità di un diodo LED

Uscite PWM

Arduino non possiede delle vere e proprie uscite analogiche. Riusciremo però ad ottenere una variazione di una tensione utilizzando le uscite digitali con la tecnica PWM

Cos'è il PWM (Pulse Width Modulation)?

Modulazione a lunghezza d'impulso.

L'idea è quella di regolare il valore medio di un segnale digitale modificando i tempi relativi di ON e OFF

SEGNALE DIGITALE con UNA DETERMINATA FREQUENZA

Le uscite PWM:

Il concetto di Duty Cycle, abbreviato in DC, come rapporto tra tempo a segnale alto TONT_{ON} e periodo del segnale TT poi moltiplicato per 100 per avere la percentuale.

Per cambiare di DC non cambia il periodo ma il tempo, la percentuale, in cui il segnale è altro, il TONT_{ON}.

Le uscite analogiche PWM sono, su Arduino, quelle DIGITALE con il simbolo ~. Si possono vedere nella figura sotto.

Per scrivere sulle uscite PWM di Arduino abbiamo:

analogWrite(pin, val);

Pin -> 3, 5, 6, 9, 10, 11

Val è gestito da una variabile a 8 bit e quindi può assumere valori che vanno da 0 a 255.

Ad esempio se:

val = 0 -> abbiamo un DC del 0%;

val = 255 -> abbiamo un DC del 100%;

val = 127 -> abbiamo un DC del 50%;

Quindi, con la funzione analogWrite, possiamo regolare il Duty Cycle:

Controllo dei carichi in PWM

  • La tecnica PWM è molto utilizzata per controllare diversi tipi di carichi: LED, lampade, motori, resistenze termiche.....

  • Sembra strano far accendere qualcosa accendendo e spegnendo in continuazione

  • La frequenze è però talmente alta (490 Hz sui pin 3, 9, 10 e 11 e 980 Hz sui pin 5 e 6) che sarà il nostro stesso occhio a fare la media di quel segnale e non percepire il lampeggio della lampada

Possiamo vedere il potenziometro come regolatore di corrente (nel caso precedente l'avevamo utilizzato come regolatore di tensione).

Per la legge di Ohm I=V/RI = V/R muovendo il cursore C verso i terminali A o B, aumentando o diminuendo la resistenza e quindi diminuendo o aumentando la corrente (la Resistenza e Intensità della corrente sono inversamente proporzionali per la legge di Ohm)

Ora vediamo, invece, come fare un regolatore di un diodo LED con Arduino:

CONTROLLO di un diodo LED in PWM

  • Legge da un input analogico la tensione fornita da un potenziometro (10 bit -> 0 - 1023)

  • Traduce nel relativo segnale PWM (8 bit -> 0-255)

  • Invia al diodo Led una tensione PWM con duty cycle variabile proporzionale alla posizione del potenziometro

  • Invia i risultati al serial monitor

La funzione map

Per fare la conversione tra i valori che arrivano dal potenziometro (0-1023) e quelli che devono andare al LED dal pin PWM (0-255) usiamo la funzione map.

// val il val del duty cycle, es 127 per il 50%
map(val, min1, max1, min2, max2);

map(val, 0, 1023, 0, 255);

Ora che abbiamo visto le funzioni analogWrite e map possiamo utilizzarle insieme ad analogRead per regolare la luminosità di un LED tramite un potenziometro:

int potenziometro = A0;
int LED = 10;
int ValPot = 0;
int ValOut = 0;

void setup() {
    Serial.begin(9600);
    // le lineee analogiche IN o OUT non vanno impostate
}

void loop() {
    // legge il valore analogico dal potenziometro
    ValPot = analogRead(potenziometro);
    
    // scala il valore letto (da 0 a 1023) in uno proporzionale (da 0 a 255)
    ValOut = map( ValPot, 0, 1023, 0, 255);
    
    // aggiorna il segnale pwm sull'out analagica led
    analogWrite(LED, ValOut);
    
    Serial.print("potenziometro = ");
    Serial.print(ValPot);
    Serial.print("\t Pwm Led = ");
    Serial.println(ValOut);
    Serial.print("dudy cycle = ");
    Serial.print(ValOut * 100/255);
}

Soluzione:

Learn Arduino and Circuits with Tinkercard!

MISC

Last updated