In questo articolo vedremmo come costruire un dipositivo in grado di leggere e visualizzare in un display l'altezza del livello di acqua in un pozzo o una cisterna. Utilizzeremo un dispositivo hardware Open Source chiamato Arduino, un sensore ad ultrasuoni per misurare l'altezza dell'acqua, un display LCD di 16 caratteri su due linee e un buzzer che ci avvertirà se il livello supera una certa soglia. |
Il progetto, come abbiamo già accennato, è composto da più parti. Un sensore sonar da posizionare nella parte alta del pozzo (lontano dall'acqua) che guarda verso il basso così da misurare la distanza tra il punto più alto del pozzo e l'acqua. Facendo una semplice differenza tra l'altezza dal fondo al sensore e la misura letta otteniamo l'altezza dell'acqua. Ad intervalli di tempo prestabiliti verrà letta la quantità dell'acqua e visualizzata sul display. Se il livello supera una soglia scatterà un allarme che fa suonare il buzzer fino a quando il livello scenderà di nuovo sotto la soglia o quando si disattiva manualmente la suoneria. Arduino controlla la logica di funzionamento, tramite un programma che vedremo di seguito, e gestisce tutti i dispositivi.
Arduino è una piattaforma elettronica open-source basata sulla semplicità e la facilità di utilizzo. È proprio per queste sue caratteristiche che viene utilizzata da artisti, design, hobbisti e chiunque si interessi di creare oggetti o ambienti interattivi.
Supporta un vasto numero di sensori ed è programmabile attraverso un linguaggio che ha molte affinità con il C. Dal sito del progetto è possibile scaricare un enviroment con editor, compilatore e funzione di upload. Tutto ciò di cui abbiamo bisogno per programmare Arduino. È possibile anche utilizzare strumenti a linea di comando ma ora non ci occuperemo di questo.
[download file='pozzo.pcb' name='pcb per ExpressPCB']
Di seguito c'è il programma caricato su Arduino. Il codice è molto semplice soprattutto se già si conosce il C o il C++. Da notare che manca la funzione main(), l'esecuzione inizia invocando la funzione setup() una sola volta all'avvio del dispositivo e poi ciclicamente la funzione loop().
/* -*- mode: c -*- */ /** * pozzo.pde * version: 1.2 */
/* initialize the library with the numbers of the interface pins */ LiquidCrystal lcd(12, 11, 5, 4, 3, 6);
int mute = 0;
byte *getChar(int n, byte newChar[]) { int i; byte code[5] = { B10000, B11000, B11100, B11110, B11111};
for (i = 0; i < 8; i++) newChar[i] = code[n - 1];
return newChar; }
void setup() { int i; float h; byte newChar[8];
/* set up the LCD's number of rows and columns: */ lcd.begin(16, 2);
for (i = 1; i < 6; i++) lcd.createChar(i, getChar(i, newChar));
newChar[0] = B00000; newChar[1] = B00100; newChar[2] = B01010; newChar[3] = B01010; newChar[4] = B11111; newChar[5] = B00100; newChar[6] = B00000;
lcd.createChar(ALARM_ICON, newChar);
newChar[0] = B00011; newChar[1] = B00101; newChar[2] = B11001; newChar[3] = B11001; newChar[4] = B11001; newChar[5] = B00101; newChar[6] = B00011;
lcd.createChar(SOUND_ICON, newChar);
newChar[0] = B00100; newChar[1] = B10010; newChar[2] = B01001; newChar[3] = B01001; newChar[4] = B01001; newChar[5] = B10010; newChar[6] = B00100;
lcd.createChar(SOUND_ICON_ON, newChar);
pinMode(BUZZER_PIN, OUTPUT);
/** * LOW to trigger the interrupt whenever the pin is low, * CHANGE to trigger the interrupt whenever the pin changes value * RISING to trigger when the pin goes from low to high, * FALLING for when the pin goes from high to low. */ attachInterrupt(SWITCH_INT, button, RISING);
/* initialize serial communication */ Serial.begin(9600); }
void loop() { long hWatherCm; int litres;
hWatherCm = read_height(); if (check_alarm(hWatherCm) != 0) /* read again wather height */ hWatherCm = read_height();
lcd.clear();
print_histogram(hWatherCm);
lcd.setCursor(0, 1);
lcd.print(hWatherCm); lcd.print(" cm - ");
// litres = SUPERFICE_BASE * (hWather / 100.0) * 1000 litres = floor(SUPERFICE_BASE * hWatherCm * 10); lcd.print(litres); lcd.print(" l ");
lcd.setCursor(14, 1); lcd.write(SOUND_ICON); lcd.setCursor(15, 1); if (!mute) lcd.write(SOUND_ICON_ON); else lcd.write('X');
/* Serial.print("cm = "); Serial.println(hWatherCm); */
switch (check_alarm(hWatherCm)) { case 1: lcd.setCursor(0, 0); lcd.write((uint8_t)ALARM_ICON);
buzz(200);
delay(DELAY\_1);
break;
case 2: lcd.setCursor(0, 0); lcd.write((uint8_t)ALARM_ICON);
buzz(200);
delay(200);
buzz(200);
delay(DELAY\_2);
break;
case 0: // no alarm delay(DELAY_0); } }
void print_histogram(int hWatherCm) { int i; int bloks; float histogram;
// hWatherCm : HPOZZO = histogram : SIZE_BAR histogram = (SIZE_BAR * hWatherCm) / H_POZZO; histogram = histogram + 0.5;
bloks = (int)histogram / 5;
for (i = 0; i < bloks; i++) lcd.write(5);
if ((int)(histogram) % 5 > 0) lcd.write((int)(histogram) % 5); }
long read_height() { /** * establish variables for duration of the ping, * and the distance result in centimeters: */ long duration, hWatherCm;
/** * The PING))) is triggered by a HIGH pulse of 2 or more microseconds. * Give a short LOW pulse beforehand to ensure a clean HIGH pulse: */ pinMode(PING_PIN, OUTPUT); digitalWrite(PING_PIN, LOW); delayMicroseconds(2); digitalWrite(PING_PIN, HIGH); delayMicroseconds(5); digitalWrite(PING_PIN, LOW);
/** * The same pin is used to read the signal from the PING))): a HIGH * pulse whose duration is the time (in microseconds) from the sending * of the ping to the reception of its echo off of an object. */ pinMode(PING_PIN, INPUT); duration = pulseIn(PING_PIN, HIGH);
/* convert the time into a distance */ hWatherCm = H_POZZO - microseconds_to_centimeters(duration);
if (hWatherCm < 0) return 0;
if (hWatherCm > H_POZZO) return H_POZZO;
return hWatherCm; }
void buzz(int msec) { if (!mute) digitalWrite(BUZZER_PIN, HIGH); delay(msec); digitalWrite(BUZZER_PIN, LOW); }
int check_alarm(int hWatherCm) { if (hWatherCm > SOGLIA_ALLARME_1) { if (hWatherCm < SOGLIA_ALLARME_2) return 1; else return 2; } return 0; }
long microseconds_to_centimeters(long microseconds) { /** * The speed of sound is 340.29 m/s or 29.4 microseconds per centimeter. * The ping travels out and back, so to find the distance of the * object we take half of the distance travelled. */ return microseconds / 29.387 / 2; }
void button() { // Serial.println("Pulsante premuto"); mute = !mute;
lcd.setCursor(15, 1); if (!mute) lcd.write(SOUND_ICON_ON); else lcd.write('X'); }
[gallery]