O módulo GY-30 é um sensor digital de luz baseado no chip BH1750FVI da ROHM. Este componente permite medir a iluminância com alta precisão, convertendo a intensidade de luz diretamente em um valor digital proporcional ao lux (lx).
Características Principais
O BH1750 possui um intervalo de medição que varia de 0 a 65.535 lx, com uma resolução de 1 lx. Ele se comunica através do protocolo I2C e opera com tensões entre 3V e 5V. O módulo GY-30 expõe cinco pinos fundamentais:
- VCC: Alimentação positiva (3-5V).
- GND: Terra.
- SCL: Clock do barramento I2C.
- SDA: Dados do barramento I2C.
- ADDR: Pino de seleção de endereço I2C (permite alterar o endereço do dispositivo).
Protocolo de Comunicação e Endereçamento
O endereço I2C padrão do BH1750 é determinado pelo estado do pino ADDR. Com o pino em nível baixo (GND), o endereço de 7 bits é 0100011. Para operações de escrita, o endereço torna-se 0x46 e para leitura 0x47.
Para obter os dados de luminosidade, é necessário seguir uma sequência de comendos definida no datasheet do componente. Os comandos principais incluem:
- Power On (0x01): Ativa o chip.
- Power Down (0x00): Coloca o chip em modo de baixo consumo.
- Continuos H-Resolution Mode (0x10): Inicia a medição contínua com resolução de 1lx.
Implementação do Firmware no STM32
Abaixo, apresentamos uma implementação utilizando I2C por software (Bit Banging) para maior flexibliidade de pinagem no microcontrolador STM32F103.
#include "stm32f10x.h"
#include "Delay.h"
// Definição de pinos para o barramento I2C
#define PORT_I2C GPIOA
#define PIN_SCL GPIO_Pin_0
#define PIN_SDA GPIO_Pin_1
// Funções auxiliares de baixo nível
void Soft_I2C_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // Open-Drain para I2C
GPIO_InitStruct.GPIO_Pin = PIN_SCL | PIN_SDA;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PORT_I2C, &GPIO_InitStruct);
GPIO_SetBits(PORT_I2C, PIN_SCL | PIN_SDA);
}
void I2C_Signal_SCL(uint8_t level) {
if (level) GPIO_SetBits(PORT_I2C, PIN_SCL);
else GPIO_ResetBits(PORT_I2C, PIN_SCL);
Delay_us(4);
}
void I2C_Signal_SDA(uint8_t level) {
if (level) GPIO_SetBits(PORT_I2C, PIN_SDA);
else GPIO_ResetBits(PORT_I2C, PIN_SDA);
Delay_us(4);
}
uint8_t I2C_Read_SDA(void) {
return GPIO_ReadInputDataBit(PORT_I2C, PIN_SDA);
}
// Protocolo I2C
void I2C_Start_Signal(void) {
I2C_Signal_SDA(1);
I2C_Signal_SCL(1);
I2C_Signal_SDA(0);
I2C_Signal_SCL(0);
}
void I2C_Stop_Signal(void) {
I2C_Signal_SDA(0);
I2C_Signal_SCL(1);
I2C_Signal_SDA(1);
}
void I2C_Transmit_Byte(uint8_t data) {
for (uint8_t i = 0; i < 8; i++) {
I2C_Signal_SDA((data & 0x80) >> 7);
data <<= 1;
I2C_Signal_SCL(1);
I2C_Signal_SCL(0);
}
}
uint8_t I2C_Receive_Byte(void) {
uint8_t buffer = 0x00;
I2C_Signal_SDA(1);
for (uint8_t i = 0; i < 8; i++) {
I2C_Signal_SCL(1);
if (I2C_Read_SDA()) buffer |= (0x80 >> i);
I2C_Signal_SCL(0);
}
return buffer;
}
uint8_t I2C_Wait_ACK(void) {
I2C_Signal_SDA(1);
I2C_Signal_SCL(1);
uint8_t ack = I2C_Read_SDA();
I2C_Signal_SCL(0);
return ack;
}
void I2C_Send_ACK(uint8_t ack_val) {
I2C_Signal_SDA(ack_val);
I2C_Signal_SCL(1);
I2C_Signal_SCL(0);
}
Leitura dos Dados do BH1750
O processo de leitura consiste em inicializar o sensor, enviar o comando de medição e, após o tempo de integração do sensor (aproximadamente 180ms para alta resolução), ler os dois bytes de dados.
uint16_t BH1750_Read_Lux(void) {
uint8_t msb, lsb;
// 1. Ligar o dispositivo
I2C_Start_Signal();
I2C_Transmit_Byte(0x46); // Endereço de escrita
if(I2C_Wait_ACK()) return 0;
I2C_Transmit_Byte(0x01); // Power On
I2C_Wait_ACK();
I2C_Stop_Signal();
// 2. Configurar modo de medição contínua (Alta Resolução)
I2C_Start_Signal();
I2C_Transmit_Byte(0x46);
I2C_Wait_ACK();
I2C_Transmit_Byte(0x10); // H-Res Mode
I2C_Wait_ACK();
I2C_Stop_Signal();
Delay_ms(200); // Tempo para estabilização da leitura
// 3. Ler dados de iluminância
I2C_Start_Signal();
I2C_Transmit_Byte(0x47); // Endereço de leitura
I2C_Wait_ACK();
msb = I2C_Receive_Byte();
I2C_Send_ACK(0);
lsb = I2C_Receive_Byte();
I2C_Send_ACK(1);
I2C_Stop_Signal();
// Combinar bytes e aplicar fator de conversão (Valor / 1.2)
uint16_t raw_data = (msb << 8) | lsb;
return (uint16_t)(raw_data / 1.2);
}
No loop principal (main), basta chamar a função de leitura e processar o valor retornado. O valor final representa a intensidade luminosa em Lux, que pode ser exibida em um display OLED ou enviada via interface serial para monitoramento.
int main(void) {
Soft_I2C_Init();
// Inicialização de periféricos de saída (ex: OLED ou UART) aqui
while(1) {
uint16_t intensidade = BH1750_Read_Lux();
// Lógica para exibir 'intensidade'
Delay_ms(500);
}
}
É importante notar que o tempo de espera de 200ms garante que o sensor complete seu ciclo de integração de luz interno, evitanod leituras de dados obsoletos ou imprecisos no barramento I2C.