Pomiar natężenia oświetlenia jest powszechny w naszym codziennym życiu. Prawdopodobnie każdy w swoim smartfonie ma funkcje automatycznego ściemniania/rozjaśniania ekranu. Bazuje ona właśnie na pomiarze natężenia światła w otoczeniu urządzenia. Pomiar wykonywany jest na bieżąco w czasie gdy telefon jest odblokowany. Dzisiaj skupię się na tym jak możemy zmierzyć ten parametr za pomocą trzech różnych czujników. Czy dadzą zbliżone pomiary?

Pomiar światła – dzisiejsi bohaterowie

Pomiaru światła będę dokonywał trzema czujnikami: BH1750, MAX44009 oraz TEMT6000.

Dokumentacje do tych układów możesz pobrać stąd:

BH1750FVI Datasheet MAX44009 Datasheet TEMT6000 Datasheet

Schemat i konfiguracja Cube

Jako, że kolejny raz działam na gotowych, chińskich modułach to schemat jest dosyć prosty.

Dwa z badanych dzisiaj czujników komunikują się za pomocą interfejsu I²C. Dodatkowo jeden może wystawiać przerwania dlatego wyznaczę dla niego odpowiedni pin. Trzeci z omawianych dzisiaj układów wystawia wartość analogową. Dlatego też trzeba przygotować jedno z wejść analogowych. Pinout ostatecznie wygląda tak.

I²C konfiguruję na 400kHz. Przerwanie natomiast będzie potrzebne z reakcją na zbocze opadające. Konfigurację ADC omówię później przy odpowiednim czujniku.

BH1750

Pierwszym z testowanych czujników jest niskoprądowy układ BH1750 firmy ROSH Semicondutor( BH1750FVI Datasheet). Porozmawiać z nim można przez interfejs I²C z maksymalną częstotliwością zegara 400 kHz. Posiada on wbudowany przetwornik ADC, który zamienia mierzoną wartość natężenia światła na postać cyfrową. Jego zakres pomiarowy to 1 – 65535 lux. Czujnik ten ma możliwość kalibracji wrażliwości pomiaru. Dzięki temu jest w stanie wykryć już 0.11 lux. Ustawieniem tym można też dopasować go do materiału osłaniającego np. szyby. Należałoby znać wartość przepuszczanego światła przez ów materiał. Szczegóły znajdziesz w dokumentacji.

Czujnik może pracować w kilku trybach:

  • Ciągły wysokiej rozdzielczości (1lx)
  • Ciągły wysokiej rozdzielczości 2 (0,5lx)
  • Ciągły niskiej rozdzielczości (4lx)
  • Ręczny wysokiej rozdzielczości (1lx)
  • Ręczny wysokiej rozdzielczości 2 (0,5lx)
  • Ręczny niskiej rozdzielczości (4lx)

Producent zaleca używanie trybu wysokiej rozdzielczości o rozdzielczości 1 lux. Ponoć dobrze sobie radzi z zakłóceniami. Mi też on się podoba, bo wartość w rejestrach pomiaru nie będzie musiała być przeliczana. W trybie ciągłym pomiar dokonywany jest cyklicznie w odstępach czasu 120 ms lub 16 ms w zależności od wybranego trybu. W trybie ręcznym natomiast konwersja wywoływana jest tylko raz. Należy odczekać wtedy aż przetwornik ADC zakończy pracę(120 ms dla highres i 16 ms dla lowres) zanim będzie można odczytać wartość pomiaru. W odróżnieniu do pracy ciągłej, przy wywołaniu manualnym czujnik po zakończonej konwersji automatycznie przechodzi w tryb Power Down gdzie pobór prądu jest znikomy(typ. 0,01 µA) w porównaniu do tego, który jest wymagany do konwersji(typ. 120 µA). Nie trzeba czujnika ręcznie budzić. Wystarczy zlecić mu konwersję.

Tablica rejestrów w zasadzie nie jest tablicą rejestrów. Z czujnikiem komunikuję się za pomocą zestawu komend nie pisząc nic bezpośrednio do jego pamięci. No to przechodzimy do kodu.

W pierwszym kroku należałoby zainicjować czujnik. Oprócz stanadrdowego przekazania wskaźnika na używany interfejs I²C, resetuję czujnik oraz ustawiam mu default’ową wartość measurement time.

