BH1750. Sensor de luz ambiente com barramento I2C.
O BH1750 é um sensor de iluminação ambiente com resolução e sensibilidade razoavelmente altas. Comporta-se perante a luz visível de forma comparável à do olho humano e não é afetado pela radiação infravermelha nem depende da temperatura da cor do tipo de iluminação, ou seja, funciona bem com luz natural e com diferentes tipos de iluminação artificial. Ele se comunica digitalmente com o microcontrolador, com o Barramento I2C, portanto é resistente a interferências se for colocado a uma certa distância do circuito que o lê. Seu tempo de resposta é bastante baixo, inferior a 200 ms nas circunstâncias mais desfavoráveis.
Do ponto de vista electrónico a sua implementação é muito simples. Basta conectar a alimentação (entre 2,4 V e 3,6 V) e o Barramento I2C. Opcionalmente, o endereço do barramento pode ser alterado para conectar dois dispositivos (com ADDR em nível baixo é 0B0100011 ou 0x23 e com ADDR em nível alto é 0B1011100 ou 0x5C) e a linha VDI pode ser usada para a função de reset com o microcontrolador.
Para conectar o BH1750 a Arduino, além de ser alimentado pela saída de 3,3 V, o mais correto é utilizar um conversor de nível além do resistores de pull-up para Barramento I2C. Embora o componente suporte uma conexão direta ao barramento Barramento I2C Não é aconselhável dimensionar um circuito sem considerar a conversão do nível.
Devido à sua popularidade, que se deve ao fato de ser muito barato em relação à sua precisão, existem diversos módulos, como o conhecido GY-30, que pode ser visto na fotografia do início. Para conectá-los de forma mais confortável durante a prototipagem com um microcontrolador, eles geralmente incluem conversores de nível para o Barramento I2C e reguladores de tensão para alimentá-los com uma tensão mais alta (até 5V) em vez da saída de 3,3V do Arduino.
O BH1750 possui dois modos de leitura, contínuo e individual, que correspondem a dois estados, ativo e baixo consumo ou suspensão. Embora se o modo de leitura contínua for usado, o BH1750 permanece ativo após a amostragem, após realizar uma medição individual ele entra automaticamente no modo de suspensão e baixo consumo de energia. A primeira leitura em modo contínuo leva no máximo 180 ms e as subsequentes entre 16 ms e 120 ms dependendo da resolução.
O sensor é capaz de medir em intervalos (resolução) de 4 lux, 1 lux e 0,5 lux. O BH1750 recomenda em sua ficha técnica utilizar a resolução de 1 lux, que permite distinguir iluminações abaixo de 10 lux (que corresponde ao crepúsculo) e é mais imune a ruídos que possam afetar a medição.
As resoluções de 1 lux e 4 lux usam os 16 bits de dados para representar a parte inteira, de modo que uma medição máxima de 65535 lux pode ser alcançada (dia ensolarado sem luz direta). O modo 0,5 lux utiliza o bit menos significativo para a parte decimal (mede de 0,5 lux a 0,5 lux) pelo que com os restantes 15 bits é possível representar um valor máximo de 32767 lux (exterior sem luz direta)
Normalmente, a janela óptica através da qual a luz ambiente é medida corresponde a todo o espectro visível e o objetivo é conseguir nela uma distribuição de sensibilidade comparável à dos humanos. Se a janela óptica for reduzida (a luz é medida numa faixa de comprimento de onda inferior) a sensibilidade do BH1750 pode ser aumentada (até 0,11 lux) com um modo de cancelamento do ajuste da influência da janela óptica aumentando a leitura do tempo na proporção. Como neste modo especial (sobredimensionado) são feitas leituras separadas, o contexto deve permitir isso sem alterar particularmente as condições de medição (por exemplo, o sensor deve permanecer muito estável, não deve mover-se para uma área com condições de iluminação diferentes)
Códigos de operação BH1750
Estado
5>
-
0B00000000
(0x00
) Baixo consumo de energia ou modo inativo. -
0B00000001
(0x01
) Ligado. -
0B00000111
(0x07
) Reiniciar. Limpa os registros de dados do BH1750.
Resolução
5>
-
0B00010011
(0x13
) Medição contínua com resolução de 4 lux (entre 16 ms e tempo de leitura) -
0B00010000
(0x10
) Medição contínua com resolução de 1 lux (tempo de leitura de 120 ms) -
0B00010001
(0x11
) Medição contínua com resolução de 0,5 lux (tempo de leitura de 120 ms) -
0B00100011
(0x23
) Uma medição com resolução de 4 lux (tempo de leitura de 16 ms) -
0B00100000
(0x20
) Uma medição com resolução de 1 lux (tempo de leitura de 120 ms) -
0B00100001
(0x21
) Uma medição com resolução de 0,5 lux (tempo de leitura de 120 ms)
Ajuste para mudança na janela óptica
5>
-
0B011MT
[0,1,2,3,4] Bit inferior do registro MTREG (Measurement Time REGister). -
0B01000MT
[5,6,7] Bit alto do registro MTREG.
Leia o BH1750 do Arduino
Para medir a iluminação ambiente com o BH1750 de Arduino a biblioteca é usada Fio que gerencia as comunicações com o Barramento I2C. O processo é o usual neste tipo de comunicação, primeiro são ativados (uma vez no programa) com Wire.begin()
, a comunicação com o BH1750 começa com Wire.beginTransmission()
e seu endereço I2C (0x5C ou 0x23 dependendo se ADDR é alto ou baixo respectivamente), é configurado enviando o código correspondente com Wire.write()
e o ônibus é liberado com Wire.endTransmission()
15
|
Wire.begin();
|
17
18
19
|
Wire.beginTransmission(DIRECCION_BH1750_0);
Wire.write(MEDIDA_CONTINUA_UN_LUX_BH1750);
Wire.endTransmission();
|
Se um dos modos de leitura contínua for usado, Wire.beginTransmission() será usado para obter os dados com o endereço I2C correspondente ao acesso ao BH1750, serão solicitados dois bytes (a resolução é de 16 bits) com Wire.requestFrom()
que são lidos, usando Wire.read()
, e são carregados em um número inteiro sem sinal, girando o primeiro byte em 8 bits. O ônibus é posteriormente liberado com Wire.endTransmission()
. O resultado final é obtido dividindo o valor retornado pelo fator de precisão (1,2 se a janela óptica não for alterada)
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
|
Se for utilizado o modo de leituras individuais, o BH1750 entra em modo sleep. Para retornar ao modo ativo pode ser enviada uma configuração (o mesmo modo de leitura ou um novo) ou o código de inicialização (0x01). O código de desligamento (1750x0) pode ser usado para forçar o BH00 a entrar no modo de hibernação.
É importante respeitar o tempo de leitura do sensor, que depende da resolução. Se a espera não for crítica, ela poderá ser unificada em um valor para todos os casos que pode ser um pouco maior que o máximo esperado para garantir que a leitura seja concluída.
Para tornar a escrita de código para o BH1750 mais confortável em Arduino, os códigos de operação mais relevantes são encontrados no documento de cabeçalho a seguir.
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
|
O código de exemplo a seguir mostra o modo de leitura mais comum no sensor de luz I2C BH1750. A resolução é de 1 lux e o modo de leitura é contínuo. O exemplo mostra, usando o console serial Arduino, cada resultado obtido a partir do valor medido.
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”);
}
}
}
|
Como eu disse acima, os modos de resolução de 1 lux e 4 lux usam 16 bits de dados para expressar a medição como um número inteiro. Por outro lado, no modo 0,5 lux, o último bit representa uma parte decimal, ou seja, o valor que contribui para a medição total é deslocado uma potência de dois para a direita. No modo 1 lux ou 4 lux, o último bit (LSB) vale 20, o penúltimo 21, os próximos 22…no modo 0,5 lux, o último bit (LSB) vale 2-1, o penúltimo 20, os próximos 21...
De acordo com esta estrutura de dados, e considerando que devem ser realizadas duas leituras I2C de um byte, para obter o valor de 16 bits é necessário carregar os bits mais significativos do byte, os primeiros a serem lidos, e girá-los 8 bits para a esquerda no modo de resolução de 1 lux e no modo de resolução de 4 lux e apenas 7 bits em 0,5 lux. Para unificar a forma de leitura no modo 0,5 lux você pode carregar o byte mais significativo em um inteiro sem sinal, girar 8 bits para a esquerda, carregar o byte menos significativo e girar todo o inteiro sem sinal 1 bit para a esquerda, preservando o valor da parte decimal que indica o LSB (bit menos significativo) para aplicá-lo mais tarde.
Logicamente, para os modos 1 lux ou 4 lux é necessário usar inteiros sem sinal (unsigned int
) para que Arduino não reserve o MSB (bit mais significativo) para o sinal e poder operar diretamente com o valor verdadeiro da medida, não com um número negativo. Em Arduino devido não é necessário, pois os números inteiros usam 32 bits, mas o mesmo programa também funcionará se for usado unsigned int
.
O código a seguir mostra como o modo 0,5 lux seria usado
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”);
}
}
}
|
Baixe os documentos para exemplos de medição de luz ambiente com o sensor BH1750 e Arduino.
Postar Comentário