Allarme per filtro frigo
Link Articolo Originale:
http://www.grix.it/viewer.php?page=10082
Avvisa del momento in cui occorre sostituire il filtro che depura l'acqua dei frigoriferi tipo americano.
Ciao a tutti i Grixiani, è da un pò che seguo con interesse questo sito e fino ad oggi non avevo avuto il tempo di proporre il mio primo schema.
Due anni fa ho comprato un frigorifero di quelli americani con il dispenser dell'acqua e del ghiaccio. Questi frigoriferi incorporano un filtro che depura l'acqua del rubinetto rendendola ottima. Il problema è che, almeno per il frigorifero in mio possesso, tale filtro va sostituito ogni sei mesi e costa oltre 60€. All'interno del frigorifero c'è una scheda elettronica con un timer che con il cambio di colore di una spia, segnale che sono passati i sei mesi e che quindi occorre sostiutirlo. Le prime volte l'ho sostiuito subito, poi, leggendo le istruzioni, ho notato che il filtro può trattare fino a circa 1100 litri di acqua che diviso per 180 giorni fa poco più di 6 litri al giorno.....e chi li beve?
Un'altro problema deriva dal fatto che sul pannello di comando, c'è un tasto che se premuto per 3 secondi azzera il timer. Va premuto dopo la sostituzione del filtro, ma vallo a spiegare a mio figlio di 3 anni e mia figlia di 18 mesi!!! (ora sarà chiaro perchè non ho avuto ancora il tempo di scrivere il mio primo articolo :) )
Per questi motivi ho pensato di realizzare il circuito di figura 1 che funziona nel seguente modo:
clicca per ingrandire |
Sul tubo dell'acqua che alimenta il frigorifero ho installato un contatore lanciaimpulsi (costo attorno ai 30€) che genera un impulso ogni 'x' litri di acqua passati. Il valore dei litri 'x' è relativo al K del contatore stesso ed è scritto su quest'ultimo. Vedremo più avanti come settare il software per i vari contatori. Il PIC16F88 legge costantemente il contatto del contatore e al superamento dei 1100 litri emette dieci bip con il buzzer BZ1 e fa lampeggiare 10 volte il led rosso D2.
Il pulsante P1 ha una duplice funzione:
- se premuto brevemente emette tanti lampeggi e suoni quanti sono i litri contati fino a quel punto.La visualizzazione è fatta una cifra alla volta iniziando dalle migliaia, con tanti lampeggi della durata di 1/4 di secondo equivalenti alla cifra stessa. Poi viene fatta una pausa di un secondo, quindi vengono visualizzate le centinaia di litri e così via. Nel caso in cui la cifra sia uguale a zero, viene emesso un bip della durata di 1/4 di secondo. Esempio: se sono passati 509 litri e premo brevemente il pulsante, il led emetterà 5 lampeggi - pausa - 1 bip - pausa - 9 lampeggi.
- se premuto per 2 secondi, resetterà il numero degli litri contati. Operazione necessaria nel momento del cambio del filtro.
Nel circuito ho previsto un connettore ICSP per la programmazione on-board del micro nel caso in cui qualcuno volesse apportare delle modifiche.
Il circuito viene alimentato da due pile a bottone che possono essere delle CR2016, CR2025 oppure CR2032. Ovviamente le ultime, garantiranno una maggior durata che è stimata in circa 200 gg, in 78 gg con le CR2016 e in 148 gg con le CR2032.
Lo stato delle batterie viene monitorato dal'ingresso analogico RA0 del PIC che legge la tensione di alimetazione per mezzo del partitore formato dalle resisrenze R3 e R4. La tensione di riferimeto Vref del convertitore analogico/digitale è determinata dal generatore di tensione U2 ed è fissata a 2,5volt. Il partitore divide a metà la tensione di alimentazione e quando la tensione delle batterie scenderà sotto i 5,1 volt, il PIC farà lampeggiare il led e suonare 3 volte il buzzer per avvisare del cambio delle batterie necessario. Per limitare i consumi sia il partitore che il generatore di tensione U2 non sono sempre alimentati, ma poichè sono collegati al pin RA2, lo saranno solo quando sarà necessario il controllo della tensione delle batterie. Sempre per limitare i consumi, il PIC per gran parte del tempo, è in modalità SLEEP e viene risvegliato dagli impulsi in ingresso al pin RB5.
Realizzazione
Per realizzare il circuito ho utilizzato CIRCAD che è free e il layout del circuito stampato è visibile in figura 2.
clicca per ingrandire |
In figura 3 e 4 si può vedere la disposizione dei componenti.
clicca per ingrandire |
Ho anche realizzato un'etichetta da apporre sul contenitore. Tutti i file relativi alla realizzazione possono essere scaricati nel link sottostante:
UserFiles/davide71/Filtro_frigo.zip
Nelle foto sotto si può vedere il mio prototipo montato e il filtro del mio frigorifero.
Per la realizzazione l'unica raccomandazione riguarda il montaggio dei due slot portapile. Sono montati uno sopra e uno sotto nel lato saldature. Consiglio di saldare prima quest'ultimo.
Programma
Il programma l'ho scritto in C ed il compilatore che ho usato è il MICROC. Tutto il progetto è prelevabile al seguente indirizzo:
UserFiles/davide71/Filtro_frigo_sorgenti(1).zip
Io ho la versione completa, ma poichè la dimensione non supera 1k di memoria, dovrebbe essere complilabile anche con quella free. Il sorgente è abbastanza semplice ed è il seguente:
/*
* Nome progetto: Filtro_frigo
* Scritto da:
Davide Bandini 06 agosto 2011
rev 1.1 19 novembre 2011
* Descrizione: Legge gli impulsi di un contatore e segnala quando è ora
di sostituire il filtro che depura l'acqua nei dispenser
dei frigoriferi side-by-side
* Configurazione:
MCU: P16F88
Dev.Board: bread-board
Oscillatore: 4.0000 MHz interno
Software: mikroC v.8.2
* Note:
*/
# define VREF PORTA.F2
# define IMPULSI PORTB.F5
# define RESET PORTB.F4
# define BATTERIA PORTB.F3
# define BUZZER PORTB.F2
# define ON 1
# define OFF 0
// variabili
unsigned char cambio_filtro=0; // flag per il cambio del filtro
unsigned char ripeti=0; // flag per la ripetizione del bip del cambio filtro
unsigned char aggiorna_eeprom=0; // flag per la scrittura in eeprom
unsigned char bip_batteria=0; // contatore per il bip del cambio batteria
unsigned char k=100; // k del contatore (litri per ogni impulso)
unsigned char beep=0; // per l'emissione del suono nella visualizzazione dei litri filtrati
unsigned int temp; // variabile temporanea
unsigned int a; // variabile temporanea
unsigned int litri_max=1100; // litri massimi che può trattare il filtro
unsigned int litri=0; // contatore per i litri filtrati
unsigned int v_batt=0; // per la misura della tensione delle batterie
/* -------------------------------------------------- */
/* ---------- gestione degli interrupts ----------- */
/* -------------------------------------------------- */
void interrupt() {
//---------- gestisce la pressione dei pulsanti --------------------------------
if (INTCON.RBIF) {
// controlla se l'interrupt è l'ingresso degli impulsi
if (!IMPULSI) {
Delay_ms(100); // attesa per antibounce
if (!IMPULSI) {
litri=litri+K; // incrementa i litri
aggiorna_eeprom=1; // attiva flag per scrivere il nuovo valore dei litri
if (cambio_filtro==1) ripeti=1; // fa ripetere i 10 bip ad ogni impulso
// successivo a quello che determina il
// cambio filtro come promemoria finchè
// non viene premuto il reset
if (litri==litri_max) {
cambio_filtro=1; // attiva il flag per il cambio filtro
ripeti=1;
}
}
}
// controlla se l'interrupt è stato il reset
if (!RESET) {
Delay_ms(100); // attesa per l'antibounce
if (!RESET) {
Delay_ms(2000);
// se premuto per più di un secondo resetta perchè ho cambiato il filtro
if (!RESET) {
Delay_ms(30);
BATTERIA=ON; // accendo il led
BUZZER=ON; // attivo il buzzer
Delay_ms(2000);
BATTERIA=OFF; // spengo il led
BUZZER=OFF; // spengo il buzzer
cambio_filtro=0;
litri=0;
ripeti=0;
aggiorna_eeprom=1; // scrivo 0 litri nella eeprom
}
// altrimenti visualizza tanti lampeggi e suoni quanti sono i litri filtrati
else {
for (a=1000; a>0; a/=10){ // eseguo il ciclo 4 volte (4 cifre)
temp=(litri/a)%10; // seleziono una cifra alla volta
// eseguo questo ciclo se la cifra>0 oppure se è=0 dopo almeno una cifra>0
if (temp || beep) {
// eseguo questo se la cifra è=0 dopo almeno una cifra>0
if (!temp) {
BUZZER=ON; // emetto un breve bip
Delay_ms(250);
BUZZER=OFF;
Delay_ms(250);
}
// eseguo questo se la cifra è>0
else while (temp) {
beep=1; // questo segnala al ciclo successivo che
// c'è stata la prima cifra>0
BATTERIA=ON; // emetto un lampeggio
Delay_ms(250);
BATTERIA=OFF;
Delay_ms(250);
temp--; // decremento temp
}
Delay_ms(750); // ritardo fra la visualizzazione di ogni cifra
}
}
beep=0; // resetto beep dopo aver visualizzato tutto
}
}
}
INTCON.RBIF = 0; // resetta l'interrupt
}
}
// ---------- funzione principale ----------------------------------------------
void main() {
ANSEL = 0x01; // setta RA0 analogico e gli altri digitali
ADCON1 = 0x20; // imposta RB3 = Vref+
TRISA = 0x09; // setta PORTA
PORTA = 0x00; // azzera PORTA
TRISB = 0x30; // setta PORTB
PORTB = 0x00; // azzera PORTB
OPTION_REG = 0x0F; // abilita le pull-up su PORTB+prescaler 1/128 al WDT
WDTCON = 0x17; // reset WDT ogni 20 minuti
INTCON = 0x08; // abilita interrupt su PORTB
OSCCON = 0x6E; // imposta il clock interno a 4MHz
INTCON.GIE = 1; // attiva gli interrupt
// legge in eeprom i litri filtrati
litri=Eeprom_Read (0x00); // leggo gli 8 bit più significativi
litri<<=8;
litri=litri+Eeprom_Read (0x01); // leggo e sommo gli 8 bit meno significativi
if (litri>=litri_max) { // se >=litri_max devo cambiare il filtro
cambio_filtro=1;
ripeti=1;
}
if (litri==0xFF) { // se acceso per la prima volta scrive i litri=0
litri=0;
Eeprom_Write(0x00, 0x00); // scrive nella eeprom 0
Eeprom_Write(0x01, 0x00);
}
Delay_ms(100);
// loop infinito
while(1) {
// verifica se devo cambiare il filtro
if (cambio_filtro & ripeti) {
// si allora emette 10 bip
for (a=0; a<10; a++) {
if (litri==0) break; // se nel frattempo ho premuto reset
BUZZER=ON;
BATTERIA=ON;
Delay_ms(500);
BUZZER=OFF;
BATTERIA=OFF;
Delay_ms(500);
}
ripeti=0;
}
// verifica se la batteria è scarica (al reset del WDT o ogni impulso/pressione tasto)
VREF=ON; // accende la tensione di riferimento
v_batt = Adc_Read(0); // legge la tensione della batteria (canale AN0)
VREF=OFF; // spegne la tensione di riferimento
// se la tensione è < 5,1 V
if (v_batt<=720) {
BATTERIA=ON;
Delay_ms(20);
BATTERIA=OFF;
bip_batteria++;
// se il led ha fatto 9 lampeggi (3,5 ore) emette 3 bip
if (bip_batteria==9) {
for (a=0; a<3; a++) {
BUZZER=ON;
Delay_ms(1000);
BUZZER=OFF;
Delay_ms(1000);
}
bip_batteria=0;
}
}
// se deve aggiornare i valori nella eeprom
if (aggiorna_eeprom) {
temp=litri>>8;
Eeprom_Write(0x00, temp); // scrive gli 8 bit MSB dei litri nella eeprom
temp=litri & 0xFF;
Eeprom_Write(0x01, temp); // scrive gli 8 bit LSB dei litri nella eeprom
aggiorna_eeprom=0;
}
// se non devo cambiare il filtro e/o la batteria è carica va in sleep
asm {
sleep
nop
clrwdt // azzera il watchdog
}
}
}//~
Inizialmente c'è la definizione di alcune costanti e la dichiarazione delle variabili. Nella variabile K dovrete mettere il valore del vostro contatore affinchè il conto dei litri possa ritornare con quelli effettivamente passati. Nel mio caso il contatore è un K=100 (1 impulso ogni 100 litri). Nella variabile litri_max occorrerà mettere invece il numero massimo dei litri che il vostro filtro può trattare. Nel mio caso 1100 litri.
Segue la routine di interrupt che si occupa della gestione dell'interrupt generato dal contalitri e della pressione del pulsante P1 (RESET).
C'è poi la funzione main che inizializza gli ingressi e le uscite del PIC, setta gli interrupt, il watchdog per un risveglio ogni 20 minuti e l'oscillatore interno a 4MHz.
Poi vengono letti i litri nella EEPROM del PIC perchè nel caso di sostituzione delle batterie se non fossero stati salvati i litri letti fino a quel punto, il pic ripartirebbe da zero.
Segue un ciclo infinito che si occupa di emettere 10 lampeggi/bip se occorre cambiare il filtro, verificare lo stato della batteria facendo un breve lampeggio seguito de 3 bip nel caso sia scarica, salvare il nuovo valore dei litri nel caso ci sia stato un nuovo impulso ed infine se non c'è il filtro da sostituire e le battrie sono buone, mettere il PIC in modalità SLEEP per ridurre al massimo i consumi.
Il codice è abbastanza commentato e chiedo scusa se potrà contenere procedure laboriose che potrebbero essere semplificate, ma sono autodidatta e comunque così com'è funziona.
Vi ringrazio per la lettura e spero che questo circuito possa servire a qualcuno per lo scopo per cui è nato o chissà magari come contatore per altre applicazioni dovi si ha la necessità di segnalare con un allarme acustico/visivo il raggiungimento di un certo numero di impulsi.
Un saluto a tutti
Davide