1
BH1750_STATUS BH1750_Init(I2C_HandleTypeDef *hi2c);

Do resetowania czujnika oraz kontrolowania stanu Power Down służą funkcje

1
2
BH1750_STATUS BH1750_Reset(void);
BH1750_STATUS BH1750_PowerState(uint8_t PowerOn);

Gdyby przyszła potrzeba zmiany czułości czujnika, użyj funkcji

1
BH1750_STATUS BH1750_SetMtreg(uint8_t Mtreg);

Ustawienie trybu w którym ma działać czujnik dokonasz za pomocą

1
BH1750_STATUS BH1750_SetMode(bh1750_mode Mode);

przy pomocy zmiennej enumeracyjnej z predefiniowanymi komendami. Dzięki temu jest zmnieszone ryzyko pomyłki.

1
2
3
4
5
6
7
8
9
typedef enum
{
CONTINUOUS_HIGH_RES_MODE = 0x10,
CONTINUOUS_HIGH_RES_MODE_2 = 0x11,
CONTINUOUS_LOW_RES_MODE = 0x13,
ONETIME_HIGH_RES_MODE = 0x20,
ONETIME_HIGH_RES_MODE_2 = 0x21,
ONETIME_LOW_RES_MODE = 0x23
}bh1750_mode;

Jeżeli korzystać będziesz z trybu ręcznego, potrzebna będzie funkcja zlecająca konwersję. Tak na prawdę to ona przesyła komendę ustawienia trybu konwersji bo tak wymaga czujnik, ale kto by pamiętał przez cały projekt jaki tryb jest użyty 😉

1
BH1750_STATUS BH1750_TriggerManualConversion(void);

No i najważniejsze. Funkcja odczytu wartości, którą zmierzył czujnik. Użycie nie powinno być problematyczne.

1
BH1750_STATUS BH1750_ReadLight(float *Result);

Jak wygląda odczyt z czujnika? Wystarczy odebrać dane bezpośrednio spod jego adresu. Jego adres jest jednocześnie rejestrem z którego czytany jest wynik. Nie ma tutaj większej filozofii stąd też odczyt i przeliczenie wartości są błyskawiczne. W trybie high resolution 2 z dokładnością 0,5 lux jest to 0,28 ms dla zegara I²C 100 kHz oraz 80 µs dla 400 kHz.

100 kHz:

400 kHz:

Pamiętaj, że chcąc korzystać z manualnej konwersji należy między zleceniem pomiaru a odczytem odczekać odpowiedni czas. Oczywiście odczyt danych można zrobić przy pomocy DMA. Spróbuj samemu to wykonać 🙂

MAX44009

Kolejnym z omawianych dzisiaj czujników jest układ MAX44009 firmy Maxim Integrated ( MAX44009 Datasheet). Podobnie jak BH1750 posiada wbudowany konwerter analogowo-cyfrowy oraz interfejs komunikacyjny I²C. Różni się od niego między innymi sposobem kodowania wyniku pomiaru. Jest on zapisany w postaci zmiennoprzecinkowej o 4-bitowym wykładniku i 8-bitowej mantysie. O liczbach zmiennoprzecinkowych pisałem tutaj. Sposób w jaki przechowywana jest wartość pomiaru pozwala na odczytywanie wyniku z różną dokładnością. Można bowiem odczytać dwa rejestry i mieć wynik w wysokiej rozdzielczości, a można pominąć drugi rejestr, który zawiera młodsze bity mantysy i cieszyć się z szybszego uzyskania wyniku lecz w niższej rozdzielczości.

Inną różnicą jest pin INT, czyli możliwość wystawienia przez układ przerwania dla mikrokontrolera. Przerwanie może być wystawione po przekroczeniu jednego z konfigurowanych progów wartości natężenia oświetlenia – górnej lub dolnej. Jednocześnie określa się minimalny czas przez który próg ma być przekroczony, aby zdecydować o wystawieniu przerwania. Oczywiście progi mogą być nastawione dwa na zasadzie okna. Co ważne przerwanie będzie wystawione nawet jeśli będzie on dział w trybie manualnym.

Ze względu na to, że MAX44009 jest nieco bardziej rozbudowany, biblioteka jest obszerniejsza. Inicjalizacja jedynie przypisuje wskaźnik do I²C:

