L’idea
Dovendo misurare la luminosità di alcuni ambienti, e dato che gli strumenti per farlo non sono molto economici, ho deciso di realizzarlo io. Per curiosità ho usato la scheda Seeeduino XIAO di Seeed Studio (la documentazione è nei link in fondo alla pagina) e, come sensore, un TSL2591: a mio parere tra i sensori ottici per hobbisti è uno dei più efficienti, con un buon rapporto qualità prezzo.
Il luxmetro mostra su un display a colori i valori letti dal sensore (infrarosso, spettro completo, luce visibile e lux) e dà un giudizio sulla luminosità con una scritta e con due LED.
Hardware
Un difetto da conoscere: il bootloader
La Seeeduino XIAO è molto valida, ma ha un piccolo neo: a volte non si riescono a caricare i programmi perché la scheda non entra in modalità bootloader. Se succede, dopo aver collegato la scheda al computer basta mettere in cortocircuito i due pin siglati RST che si trovano a fianco del connettore USB. Se, collegandola, non compare nessuna porta COM, vuol dire che la scheda non è entrata in modalità bootloader.
I collegamenti
I due LED segnalano la luminosità: il LED rosso acceso indica luminosità insufficiente oppure illuminazione alta, fuori scala.
| Funzione | Pin della XIAO |
|---|---|
| LED rosso | 3 |
| LED verde | 2 |
Il display
Display TFT 240×240 IPS con controller ST7789.
| Pin del display | Pin della Seeeduino XIAO |
|---|---|
| GND | GND |
| VCC | 3V3 |
| SCL | 8 |
| SDA | 10 |
| RES | 0 |
| DC | 1 |
| BLK | non collegato |
Il display parla con la scheda attraverso il bus SPI: SCL è il segnale di clock e SDA quello dei dati. Il modulo non ha un pin CS: nel codice la costante TFT_CS vale 10, lo stesso pin collegato a SDA.
Il sensore TSL2591
| Pin del sensore | Pin della Seeeduino XIAO |
|---|---|
| GND | GND |
| VCC | 3V3 |
| SDA | 4 |
| SCL | 5 |
Il sensore usa il bus I²C (libreria Wire), che sulla XIAO ha proprio i pin 4 (SDA) e 5 (SCL).
Codice
Il sorgente
Il codice completo è nel file luxmetro2591.ino, da scaricare in fondo alla pagina: si apre direttamente con l’Arduino IDE. Io l’ho sviluppato con PlatformIO, dove lo stesso programma sta nel file src/main.cpp; la configurazione del progetto è questa:
[env:seeed_xiao]
platform = atmelsam
board = seeed_xiao
framework = arduino
lib_deps =
adafruit/Adafruit ST7735 and ST7789 Library@^1.8.0
adafruit/Adafruit GFX Library@^1.11.2
adafruit/Adafruit TSL2591 Library@^1.4.2
adafruit/Adafruit BusIO@^1.11.6
Con l’Arduino IDE le stesse librerie si installano dal gestore librerie, scegliendo come scheda la Seeeduino XIAO (il pacchetto di schede si trova nella documentazione di Seeed Studio, nei link in fondo alla pagina).
La struttura del programma
I numeri delle righe sono quelli del file luxmetro2591.ino.
| Righe | Che cosa contengono |
|---|---|
| 1-7 | Le librerie: grafica (Adafruit_GFX), SPI, display ST7789, Wire (I²C), supporto ai sensori Adafruit e libreria del TSL2591. |
| 9-15 | I pin (TFT_CS 10, TFT_RST 0, TFT_DC 1, LED_ROSSO 3, LED_VERDE 2) e i due oggetti: tft (display) e tsl (sensore). |
| 24-25 | Le variabili: prova (0 per usare il display, diverso da 0 per stampare i valori sul monitor seriale) e due stringhe di appoggio per i testi. |
| 27-72 | setup(): avvia seriale, LED, display e sensore, mostra la schermata iniziale. |
| 74-118 | loop(): legge la luminosità, scrive il giudizio e accende i LED, poi aspetta 4 secondi. |
| 121-161 | configureSensor(): imposta guadagno e tempo di integrazione del sensore. |
| 163-220 | advancedRead(): legge il sensore, calcola i lux, scrive i valori sul display e restituisce la categoria di luminosità. |
| 223-268 | simpleRead(): una lettura più semplice, della sola luce visibile. Nel loop() è disattivata (commentata). |
| 273-311 | displaySensorDetails() e unifiedSensorAPIRead(): funzioni di esempio della libreria, per il monitor seriale. Non sono usate. |
setup(): avvio
All’accensione il programma avvia la seriale a 9600 baud, imposta i due pin dei LED come uscite e inizializza il display a 240×240 punti (tft.init(240, 240, SPI_MODE2), rotazione 3). Mostra per 3,5 secondi la schermata di presentazione, un riquadro verde con la scritta «QuinciSoft LuxTsl2591» in rosso, poi spegne i LED, avvia il sensore con tsl.begin() e chiama configureSensor().
configureSensor(): guadagno e tempo
tsl.setGain(TSL2591_GAIN_MED); // guadagno 25x
tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // tempo di integrazione: 100 ms
Il TSL2591 può adattarsi a luci diverse cambiando il guadagno (quanto amplifica il segnale: 1×, 25×, 428× o 9876×) e il tempo di integrazione (per quanto tempo raccoglie la luce: da 100 a 600 ms). Un tempo lungo e un guadagno alto servono con poca luce; un tempo breve e un guadagno basso con tanta luce. Nel programma sono scelti guadagno medio e 100 ms; le altre combinazioni sono lasciate come commenti da attivare. La funzione scrive poi sul monitor seriale i valori impostati.
advancedRead(): la lettura
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16; // 16 bit alti: infrarosso
full = lum & 0xFFFF; // 16 bit bassi: spettro completo
double lux = tsl.calculateLux(full, ir);
Il sensore ha due fotodiodi, uno sensibile a tutto lo spettro e uno all’infrarosso. La libreria restituisce i due valori in un unico numero a 32 bit: il programma li separa con uno spostamento di bit e una maschera. La luce visibile è la differenza tra i due (full - ir), e i lux li calcola la libreria a partire da entrambi. Sul display i quattro valori compaiono su quattro righe, in colori diversi (IR rosso, Full bianco, Vis. giallo, Lux blu). Prima di riscrivere ogni valore il programma cancella con un rettangolo nero (fillRect) quello precedente, altrimenti le cifre si sovrapporrebbero.
La funzione restituisce anche una categoria, in base ai lux:
| Lux | Categoria | Scritta | LED |
|---|---|---|---|
| fino a 100 | 0 | «Insuff.» | solo il rosso |
| da 100 a 200 | 1 | «Scarsa.» | rosso e verde |
| oltre 200 | 2 | «Ok.» | solo il verde |
Luce troppo intensa (fuori scala). Se il sensore satura, la libreria restituisce per i lux il valore −1 (accanto a «Lux:» il display scrive -1.00). Il programma lo tratta come la categoria 0: compare «Insuff.» e si accende il LED rosso. Per questo il LED rosso segnala sia la luminosità insufficiente sia l’illuminazione alta fuori scala: per distinguere i due casi basta guardare il valore dei lux.
loop(): giudizio e LED
scelta = advancedRead();
switch (scelta) {
case 0: /* "Insuff." - LED rosso */ break;
case 1: /* "Scarsa." - LED rosso e verde */ break;
default:
case 2: /* "Ok." - LED verde */ break;
}
delay(4000); // una misura ogni 4 secondi
A ogni giro il programma legge il sensore, scrive in basso la scritta corrispondente alla categoria (dopo aver cancellato quella precedente) e imposta i due LED. Poi attende 4 secondi: la misura si aggiorna quindi circa ogni quattro secondi.
Altre note sul codice
- Per leggere i valori sul monitor seriale invece che sul display, basta mettere
provaa un valore diverso da 0. - Nel codice, accanto alla definizione del LED verde, c’è il commento «prima 4»: in una versione precedente il LED era collegato al pin 4.
Prova
Nella foto il luxmetro, in un contenitore nero, misura circa 54 lux: essendo sotto i 100 lux, il display mostra «Insuff.» e si accende il LED rosso.
Scarica
- Codice sorgente (luxmetro2591.ino) Sorgente Arduino · 8 KB
Link utili
Questi link portano a siti esterni, che si aprono in una nuova scheda.
Hai domande su questo progetto?
Scrivimi dalla pagina Contatti: ti rispondo appena possibile.