Programmare con Arduino
Il linguaggio di programmazione Arduino può essere diviso in tre parti principali:
- Funzioni: per controllare la scheda Arduino ed eseguire calcoli
- Variabili: tipi di dati e costanti
- Struttura: gli elementi del codice Arduino (C ++)
L'ambiente di programmazione Arduino può essere esteso tramite l'uso di librerie che forniscono ulteriori funzionalità rispetto al linguaggio base e sono particolarmente utili per l'utilizzo di moduli aggiuntivi.
Funzioni di uso frequente
Input/Output digitali
pinMode (pin, mode) Configura il pin specificato come input o output
- pin: il numero del pin digitale
- mode = {INPUT | OUTPUT | INPUT_PULLUP}
- Nel modo INPUT_PULLUP viene collegato un resistore (pull-up) collegato alla linea di alimentazione (+5 V in Arduino UNO) del valore di 20 ÷ 50 kΩ
digitalRead (pin) Legge il valore logico di un pin digitale
- pin: il numero del pin digitale
- Valore restituito: HIGH o LOW
- Deve essere preceduto dall’istruzione pinMode(pin, INPUT)
Con pinMode() impostato su INPUT_PULLUP, in assenza di connessioni, la funzione digitalRead (pin) restituisce sempre il valore HIGH.
digitalWrite (pin, value) Assegna un valore logico ad un pin digitale
- pin: il numero del pin digitale
- value: valore assegnato: HIGH | LOW (1 | 0)
- Deve essere preceduto dall’istruzione pinMode(pin, OUTPUT)
Se il pin è configurato come INPUT:
– digitalWrite(HIGH) abilita il pullup interno sul pin di input
– digitalWrite(LOW) disabilita il pullup interno sul pin di input
Input/Output analogico
analogRead (pin) Legge la tensione elettrica applicata ad un pin analogico (tra 0 e 5 V)
- pin: il numero del pin (0..5 oppure A0..A5)
- Restituisce un numero intero compreso tra 0 e 1023 (risoluzione di 10 bit)
- Risoluzione di 4,9 mV (~5 V/1024)
- Il tempo di conversione è di circa 100 ms
- Massimo 10000 letture al secondo
- I pin analogici non hanno bisogno di essere dichiarati come pin di INPUT o OUTPUT
analogReference(type) Modifica l'intervallo dei valori analogici da leggere
- type:
– DEFAULT: il riferimento predefinito di 5 volt
– INTERNAL: riferimento integrato uguale a 1,1 volt su ATmega328P
– EXTERNAL: viene utilizzata come riferimento la tensione applicata al pin AREF (da 0 a 5 V)
Esempio
#define ANALOG_PIN 5
unsigned int value;
float voltage;
void setup() {
Serial.begin(9600);
}
void loop() {
value = analogRead(ANALOG_PIN);
voltage = value * (5.0 / 1023.0);
Serial.println(voltage);
delay(100);
}
analogWrite (pin, value)
È una operazione di scrittura pseudo-analogica in quanto viene generato un segnale di tipo PWM
- pin: i pin dedicati a questa funzione sono: 3, 5, 6, 9, 10, 11 (indicati con il simbolo ~)
- value: valore compreso tra 0 e 255 (8 bit)
- Non è necessario chiamare pinMode() per impostare il pin come output prima di chiamare analogWrite()
- L'uso successivo delle istruzioni digitalRead() o digitalWrite() sullo stesso pin, disattivano il segnale PWM
Dà la possibilità di controllare la tensione media di un segnale digitale tramite la variazione della larghezza degli impulsi. È caratterizzata da un segnale digitale a frequenza (fissa) e da un rapporto variabile tra la durata del livello attivo (HIGH) e il periodo totale (duty cycle), con value = 127 si ha un'onda quadra (uguali valori HIGH/LOW).
Questo tipo di segnale viene spesso usato per il controllo della velocità di rotazione di un motore, della luminosità di un led, ecc.
Note
- Con value uguale a 0 e 255 si ha un segnale di livello costante: analogWrite(pin, 0) equivale a digitalWrite(LOW), analogWrite(pin, 255) equivale a digitalWrite(HIGH)
- Nel segnale PWM la frequenza rimane fissa ma dipende dal pin in uso: con Arduino UNO si hanno i seguenti valori: sui pin 3, 9, 10, 11 la frequenza è circa 490 Hz, sui pin 5 e 6 la frequenza è circa 980 Hz
- L'uso della funzione tone() interferisce con l'uscita PWM sui pin 3 e 11
- I segnali PWM sui pin 5 e 6 generano cicli di lavoro superiori a quanto impostato, soprattutto per valori minori di 10, a causa di interazioni con le funzioni millis() e delay() che condividono lo stesso interrupt
- Se si usa l'istruzione digitalWrite su due motori, è importante collegarli su pin che hanno la stessa frequenza
Alcuni approfondimenti sulla modulazione PWM di Arduino
playground.arduino.cc/Code/PwmFrequency
www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Generare un'onda quadra (suono)
tone (pin, frequency)
tone (pin, frequency, duration) Genera un'onda quadra (tono) di frequenza compresa tra 31 Hz e 65535 Hz
- pin: il pin su cui generare il tono
- frequency: la frequenza del tono in Hz (unsigned int)
- duration: la durata del tono in millisecondi (unsigned long)
Se non è indicata la durata, il tono continua fino ad un’eventuale chiamata a noTone ()
noTone (pin) Arresta la generazione del tono attivato dalla funzione tone()
Note
- È possibile generare un solo tono alla volta
- Se un tono è già in esecuzione, su di un pin diverso, la chiamata a tone() non avrà alcun effetto
- Se devono essere eseguiti due toni in successione è necessario intercalare la funzione delay(duration) altrimenti il tono viene eliminato prima del completamento
- Si può ottenere un'onda quadra di frequenza fissa anche utilizzando l'istruzione PWM analogWrite(pin, 127)
- L'uso della funzione tone() interferisce con l'uscita PWM sui pin 3 e 11
- Per riprodurre suoni di frequenza diversa si sconsiglia l'uso dei cicalini piezoelettrici (buzzer), spesso in dotazione ai kit Arduino, perché sono in grado di riprodurre solo un limitato intervallo di frequenze.
Intervalli di tempo
La funzioni per la gestione degli intervalli di tempo si dividono in due categorie:
- quelle che bloccano l'esecuzione del programma per un determinato intervallo di tempo: delay(ms) e delayMicroseconds(µs)
- quelle che restituiscono il tempo trascorso dall'accensione del sistema: millis() e micros()
delay(ms)
Blocca l’esecuzione del programma per l’intervallo di tempo, in millisecondi, indicato dal parametro ms (unsigned long)
delayMicroseconds(µs)
Blocca l’esecuzione del programma per l’intervallo di tempo, in microsecondi, indicato dal parametro µs (unsigned long)
Il valore massimo utilizzabile è 16383 (14 bit) con un’accuratezza di circa 3 µs
millis()
Restituisce il numero di millisecondi (unsigned long) trascorsi da quando la scheda Arduino ha iniziato a eseguire il programma corrente (ritorna a 0 dopo circa 50 giorni)
Utilizza un contatore che viene aggiornato continuamente da un interrupt collegato al timer 0
micros()
Restituisce il numero di microsecondi (unsigned long) trascorsi da quando la scheda Arduino ha iniziato a eseguire il programma corrente (ritorna a 0 dopo circa 70 minuti)
Nota
Il microcontrollore ATMega328 ha tre timer, che dipendono dal clock di sistema (per Arduino UNO è 16 MHz):
- Timer0: timer a 8 bit utilizzato dalle funzioni delay(), millis() e micros()
- Timer1: timer a 16 bit utilizzato dalla libreria Servo; non è possibile utilizzare la funzione PWM sui pin 9 e 10 quando si utilizza questa libreria
- Timer2: timer a 8 bit utilizzato dalla funzione tone(); non è possibile utilizzare la funzione PWM sui pin 3 e 11 quando si utilizza questa libreria.
Comunicazione Seriale (asincrona)
La maggior parte delle schede della famiglia Arduino dispone di un connettore USB per il collegamento al computer. Il connettore USB è collegato alla porta seriale del microcontrollore tramite un convertitore USB/seriale che effettua una conversione tra il protocollo USB e quello seriale asincrono (UART o USART).
In Arduino UNO per la comunicazione seriale sono utilizzati i pin digitali 0 (RX) e 1 (TX) del connettore Digital (PWM~). L'utilizzo dei pin 0 e 1 per altri scopi, è sconsigliato perché può interferire con la comunicazione seriale diretta alla porta USB: alcune schede però hanno un sistema di commutazione automatica in modo che, quando si inserisce un connettore USB, eventuali collegamenti sui pin 0 e 1 sono disattivati, questa funzionalità è particolarmente utile quando si connettono a questi pin moduli Bluetooth o WiFi. Alcune schede dispongono anche di altre porte seriali: è importante tenere presente che i livelli di tensione presenti sui pin del microcontrollore non sono compatibili con quelli delle porte seriali standard RS232C per cui è necessario usare opportuni adattatori!
Quando si collega la scheda Arduino al computer, il sistema operativo (tramite opportuni driver) genera una porta seriale virtuale che in Windows è indicata da com seguita da un numero progressivo (es. com5, com6). Alle linee TX/RX sono collegati due led che lampeggiano in presenza di un flusso di dati.
La porta USB svolge tre importanti funzioni: l'alimentazione della scheda, il caricamento dei programmi e lo scambio di dati.
Le principali funzioni per la comunicazione seriale, contenute nel package Serial, sono:
Serial.begin(speed) Imposta la velocità per lo scambio dei dati, in bit per secondo (long); il valore predefinito di speed è 9600 b/s
Serial.print(val) Invia i dati della stringa val sulla porta seriale come testo ASCII
Serial.println(val) aggiunge in coda alla stringa val il carattere di nuova riga ('\ n')
Serial.println(val, format) format specifica la base numerica (per gli interi) o il numero di cifre decimali (per i numeri in virgola mobile)
Nota: Serial.print e Serial.println restituiscono il numero di byte inviati: la lettura di questo valore è opzionale
Serial.flush() Attende il completamento della trasmissione dei dati seriali in uscita
Serial.readString() Legge i caratteri dalla porta seriale in una stringa; la funzione termina se l'attesa supera il tempo massimo predefinito (vedi Serial.setTimeout)
Serial.readStringUntil(terminator) Come readString, ma la funzione termina se viene rilevato il carattere di fine lettura terminator o l'attesa supera il tempo massimo predefinito
Serial.read() Restituisce il primo byte dei dati in arrivo (-1, se non ci sono dati disponibili)
Serial.readBytes(buffer, length) Legge i caratteri dalla porta seriale e li copia nell'area di memoria buffer
- buffer: il buffer per memorizzare i byte in (char[] o byte[])
- length: il numero di byte da leggere (int): restituisce il numero di byte inseriti nel buffer
Serial.readBytesUntil(character, buffer, length) Come readByte, ma la funzione termina se viene rilevato il carattere di fine lettura indicato in character o se l'attesa supera il tempo massimo predefinito in Serial.setTimeout()
Serial.available() Restituisce il numero di byte (caratteri) disponibili per la lettura
Serial.setTimeout (time) Imposta il tempo massimo per l'attesa dei dati (in millisecondi). Il valore di time predefinito è 1000 ms
Altre funzioni nella documentazione di riferimento del package Serial.