1
MAX44009_STATUS MAX44009_Init(I2C_HandleTypeDef *hi2c);

Następnie znajdują się funkcje konfiguracyjne czujnik. Można skorzystać z wpisania za jednym razem odpowiedniej wartości do rejestru, lub użyć kilku wygodnych samokomentujących się funkcji zmieniających tylko jedną funkcję.

1
2
3
4
5
6
7
MAX44009_STATUS MAX44009_ReadConfigurationRegister(uint8_t *Config);
MAX44009_STATUS MAX44009_WriteConfigurationRegister(uint8_t Config);

MAX44009_STATUS MAX44009_ContinuousMode(uint8_t Enable);
MAX44009_STATUS MAX44009_ManualConfiguration(uint8_t Enable);
MAX44009_STATUS MAX44009_CurrentDivisionRatio(uint8_t Enable);
MAX44009_STATUS MAX44009_IntegrationTime(max44009_timer Timer);

Zwróć uwagę na ostatnią funkcję, która jako argument przyjmuje enuma:

1
2
3
4
5
6
7
8
9
10
11
typedef enum
{
INTEGRATION_TIME_6_25_MS = 0x07, // Manual mode only
INTEGRATION_TIME_12_5_MS = 0x06, // Manual mode only
INTEGRATION_TIME_25_MS = 0x05, // Manual mode only
INTEGRATION_TIME_50_MS = 0x04, // Manual mode only
INTEGRATION_TIME_100_MS = 0x03, // This is a preferred mode for high-brightness applications
INTEGRATION_TIME_200_MS = 0x02,
INTEGRATION_TIME_400_MS = 0x01,
INTEGRATION_TIME_800_MS = 0x00 // This is a preferred mode for boosting low-light sensitivity
} max44009_timer;

Najważniejszą częścią jest oczywiście odczytanie wartości oświetlenia w otoczeniu czujnika. Jak wspominałem wcześniej, można wykonać to w dwojaki sposób i też to uwzględniłem.

1
2
3
</p>
MAX44009_STATUS MAX44009_ReadLightLowResolution(float *Result);
MAX44009_STATUS MAX44009_ReadLightHighResolution(float *Result);

Tutaj jest pewna ciekawostka. Otóż dokumentacja mówi: “If user wants to read both the Lux High-Byte register 0x03 and Lux Low-Byte register 0x04, then the master should not send a STOP command between the reads of the two registers. Instead a Repeated START command should be used.” . Co to oznacza? Układ sam zinkrementuje adres rejestru do odczytu pod warunkiem, że po zczytaniu pierwszego powtórzy sekwencje startu na magistrali I²C. Niestety korzystając z funkcji HAL’owej HAL_I2C_Mem_Read mikrokontroler nie wystawia bitu startu między kolejnymi odczytanymi bajtami. Powoduje to, że czujnik podaje dwa razy wartość rejestru 0x03 zamiast 0x04 w drugim bajcie.

Najprostszym rozwiązaniem będzie po prostu dwukrotne wywołanie HAL_I2C_Mem_Read. Niestety kosztuje to drugie wywołanie adresu czujnika oraz podaniemu z którego rejestru chce się czytać.

Jeżeli okaże się, że trzeba ten czas skrócić z jakiegoś powodu, rozwiązaniem może być zastosowanie funcji HAL_I2C_Master_Sequential_Receive_IT. Spróbuj z jej pomocą ulepszyć odczyt 🙂

Na koniec pozostały jeszcze funkcje użyteczne przy przerwaniach.

1
2
3
4
5
6
MAX44009_STATUS MAX44009_ReadInterruptStatus(uint8_t *Status);
MAX44009_STATUS MAX44009_WriteInterruptEnable(uint8_t Enable);

MAX44009_STATUS MAX44009_SetUpperThreshold(float Threshold);
MAX44009_STATUS MAX44009_SetLowerThreshold(float Threshold);
MAX44009_STATUS MAX44009_SetThresholdTimer(uint8_t Timer);

Kasowanie flagi przerwania w czujniku dokonuje się automatycznie po odczytaniu rejestru statusowego lub wyłączeniu przerwania. Wartości graniczne które mają wpływ na wystawienie przerwania podawane i przechowywane są przez czujnik w postaci zmiennoprzecinkowej o obniżonej rozdzielczości(4-bitowy wykładnik i 4-bitowa mantysa). Pamiętaj o tym ograniczeniu. Czas spełnienia warunku wymagany do wystawienia przerwania przyjmowany w argumencie jest w dziesiątkach milisekund(wartość * 10 ms). Czyli dla nastawienia sekundy w argumencie podać należy wartość 100.

