[166] Odczyt licznika wody cz. 2
Mając wiedzę z poprzedniego artykułu, moglibyśmy już napisać właściwy szkic, jednak system zastawił na nas pułapkę. Gdy akurat czujnik ustawi się w pozycji pomiędzy, może dojść do niekontrolowanego przełączania się odczytów i naliczą nam się litry, choć nic nie będzie kapać. Brakuje tak zwanej histerezy. Można to zrobić elektronicznie, ale od czego mamy Arduino?
const byte phototransistor = A0; // Port fototranzystora.
const byte led = 13; // Port diody stanu fototranzystora.
const int threshold = 303; // Środek między napięciem "ciemnym" i "jasnym", początkowo 512.
const int hysteresis = 50; // Histereza.
bool ledState = false; // Stan diody stanu fototranzystora.
void setup() {
pinMode(led, OUTPUT);
Serial.begin(115200);
}
void loop() {
int voltage = analogRead(phototransistor); // Prześlij wartość napięcia fototranzystora do zmiennej.
Serial.println(voltage); // Wyślij ją na monitor.
if (voltage < threshold - hysteresis) { // Jeśli napięcie spadło poniżej progu i histerezy...
ledState = true; // Ustaw stan diody.
} else if (voltage > threshold + hysteresis) { // Jeśli napięcie wzrosło powyżej progu i histerezy...
ledState = false; // Zeruj stan diody.
}
digitalWrite(led, ledState); // Prześlij stan diody do portu diody.
delay(100);
}
Podłączymy się teraz na pin analogowy. Powołamy do życia port fototranzystora, który nie będzie badać stanu cyfrowego, a napięcie. Ten szkic będzie wymagać kalibracji, więc na początek próg przełączania ustawimy na środek – czyli na wartość 512. Utworzymy też współczynnik histerezy. Co to jest? To pewna wartość, tak dobrana, że przełączanie stanu diody nastąpi tylko jeśli napięcie będzie niższe od połowy minus ta wartość albo wyższe od połowy plus ta wartość. Innymi słowy, jeśli napięcie będzie sobie pływać na progu przełączania, czyli w okienku o podwójnej wartości histerezy, żadnej reakcji nie będzie.
Skompilujmy tę wersję, na razie nie przejmując się jej działaniem. Ustawmy tarczę w najciemniejszej pozycji i sczytajmy wartości wyświetlane w polu monitora. Potem przesuńmy ją w pozycję najjaśniejszą i ponownie sczytajmy te wartości. U mnie wyszło mniej więcej 25 oraz 580. Nie musimy ich traktować tak dokładnie, tylko mniej więcej. Teraz rozwiążemy równianie: dodajemy obie wartości do siebie i wynik dzielimy przez dwa. Da nam to 303 i tę wartość należy wpisać do szkicu. Parametr „histereza” powinien przyjmować mniej więcej dziesięć procent zakresu pracy. Wstawiłem 50. Po kompilacji dioda powinna się przełączać już bez ryzyka mrugania w stanach pośrednich. Szczegóły działania algorytmu wyjaśniłem w komentarzach.
I jeszcze jedna moja uwaga: środek przedziału możemy równie dobrze określić mierząc napięcia woltomierzem i przeliczając wynik na dziesięciobitową wartość – jak widać, wyszło praktycznie tyle samo. Skoro wszystko działa, zbudujmy licznik. W tym celu użyję wyświetlacza na płytce edukacyjnej TME. Ograniczę się do pierwszych ośmiu znaków, dzięki czemu można będzie użyć takich właśnie małych wyświetlaczy.
#include <Wire.h> // Biblioteka obsługująca magistralę I2C
#include <hd44780.h> // Biblioteka obsługująca wyświetlacze 44780
#include <hd44780ioClass/hd44780_I2Cexp.h> // Dodatek obsługujący wyświetlacze podłączone do ekspandera I2C
hd44780_I2Cexp lcd(0x20, I2Cexp_MCP23008, 7, 6, 5, 4, 3, 2, 1, HIGH); // Konfiguracja połączeń wyświetlacza LCD
const byte phototransistor = A0; // Port fototranzystora.
const byte led = 13; // Port diody stanu fototranzystora.
const int threshold = 303; // Środek między napięciem "ciemnym" i "jasnym", początkowo 512.
const int hysteresis = 50; // Histereza.
bool currDisc = false; // Obecny stan tarczy.
bool prevDisc = false; // Poprzedni stan tarczy.
unsigned long waterMeter = 999999; // Licznik wodomierza.
char text[8]; // Tablica dla reprezentanta znakowego licznika wodomierza.
void setup() {
pinMode(led, OUTPUT);
lcd.begin(16, 2);
lcd.print("000000 >"); // Wyślij grafikę startową.
}
void loop() {
int voltage = analogRead(phototransistor); // Prześlij wartość napięcia fototranzystora do zmiennej.
if (voltage < threshold - hysteresis) { // Jeśli napięcie spadło poniżej progu i histerezy...
currDisc = true; // Ustaw stan tarczy.
} else if (voltage > threshold + hysteresis) { // Jeśli napięcie wzrosło powyżej progu i histerezy...
currDisc = false; // Zeruj stan tarczy.
}
if (!prevDisc && currDisc) { // Jeśli stan tarczy zmienił się z niskiego na wysoki...
waterMeter++; // Zwiększ wartość licznika wodomierza
if (waterMeter > 999999) { // Jeśli przekroczył wartość maksymalną...
waterMeter = 0; // Zeruj go.
}
lcd.setCursor(0, 0); // Ustaw kursor na początku wyświetlacza.
snprintf(text, sizeof(text), "%06lu", waterMeter); // Formatuj tekst licznika wodomierza.
lcd.print(text); // Prześlij go na wyświetlacz.
lcd.print(" >"); // Wyświetl grafikę związaną z obrotem tarczy.
} else if (prevDisc && !currDisc) { // Jeśli stan tarczy zmienił się z wysokiego na niski...
lcd.setCursor(6, 0); // Ustaw kursor.
lcd.print(" <"); // Wyświetl grafikę związaną z obrotem tarczy.
}
prevDisc = currDisc; // Załaduj obecny stan tarczy do zmiennej jej poprzedniego stanu.
digitalWrite(led, currDisc); // Prześlij stan tarczy do portu diody.
}
Ponieważ ten mój jest podłączony przez ekspander I2C, trzeba użyć stosownych bibliotek. Wyświetlacz ten już wielokrotnie wystąpił w artykułach, więc ten etap omawiania programu pominę. Zmienimy nazwy niektórych zmiennych, bo teraz będą mieć inny sens. W części wstępnej wyświetlimy sześć zer oraz wskaźnik obrotu tarczy – odpowiednik diody świecącej z poprzedniego szkicu, której obsługę zresztą pozostawię. Użyłem znaków mniejszości i większości, będą one naprzemiennie ukazywać się na końcu wyświetlacza, tworząc taką prymitywną animację.
Zaczynamy podobnie: mierzymy napięcie i ładujemy do binarnej zmiennej stan odczytany – z uwzględnieniem histerezy, co poznaliśmy już w poprzednim szkicu. W kolejnym warunku będziemy rozpoznawać chwile, gdy stan zmienił się z niskiego na wysoki lub odwrotnie. Jeśli zaszło pierwsze zdarzenie, zwiększamy licznik litrów – przypomnę: jeden obrót tarczy to jeden litr. Jeśli przeczymy wartość licznika, wyzerujemy go. Oprócz tego ustawimy kursor na początku wyświetlacza i za pomocą sprytnej instrukcji zamieniającej liczby na łańcuchy, sformatujemy stan licznika tak, by zawsze widać było sześć cyfr – z zerami nieznaczącymi. Na końcu wyświetlimy jeszcze pierwszą grafikę animacji.
W przypadku odwrotnym, czyli zmiany stanu wysokiego na niski, nie będziemy liczyć litrów, a tylko zadbamy o wyświetlenie drugiej grafiki animacji. Po tym wszystkim jeszcze trzeba przepisać stan fototranzystora do pomocniczej zmiennej, przechowującej poprzedni jego stan i wysłać go na diodę świecącą.
I to już wszystko. Mamy prosty licznik, dublujący ten na cyferblacie, ze wskaźnikiem aktywności przepływu. Tutaj należałoby zadbać o zasilanie buforowe, by nam się całość przypadkiem nie zresetowała. Stan licznika można też zapisywać w pamięci nieulotnej, na przykład co metr sześcienny. Mając komputerek, możemy wykrywać zbyt duży przepływ – zdarzający się gdy pęknie jakaś rura oraz zbyt długi przepływ – na wypadek jakiegoś wycieku o mniejszej mocy, ale trwającego zdecydowanie za długo. Można także dane eksportować w świat, radiowo czy jakkolwiek inaczej. Ale o tym napiszę innym razem.

Inne artykuły z tej kategorii
Fotograficzny kalkulator raz jeszcze


































































