Interface do Sensor de Intensidade Luminosa BH1750 (GY-30) com STM32F103

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.

Tags: STM32 BH1750 I2C sensores firmware

Publicado em 8-8 22:27