Jeszcze trochę liczb i wykresów.

100k low resolution:

400k low resolution:

100k high resolution:

400k high resolution:

 Low resolutionHigh resolution
100 kHz0,38 ms0,78 ms
400 kHz0,1 ms0,2 ms

Jak widać zegar 400 kHz bije na głowę 100 kHz. Nawet odczyt wysokiej rozdzielczości dla zegara 400k jest szybkszy niż niskiej przy 100k. Do tego pamiętaj, że ten odczyt nie jest optymalny bo można go jeszcze przyśpieszyć.

Przetestowałem również działanie progów dla przerwania. Ustawiłem próg na 300 lux. 

Przerwanie jest aktywne stanem niskim.

Działa jak trzeba 🙂

TEMT6000

Ostatnim omawianym dzisiaj czujnikiem światła jest TEMT6000 firmy Vishay. Tym razem nie jest to kompletny układ scalony z wbudowanym przetwornikiem ADC. Element ten to fototranzystor NPN. Prąd na jego kolektorze jest proporcjonalny do ilości padanego światła. Ta zależność to 1 µA = 2 lux co jest łatwe do przeliczenia.

Ściąganie pomiarów i obliczenia musimy zrobić sami na STM32. Na szczęście MCU ma wbudowany przetwornik ADC o rozdzielczości 12 bitów co ułatwia sprawę. Chiński moduł posiada rezystor wpięty w szereg z emiterem dzięki czemu zgodnie z prawem Ohma napięcie odkładane na nim jest proporcjonalne do przepływającego prądu, a ten z kolei jest proporcjonalny do ilości padanego światła na fotoczułą bazę. Wystarczy więc znać spadek napięcia na rezystorze. Wlutowany został opornik o wartości 10 kΩ niestety o tolerancji 5% co będzie miało wpływ na wyniki pomiarów. Zdecydowanie lepiej jest już przełknąć te pół grosza i wlutować element z tolerancją 1%.

W takim układzie z moich obliczeń wynika, że 1 lux = 5 mV na rezystorze.

Cała konfiguracja czujnika polega na skonfigurowaniu przetwornika ADC w mikrokontrolerze. Ja podpiąłem czujnik do kanału IN0 ADC1. Można go skonfigurwać na 3 sposoby jeśli chodzi o sposób czytania wyniku konwersji.

  1. Polling, czyli ręczne zlecenie konwersji i oczekiwanie na jej zakończenie aby odczytać wartość
  2. Trzyb przerwaniowy – czytanie z ADC po ukończonej konwersji. Angażuje CPU
  3. DMA – cała procedura zlecania konwersji oraz czytania z ADC jest automatyczna i nie wymaga angażowania CPU

Co wybrać? To chyba jasne – DMA 🙂 Nie zawracałbym sobię głowy innym trybem przy tak prostym elemencie.

Konfiguracja w STM32CubeMX jest prosta. Prescaler ustaw na jak najniższy dzięki temu ADC będzie działał szybciej chyba, że budujesz urządzenie bateryjne. Wtedy liczy się pobór prądu. Rozdzielczość zostaw 12-bitową. Włącz tryb ciągłej konwersji. Dzięki temu ADC będzie ciągle samo sobie zlecało konwersję. Musisz włączyć również zapytania do DMA po zakończonej konwersji. Jest to takie szturchnięcie DMA, aby przepisał wynik pomiaru do wybranego miejsca w pamięci. W dalszej kolejności ważnym parametrem jest Sampling Time. Istnieje tutaj zależność mięczy czasem samplowania, a dokładnością. Jak można się domyślić krótszy czas oznacza mniejsza dokładność. Ustawiłem maksymalny czas bo zależy mi na dokładności.

Zostaje jescze ustawienie DMA oraz przerwania. DMA należy postawić dla wybranego ADC. Włącz mu tryb Circular oraz zaznacz, aby inkrementował adres pamięci – będzie to potrzebne do uśredniania próbek.

