pozzoIn 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.

Panoramica

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

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.

Schema elettrico

PCB

[download file='pozzo.pcb' name='pcb per ExpressPCB']

Sketchbook

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 */

include #define PING_PIN 13

define BUZZER_PIN 8

define SWITCH_INT 0 /* 0 => pin 2 */

define PI 3.1415926535898

define SUPERFICE_BASE (R_POZZO * R_POZZO * PI)

define SIZE_BAR (16 * 5)

define ALARM_ICON 0 /* code */

define SOUND_ICON 6 /* code */

define SOUND_ICON_ON 7 /* code */

define R_POZZO 0.5 /* raggio pozzo (m) */

define H_POZZO 146.0 /* cm */

define SOGLIA_ALLARME_1 100 /* cm */

define SOGLIA_ALLARME_2 120 /* cm */

define DELAY_0 60000 /* ms; 1000 * 60 * 1 = 1 min */

define DELAY_1 600 /* ms */

define DELAY_2 200 /* ms */

/* 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'); }

Immagini

[gallery]