BH1750. Czujnik światła otoczenia z magistralą I2C.
BH1750 to czujnik oświetlenia otoczenia o stosunkowo wysokiej rozdzielczości i czułości. Zachowuje się w obliczu światła widzialnego w sposób porównywalny do ludzkiego oka, nie podlega działaniu promieniowania podczerwonego ani nie zależy od temperatury barwowej rodzaju oświetlenia, czyli dobrze współpracuje ze światłem naturalnym oraz różne rodzaje sztucznego oświetlenia. Komunikuje się cyfrowo z mikrokontrolerem, za pomocą Magistrala I2C, dzięki czemu jest odporny na zakłócenia, jeśli zostanie umieszczony w określonej odległości od obwodu, który go odczytuje. Jego czas reakcji jest dość krótki, w najbardziej niesprzyjających warunkach poniżej 200 ms.
Z elektronicznego punktu widzenia jego wdrożenie jest bardzo proste. Wystarczy podłączyć zasilanie (od 2,4 V do 3,6 V) i Magistrala I2C. Opcjonalnie istnieje możliwość zmiany adresu magistrali w celu połączenia dwóch urządzeń (przy ADDR na niskim poziomie jest to 0B0100011 lub 0x23 a przy ADDR na wysokim poziomie jest to 0B1011100 lub 0x5C) a linię VDI można wykorzystać do funkcji resetu za pomocą mikrokontroler.
Aby podłączyć BH1750 do Arduino, oprócz zasilania z wyjścia 3,3 V, najbardziej poprawne jest użycie konwertera poziomu oprócz rezystory podciągające dla Magistrala I2C. Chociaż komponent będzie obsługiwał bezpośrednie połączenie z magistralą Magistrala I2C Nie zaleca się dobierania rozmiaru obwodu bez uwzględnienia konwersji poziomu.
Ze względu na jego popularność, wynikającą z bardzo niskiej ceny w stosunku do precyzji, pojawiło się kilka modułów, jak np. dobrze znany GY-30, który widać na zdjęciu na początku. Aby wygodniej je łączyć podczas prototypowania z mikrokontrolerem, zwykle zawierają one konwertery poziomów dla Magistrala I2C i regulatory napięcia do zasilania ich wyższym napięciem (do 5 V) zamiast wyjścia 3,3 V Arduino.
BH1750 posiada dwa tryby odczytu, ciągły i indywidualny, które odpowiadają dwóm stanom: aktywnemu i niskiemu poborowi mocy lub uśpieniu. O ile w przypadku korzystania z trybu odczytu ciągłego, BH1750 pozostaje aktywny po pobraniu próbki, o tyle po wykonaniu indywidualnego pomiaru automatycznie przechodzi w tryb uśpienia i niskiego poboru mocy. Pierwszy odczyt w trybie ciągłym trwa maksymalnie 180 ms, a kolejne od 16 ms do 120 ms w zależności od rozdzielczości.
Czujnik może dokonywać pomiarów w odstępach (rozdzielczość) 4 luksów, 1 luksów i 0,5 luksów. BH1750 w swojej karcie katalogowej zaleca stosowanie rozdzielczości 1 luksa, co pozwala na rozróżnienie iluminacji poniżej 10 luksów (co odpowiada zmierzchowi) i jest bardziej odporne na szumy, które mogłyby mieć wpływ na pomiar.
W rozdzielczości 1 luksa i 4 luksów 16 bitów danych reprezentuje część całkowitą, dzięki czemu można uzyskać maksymalny pomiar 65535 luksów (słoneczny dzień bez bezpośredniego światła). Tryb 0,5 luksa wykorzystuje najmniej znaczący bit dla części dziesiętnej (od 0,5 luksa do 0,5 luksa), więc przy pozostałych 15 bitach możliwe jest przedstawienie maksymalnej wartości 32767 luksów (na zewnątrz bez bezpośredniego światła)
Zwykle okno optyczne, według którego mierzone jest światło otoczenia, odpowiada całemu spektrum widzialnemu i celem jest uzyskanie w nim rozkładu czułości porównywalnego z ludzkim. W przypadku zmniejszenia okna optycznego (światło mierzone jest w dolnym zakresie długości fali) można zwiększyć czułość BH1750 (do 0,11 luksa) w trybie anulowania regulacji wpływu okna optycznego poprzez zwiększenie odczytu czasu w proporcji. Ponieważ w tym trybie specjalnym (nadwymiarowym) dokonywane są oddzielne odczyty, kontekst musi na to pozwalać bez szczególnej zmiany warunków pomiaru (na przykład czujnik musi pozostać bardzo stabilny, nie może przemieszczać się do obszaru o różnych warunkach oświetlenia)
Kody operacyjne BH1750
Estado
5>
-
0B00000000
(0x00
) Niski pobór mocy lub tryb bezczynności. -
0B00000001
(0x01
) Włączony. -
0B00000111
(0x07
) Resetowanie. Czyści dzienniki danych BH1750.
Uchwała
5>
-
0B00010011
(0x13
) Pomiar ciągły przy rozdzielczości 4 luksów (od 16 ms do czasu odczytu) -
0B00010000
(0x10
) Pomiar ciągły przy rozdzielczości 1 luksa (czas odczytu 120 ms) -
0B00010001
(0x11
) Pomiar ciągły przy rozdzielczości 0,5 luksa (czas odczytu 120 ms) -
0B00100011
(0x23
) Pomiar przy rozdzielczości 4 luksów (czas odczytu 16 ms) -
0B00100000
(0x20
) Pomiar przy rozdzielczości 1 luksów (czas odczytu 120 ms) -
0B00100001
(0x21
) Pomiar przy rozdzielczości 0,5 luksów (czas odczytu 120 ms)
Korekta zmiany okna optycznego
5>
-
0B011MT
[0,1,2,3,4] Dolny bit rejestru MTREG (Rejestr czasu pomiaru). -
0B01000MT
[5,6,7] Wysoki bit rejestru MTREG.
Przeczytaj BH1750 z Arduino
Aby zmierzyć oświetlenie otoczenia za pomocą BH1750 od Arduino biblioteka jest używana Drut który zarządza komunikacją z Magistrala I2C. Proces jest typowy dla tego typu komunikacji, najpierw są one aktywowane (po wejściu do programu). Wire.begin()
, komunikacja z BH1750 rozpoczyna się od Wire.beginTransmission()
i twój adres I2C (0x5C lub 0x23 w zależności od tego, czy ADDR jest odpowiednio wysoki, czy niski), konfiguruje się go poprzez przesłanie odpowiedniego kodu za pomocą Wire.write()
i autobus jest wypuszczany z Wire.endTransmission()
15
|
Wire.begin();
|
17
18
19
|
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.write(MEDIDA_CONTINUA_UN_LUX_BH1750);
Wire.endTransmission();
|
Jeśli używany jest jeden z trybów odczytu ciągłego, do pobrania danych z adresem używana jest funkcja Wire.beginTransmission(). I2C odpowiadające dostępowi do BH1750, zostaniesz poproszony o podanie dwóch bajtów (rozdzielczość wynosi 16 bitów) z Wire.requestFrom()
które są czytane, używając Wire.read()
i są ładowane do liczby całkowitej bez znaku, obracając pierwszy bajt o 8 bitów. Autobus jest następnie zwalniany z Wire.endTransmission()
. Ostateczny wynik uzyskuje się dzieląc zwróconą wartość przez współczynnik precyzji (1,2 jeśli okno optyczne nie ulega zmianie)
28
29
|
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.requestFrom(DIRECCION_BH1750_0,2);
|
37
38
|
lectura_BH1750=Wire.read()<<8; // Leer el primer byte y rotarlo 8 bits
lectura_BH1750|=Wire.read(); // Leer el segundo byte y «juntarlo» con el anterior on OR
|
40
|
iluminacion=long(100.0*(float)lectura_BH1750/DIVISOR_PRECISION)/100; // Resultado corregido y sin decimales
|
W przypadku korzystania z trybu odczytów indywidualnych BH1750 przechodzi w tryb uśpienia.W celu powrotu do trybu aktywnego można przesłać konfigurację (ten sam tryb odczytu lub nowy) lub kod włączenia zasilania (0x01). Kodu wyłączenia (1750x0) można użyć do wymuszenia przejścia urządzenia BH00 w tryb uśpienia.
Ważne jest przestrzeganie czasu odczytu czujnika, który zależy od rozdzielczości. Jeśli oczekiwanie nie jest krytyczne, można je ujednolicić w wartości dla wszystkich przypadków, które mogą być nieco większe niż oczekiwane maksimum, aby zapewnić zakończenie odczytu.
Aby pisanie kodu dla BH1750 było wygodniejsze w Arduino, najbardziej odpowiednie kody operacji znajdują się w poniższym dokumencie nagłówkowym.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#define REPOSAR_BH1750 0x00 // Modo de reposo o bajo consumo
#define ENCENDER_BH1750 0x01
#define RESETEAR_BH1750 0x07
#define MEDIDA_CONTINUA_CUATRO_LUX_BH1750 0x13
#define MEDIDA_CONTINUA_UN_LUX_BH1750 0x10
#define MEDIDA_CONTINUA_MEDIO_LUX_BH1750 0x11
#define MEDIDA_SIMPLE_CUATRO_LUX_BH1750 0x23
#define MEDIDA_SIMPLE_UN_LUX_BH1750 0x20
#define MEDIDA_SIMPLE_MEDIO_LUX_BH1750 0x21
#define ESPERA_BH1750_0 250 // 250 milisegundos de espera de lectura del BH1750 (mayor que la máxima)
#define TIMEOUT_I2C 10 // 10 milisegundos de espera antes de renunciar a leer el bus I2C
#define DIVISOR_PRECISION 1.2 // valor por el que dividir la lectura para calcular la luminosidad 1.2 si no hay cambios en la ventana óptica
#define DIRECCION_BH1750_0 0x23
#define DIRECCION_BH1750_1 0x5C
|
Poniższy przykładowy kod pokazuje najpopularniejszy tryb odczytu w czujniku światła I2C BH1750. Rozdzielczość wynosi 1 luks, a tryb odczytu jest ciągły. Przykład pokazuje użycie konsoli szeregowej Arduino, każdy wynik uzyskany na podstawie zmierzonej wartości.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include “BH1750.h” // Cargar los códigos de operación del BH1750
#include <Wire.h>
unsigned int lectura_BH1750;
unsigned int iluminacion;
//float iluminacion; // Mostrar el valor con decimales
long cronometro_lecturas=0;
long tiempo_transcurrido;
long cronometro_timeout_i2c;
void setup()
{
Serial.begin(9600);
Wire.begin();
delay(ESPERA_BH1750_0); // Espera inicial para estabilizar el BH1750
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.write(MEDIDA_CONTINUA_UN_LUX_BH1750);
Wire.endTransmission();
}
void loop()
{
tiempo_transcurrido=millis()–cronometro_lecturas;
if(tiempo_transcurrido>ESPERA_BH1750_0)
{
cronometro_lecturas=millis();
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.requestFrom(DIRECCION_BH1750_0,2);
do
{
tiempo_transcurrido=millis()–cronometro_timeout_i2c;
}
while(Wire.available()<2&&tiempo_transcurrido<TIMEOUT_I2C);
if(Wire.available()>1)
{
lectura_BH1750=Wire.read()<<8; // Leer el primer byte y rotarlo 8 bits
lectura_BH1750|=Wire.read(); // Leer el segundo byte y «juntarlo» con el anterior on OR
//iluminacion=lectura_BH1750/DIVISOR_PRECISION; // Resultado corregido y con decimales (mínimamente más preciso pero menos legible)
iluminacion=long(100.0*(float)lectura_BH1750/DIVISOR_PRECISION)/100; // Resultado corregido y sin decimales
Serial.print(“La iluminación es de “);
Serial.print(iluminacion);
Serial.println(” lux”);
}
}
}
|
Jak powiedziałem powyżej, zarówno tryby rozdzielczości 1 luksa, jak i 4 luksów wykorzystują 16 bitów danych do wyrażenia pomiaru jako liczby całkowitej. Natomiast w trybie 0,5 luksa ostatni bit reprezentuje część dziesiętną, to znaczy wartość, która składa się na pomiar całkowity, jest przesunięta o potęgę dwójki w prawo. W trybie 1 luksa lub 4 luksów ostatni bit (LSB) jest warte 20, przedostatni 21, następne 22…w trybie 0,5 luksa ostatni bit (LSB) jest warte 2-1, przedostatni 20, następne 21...
Zgodnie z tą strukturą danych i biorąc pod uwagę, że należy przeprowadzić dwa odczyty I2C bajtu, aby uzyskać wartość 16-bitową, należy załadować najbardziej znaczące bity bajtu, pierwsze do odczytania, i obrócić je o 8 bitów w lewo w trybie rozdzielczości 1 luksa i w trybie rozdzielczości 4 luksów oraz tylko 7 bitów w 0,5 luksa. Aby ujednolicić sposób odczytu w trybie 0,5 lux można załadować najbardziej znaczący bajt do liczby całkowitej bez znaku, obrócić 8 bitów w lewo, załadować najmniej znaczący bajt i obrócić całą liczbę całkowitą bez znaku o 1 bit w lewo. wartość części dziesiętnej wskazującej LSB (najmniej znaczący bit) zastosować go później.
Logicznie rzecz biorąc, dla trybów 1 luksa lub 4 luksów konieczne jest użycie liczb całkowitych bez znaku (unsigned int
) Po co Arduino nie rezerwuj MSB (najbardziej znaczący bit) dla znaku i móc bezpośrednio operować prawdziwą wartością pomiaru, a nie liczbą ujemną. W Duet Arduino nie jest to konieczne, ponieważ liczby całkowite używają 32 bitów, ale ten sam program będzie również działać, jeśli zostanie również użyty unsigned int
.
Poniższy kod pokazuje, w jaki sposób będzie używany tryb 0,5 luksa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#include “BH1750.h” // Cargar los códigos de operación del BH1750
#include <Wire.h>
unsigned int lectura_BH1750;
//unsigned int iluminacion;
float iluminacion; // Mostrar el valor con decimales
long cronometro_lecturas=0;
long tiempo_transcurrido;
long cronometro_timeout_i2c;
bool parte_decimal;
void setup()
{
Serial.begin(9600);
Wire.begin();
delay(ESPERA_BH1750_0); // Espera inicial para estabilizar el BH1750
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.write(MEDIDA_CONTINUA_MEDIO_LUX_BH1750);
Wire.endTransmission();
}
void loop()
{
tiempo_transcurrido=millis()–cronometro_lecturas;
if(tiempo_transcurrido>ESPERA_BH1750_0)
{
cronometro_lecturas=millis();
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.requestFrom(DIRECCION_BH1750_0,2);
do
{
tiempo_transcurrido=millis()–cronometro_timeout_i2c;
}
while(Wire.available()<2&&tiempo_transcurrido<TIMEOUT_I2C);
if(Wire.available()>1)
{
lectura_BH1750=Wire.read()<<8; // Leer el primer byte y rotarlo 8 bits
lectura_BH1750|=Wire.read(); // Leer el segundo byte y «juntarlo» con el anterior on OR
parte_decimal=(lectura_BH1750<<15)>0;
lectura_BH1750>>=1;
iluminacion=((float)lectura_BH1750+(parte_decimal?0.5:0.0))/DIVISOR_PRECISION;
Serial.print(“La iluminación es de “);
Serial.print(iluminacion);
Serial.println(” lux”);
}
}
}
|
Zamieść komentarz