W ustawieniach NVIC upewnij się, że masz włączone przerwanie od DMA Stream. Jeżeli masz aktywne przerwanie od ADC – wyłącz je. Nie będzie potrzebne w tym wypadku.

Po tych ustawieniach w zasadzie czujnik działa sam. Jedyne co trzeba zrobić to uruchomić konwersję oraz przeliczać wartość ADC na wartość lux.

Służą do tego tylko dwie funkcje

1
2
3
TEMT6000_STATUS TEMT6000_Init(ADC_HandleTypeDef *hadc);

TEMT6000_STATUS TEMT6000_ReadLight(float *Result);

Inicjalizacja startuje konwersję DMA na podanym ADC. Odczyt przelicza wartość ADC na ilość padanego na czujnik światła. Jak policzyć tą wartość?

Potrzebna jest wiedza o tym jakie jest napięcie referencyjne dla przetwornika ADC. W dokumentacji płytek Nucleo znalazłem, że odpowiada za to zworka SB57. Domyślnie jest ona zamknięta co prowadzi do tego, że na pin Vref+ podane jest napięcie VDD, czyli 3,3 V.  Ilość różnych wyników ADC to 4096 dla rozdzielczości 12 bit, więc wynik należy pomnoścyć przez wartość napięcia odniesienia i podzielić przez maksymalną liczbę pomiarów. Wartośc którą otrzymałem w ten sposób to ilość woltów na rezystorze. Łatwiej jednak byłoby przeliczać w miliwoltach, więc wynik mnożę razy 1000. Teraz wiedząc, że 1 lux = 5 mV, dzielę tą wartość przez 5. Po skróceniu działań wynik wygląda następująco:

Lux = ((AdcValue * 3.3) / 4096) * 200;

Zaimplementowałem również uśrednianie pomiarów. Liczbę pomiarów do uśredniania definiuje się poprzez TEMT6000_ADC_SAMPLES w pliku nagłówkowym. Zmniejsza to wahania na przetworniku ADC.

Porównanie

Przyszedł czas na porównanie tych trzech czujników. Umieściłem je na jednej, małej płytce stykowej po to, aby były blisko siebie. Do oświetlania użyłem lampy, która daje równomierne światło i stoi w znacznej odległości od płytki. Dzięki temu światło rozkłada się równomiernie na każdy czujnik. Do wykresów idealnie sprawdzi się tutaj STM32 Studio. Pomiar światła na moim biurku przy standardowym oświetleniu w pokoju wyląda następująco.

Fototranzystor TEMT6000 po przeliczeniu wartości wskazuje o wiele niższy poziom naświetlenia niż pozostałe badane czujniki. Co ciekawe aplikacja na spartfonie wskazuje około 575 lux, co jest znacznie wyższą wartością niż pokazują wszystkie czujniki. Przykryłem dłonią wszystkie czujniki i zgodnie z przewidywaniami, wskazania spadły prawie do zera i dla każdego z czujników, łącznie ze smartfonem wyniki są zbliżone(ok 10 lux).

Niespodzianka i ogromne rozczarowanie przychodzi z mocniejszym oświetleniem wszystkich czujników.

Jak widać każdy pokazuje co chce… Czujnik w smartfonie odleciał natomiast do około 2500 lux. Która wartość jest najbliższa prawdzie? Nie potrafię tego powiedzieć bez profesjonalnego, kalibrowanego luxomierza.

EDIT: Po głębszej analizie

No dobra, posiedziałem jeszcze trochę nad tymi czujnikami i trybem debugowym w Eclipse. Zauważyłem, że wartość ADC dla mocno oświetlonego TEMT6000 jest bliska maksymalnej. Skoro tak, to na rezystorze odłożyło się prawie całe napięcie zasilania. W rzeczywistości było to około 3 V, bo trochę odpada na złącze kolektor-emiter fototranzystora. Policzmy z prostego prawa Ohma jaki prąd płynął przez fabryczny rezystor 10 kΩ.

I = 3 [V] / 10000 [Ω] = 0,0003 [A] = 300 [µA]

Z tego wynika, że maksymalną wartość w luxach jaką może pokazać TEMT6000 z fabrycznym rezystorem 10 kΩ to około 600 lux. Wziąłem mocniejszą lampę i faktycznie tak jest. Pomiar zatrzymuje się kawałek przed 700 lux. Co teraz?

