W tej części omówię w kilku słowach programową obsługę czujników które zostały wykorzystane w stacji meteo – prędkości i kierunku wiatru, ilości opadu, temperatury, ciśnienia, oraz wilgotności. Przedstawiony zostanie również szkielet programu.
Obsługa czujnika prędkości wiatru.
Podczas jednego obrotu czujnika prędkości wiatru wyzwalane są dwa impulsy. Do zliczania tych impulsów został wykorzystany mechanizm wykrywania zboczy, a dokładnie przerwania zewnętrze reagujące na zbocze narastające. Wykorzystywane jest przerwania zewnętrznego INT1. Konfiguracja wygląda następująco:
//dla czujnika prędkości wiatru
EICRA |= (1<<ISC11); //reakcja na zbocze opadające
EIMSK |= (1<<INT1); //aktywacja przerwania dla int1
Natomiast obsługa przerwania:
//***** przerwanie zewnętrzne od prędkości wiatru
ISR (INT1_vect){
if(!bool_meteo.hold_speed){
ds_counter_wind++;
bool_meteo.hold_speed = 1;
}
}
Zliczanie zatrzymywane jest do momentu, kiedy nie nastąpi wysłanie danych. Po wysłaniu danych ponownie uruchamiane jest liczenie impulsów.
Obsługa wskaźnika kierunku wiatru.
Jak już było wspomniane w pierwszej części serii wpisów o stacji meteo, każdy kierunek ma swoją wartość rezystancji (poprzez kontaktron zwierane są odpowiednie rezystory), dlatego do pomiaru potrzebne jest skonfigurowanie odpowiednio przetwornika ADC. Konfiguracja wraz z komentarzami przedstawia się następująco:
//********** inicjalizacja ADC
//dla czujnika kierunku wiatru
DIDR0 |= (1<<ADC0D); //wyłączenie funkcji tryby cyfrowego dla tego pinu
ADMUX &= ~(1<<ADLAR); //wyrównanie do prawej
ADMUX |= (1<<REFS0); //napięcie zasilania jako odniesienia
ADCSRA |= (1<<ADPS1) | (1<<ADPS2); //preskaler 64 - mniej niż 200khz
ADCSRA |= (1<<ADEN); //włączenie ADC
Następnie co określony czas (co około 5s) dokonywany jest pomiar z wejścia analogowego. Podczas testów stacji meteo, sprawdziłem ile wynosi odczytana wartość ADC dla każdego z 16 możliwych kierunków. Na podstawie tego utworzyłem tabelę z 3 kolumnami, gdzie w pierwszej kolumnie znajdowała się dolna wartość ADC, w drugiej górna, a w trzeciej przypisany kierunek. Dzięki ustaleniu dolnej i górnej wartości układ jest mniej wrażliwy na zmianę rezystancji, która może zmieniać się pod wpływem, np. temperatury. Tak wygląda wykorzystywana tabela:
DS_WIND_DIR const ds_direction[16] PROGMEM = {
{740,799,"N"},
{310,419,"NNE"},
{420,499,"NE"},
{75,87,"ENE"},
{88,109,"E"},
{20,74,"ESE"},
{160,209,"SE"},
{110,159,"SSE"},
{260,309,"S"},
{210,259,"SSW"},
{600,639,"SW"},
{500,599,"WSW"},
{910,1000,"W"},
{800,849,"WNW"},
{850,909,"NW"},
{640,739,"NNW"},
};
Podczas normalnej pracy stacji meteo, odczytywana jest bieżąca wartość z przetwornika ADC i sprawdzana jest w którym zakresie się ona znajduje – dany zakres ma przypisany jeden kierunek.
Obsługa czujnika ilości opadu.
Pomiar ilości opadu polega na zmianie stanu sygnału wejściowego – zmiana ta nastąpi gdy w korytku znajdzie się odpowiednia ilość wody, która w przeliczeniu jest równa 0,2794 mm / metr kwadratowy opadu. Ilość zmian sygnałów liczona jest poprzez wykorzystanie przerwania zewnętrznego INT0, reagującego również na zbocze narastające.
//dla czujnika ilości opadu
EICRA |= (1<<ISC11); //reakcja na zmianę sygnału
EIMSK |= (1<<INT0); //aktywacja przerwania dla int1
Zliczanie impulsów wykonywane jest do momentu wysłania danych do prezentera. Po wysłaniu danych ilość impulsów jest resetowana. Obsługa tego przerwania prezentowana jest następująco:
//***** przerwanie zewnętrzne od ilosci opadu
ISR (INT0_vect){
ds_counter_rain++;
}
Przy omawianiu prezentera przedstawię sposób obliczanie ilości opadu na metr kwadratowy.
Czujnik ciśnienia BMP180.
Obsługa czujnika ciśnienia została opisana w osobnym artykule do którego gorąco zachęcam – czujnik BMP180.
Czujnik wilgotności DHT22.
Również obsługa tego czujnika została zaprezentowana w innym artykule – czujnik wilgotności DHT22.
Obsługa RFM69 do komunikacji bezprzewodowej.
Biblioteka do obsługi układu RFM69 został zaczerpnięta z tzw greenbooka – Język C Pasja programowania mikrokontrolerów 8-bitowych, wydawnictwa Atnel. Biblioteka ta została obszernie opisana w wymienionej książce, a autor bardzo się przyłożył do niej – jest skuteczna i prosta w obsłudze. Zachęcam do zapoznania się z tą książką, oraz z bibliotekami opisanymi w niej.
sprintf(buf, "%04u;%02i;%04i;%03i;%04u;%03i;%01i;%03i;%01i;%01i;%03i;%01i;%s;%01i;",\
(unsigned)ds_bmp180.bmp180_pressure_cell,ds_bmp180.bmp180_pressure_frac,(unsigned)humidity,imp,\
(unsigned)adc_dir,imp_rain_gauge,sens_temp[0].subzero,sens_temp[0].cel,sens_temp[0].cel_fract_bits,\
sens_temp[1].subzero,sens_temp[1].cel,sens_temp[1].cel_fract_bits,voltage,connect_on);
Zastosowany układ wykorzystuje częstotliwość 433MHZ, a stacji meteo został przydzielony własny adres – w dość prosty sposób dzięki zastosowanej bibliotece. Następnie co określony czas wysyłany jest pakiet danych do urządzeń prezentujących warunki atmosferyczne.
A do czego jest stosowany UART?
Jak już wiecie, układ zasilany jest z baterii li-ion, która natomiast ładowana jest poprzez ogniwo fotowoltaiczne (pisałem o tym w jednym we wcześniejszych artykułach – pod tym adresem). Ładowaniem zajmuje się układ firmy ATNEL – DIGI-LION, który właśnie posiada wyjście magistrali UART. Moduł ten wysyła napięcie jakie panuje na ogniwie Li-ion, do stacji meteo, która to z kolei wysyła dane do prezentera. Dzięki temu jest możliwość bieżącego podglądu wartości napięcia na tym ogniwie.
Dodatkowo stacja meteo posiada botloader który umożliwia łatwe i szybkie wgranie nowego oprogramowania. W przyszłości, mam zamiar dodać możliwość konfiguracji stacji meteo komendami AT.
Szkielet programu – główna pętla programu.
Poniżej przedstawiam główną pętlę programu. Przed pętlą programu znajduje się konfiguracja wszystkich peryferiów podłączonych do mikrokontrolera.
while(1){
if(frequency_1hz == (TIME_MEAS-2) && status == 0){
status = 1;
//start odczytu kierunku wiatru
pomiar_adc(0);
//żądanie wykonania pomiaru temperatury dla wszystkich czujników
DS18X20_start_meas( DS18X20_POWER_EXTERN, NULL );
}else if(frequency_1hz == (TIME_MEAS-1) && status == 1){
status = 2;
//odczyt wilgotności i temperatury z dht22
ds_read_dht(&humidity, &temperature);
//odczyt ciśnienia i temperatury z bmp180
ds_bmp180_start(BMP180_OSS_8);
//przeliczenie prędkości i ilosci opadu
imp = ds_speed_wind( &speed_wind); //przeliczenie prędkości wiatru
imp_rain_gauge = ds_rain_gauge( &rain_gauge);
//odczyt temperatury z dwóch czujników
switch(meteo_conf_ram.nr_sensor_temperatur){
case 2:
DS18X20_read_meas(meteo_conf_ram.sensors[1], &sens_temp[1].subzero, &sens_temp[1].cel, &sens_temp[1].cel_fract_bits);
case 1:
DS18X20_read_meas(meteo_conf_ram.sensors[0], &sens_temp[0].subzero, &sens_temp[0].cel, &sens_temp[0].cel_fract_bits);
default:
break;
}
uint16_t adc_dir = odczyt_adc();
//przygotowanie ramki danych do wysłania
connect_on = 1;
sprintf(buf, "%04u;%02i;%04i;%03i;%04u;%03i;%01i;%03i;%01i;%01i;%03i;%01i;%s;%01i;",\
(unsigned)ds_bmp180.bmp180_pressure_cell,ds_bmp180.bmp180_pressure_frac,(unsigned)humidity,imp,\
(unsigned)adc_dir,imp_rain_gauge,sens_temp[0].subzero,sens_temp[0].cel,sens_temp[0].cel_fract_bits,\
sens_temp[1].subzero,sens_temp[1].cel,sens_temp[1].cel_fract_bits,voltage,connect_on);
}else if(frequency_1hz == (TIME_MEAS) && status == 2){
status = 0;
frequency_1hz = 0; //wyzerowanie przerwania co 1hz;
//wysyłamy
rfm69_transmit(1,buf,0);
//usypiamy rfm69
rfm69_sleep();
}
//odczyt ciśnienia
ds_bmp180_measure();
//Odbiór danych z uart - z digi-lion
UART_EVENT(buf_uart);
//uśpienie
sleep_mode();
}
Jak można zauważyć, pętla programu jest dość krótka – wszystko obsługiwane jest w kolejnych krokach, co odpowiedni czas (w tym przypadku co 1Hz). W pierwszym kroku rozpoczynany jest pomiar ADC z którego odczytywany jest kierunek wiatru, oraz wysyłane jest żądanie pomiaru dla czujników temperatury DS18B20. Następny krok polega na odczytaniu danych z czujnika wilgotności DHT22, oraz wysłaniu żądaniu pomiaru do czujnika ciśnienia BMP180. W tym kroku odczytywana i obliczana jest prędkość i kierunek wiatru, ilość opadu, oraz dokonywany jest odczyt temperatury z czujników DS18B20. Ostatnim etapem w tym kroku jest przygotowanie ramki danych do wysłania drogą bezprzewodową, które to wysłanie odbywa się w ostatnim kroku.Wykorzystany jest do tego moduł RFM69. Po wysłaniu danych usypiany jest układ RFM69 aby zaoszczędzić energię. Co obieg pętli, odczytywane jest ciśnienie, oraz obsługiwana jest komunikacja UART. Dodatkowa w celu zaoszczędzenia energii usypiany jest mikrokontroler. Wykorzystywany jest tryb IDLE – układ jest wybudzany przy każdej możliwej okazji (jest to minimalny sposób na oszczędzanie energii, ale wystarczy 😉 )
Jak można zauważyć niektóre biblioteki do obsługi odpowiednich urządzeń są mojego autorstwa a niektóre zostały zaczerpnięte z książek firmy Atnel. Podczas pisania programu, jedną z najważniejszych rzeczy, są dobrze napisane biblioteki, które umożliwiają pewną komunikację z wykorzystywanymi urządzeniami, oraz łatwość ich obsługi.
Pozdrawiam i zachęcam do komentowania.
W przypadku pytań lub znalezienia błędów – piszcie.