Należałoby wymienić rezystor. Na jaki? Mamy w zasadzie jedno ograniczenie – maksymalny prąd kolektora, przez który może popłynąć maksymalnie 20 mA co równa się ok 40000 lux. Taka wartość jest zdecydowanie za duża do normalnego użytku. Wprowadzi to też mniejszą rozdzielczość pomiarową bo ADC może zmierzyć tylko 4096 poziomów. 10000 lux będzie już lepszą wartością. Jaki rezystor będzie potrzebny? 10000 lux to 5000 µA a taki prąd, aby odłożyć 3 V na rezystorze to ten musi mieć wartość:

R = 3 [V] / 0,005 [A] =  600 [Ω]

Nie mam pod ręką takiego rezystora SMD, ale mam 1 kΩ, co pozwoli na uzyskanie maksymalnie 6000 lux. I faktycznie pomiar działa lepiej lecz nadal czujnik ten pokazuje o wiele niższą wartość niż pozostałe dwa – cyfrowe. Zastanawiałem się co jeszcze może mieć na to wpływ.

Sprawdziłem reakcje widmową tych czujników. Wziąłem wykresy z każdej dokumentacji i wstawiłem je na jeden wykres. Dołożyłem jeszcze krzywą odpowiadającą za to jak światło postrzega ludzkie oko.

Niestety pomiar swiatła jest subiektywny. Zasada w tego typu pomiarach jest taka, że czujnik powinien mieć charakterystykę jak najbardziej zbliżoną do ludzkiego oka. Jak widać wszystkie moje dzisiejsze czujniki trochę odbiegają od ‘normy’. TEMT6000 w ogóle łapie sporo światła z zakresu podczerwieni. Sprawdziłem nawet pilotem od TV reakcje wszystkich trzech i tylko TEMT6000 reagował na diodę IR.

Niestety nie jestem dobry z fotoelektroniki i nie wytłumaczę dlaczego TEMT6000 mimo większych czułości w szerszym zakresie podaje dużo niższe wyniki. Fajnie jakby znalazł się ktoś kto nam to wyjaśni w komentarzu. Jednak do dokładnego pomiaru światła widzialnego wykreśliłbym TEMT6000. Może on się co najwyżej nadać do ściemniania wyświetlacza i takie też zastosowanie ma wypisane w dokumentacji.

Czujniki cyfrowe mają wbudowane układy przetwarzające sygnał padający na fotodiody/fototranzystory. Zapewne jest w nich trochę magicznej obróbki i kompensacji, stąd wyniki są zbliżone do siebie.

Podsumowanie

Czujniki światła konwertujące na ilość padanych na nie luxów to bardzo kuszące układy. Jednak jak wykazały bezpośrednie porównania każdy mimo, że reaguje na ilośc światła zgodnie z zamierzeniami (im więcej tym więcej wskazuje), to wartości bezwzględne są rozjechane. Bardzo chętnie wykonałbym porównanie do porządnego, certyfikowanego luxomierza. Dzięki temu można byłoby określić który z badanych dzisiaj czujników wart jest zakupu. Te czujniki kosztują grosze, więc nie spodziewałem się po nich cudów. Nie użyłbym ich do budowanie precyzyjnego miernika.

Jednak nie przekreślałbym totalnie każdego z nich. Jako czujniki ogólnego zastosowania w sytuacji gdy chcemy sprawdzić np. czy jest ciemniej czy jaśniej mogą sprawdzić się idealnie. Nie zawsze potrzebna jest wiedza o tym ile luxów jest w okół. Np smartfon domyślnie nigdzie  nie podaje wartości natężenia światła. Jego czujnik ma tylko określić czy jest jasno czy ciemno i na tej podstawie okreslić jasność podświetlenia. Takiej kalibracji można dokonać dla każdego czujnika i w efekcie mogą pracować z mniej więcej podobnym efektem.

Projekt z kodem dla wszystkich czujników znajduje się na moim GitHubie: link

Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś, chciałbyś coś dodać istotnego lub po prostu uważasz, że chciałbyś podystkutować w tym temacie, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.


Raz na jakiś czas wyślę Ci też e-mail z ciekawymi rzeczami które znalazłem


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Serwis wykorzystuje pliki cookies. Korzystając ze strony wyrażasz zgodę na wykorzystywanie plików cookies. Więcej informacji znajdziesz na stronie Polityka Prywatności

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close