BH1750( GY-302 ) light sensor


Here I will briefly introduce the basic information of the BH1750 light sensor module (not much nonsense), and I will focus on explaining its use. I believe that you are more concerned about how it is used in front of the screen. OK, gogogo! ! !

1. Product Introduction

Chip: BH1750FVI is a digital light intensity sensor integrated circuit for two-wire serial bus interface. This integrated circuit can adjust the brightness of the LCD or keyboard backlight according to the collected light intensity data. Its high resolution can detect a wide range of light intensity changes.

Working principle: The interior of BH1750 is composed of photodiode, operational amplifier, ADC acquisition, crystal oscillator and so on. The PD diode converts the input optical signal into an electrical signal through the photovoltaic effect. After being amplified by the operational amplifier circuit, the voltage is collected by the ADC, and then converted into a 16-bit binary number through the logic circuit and stored in the internal register (the stronger the light, the higher the photocurrent. The larger the voltage, the greater the voltage).

Physical circuit diagram:
insert image description here
PCB schematic diagram:
insert image description here

Physical map:
insert image description here
It can be seen that the module has 5 pins, and then let’s see what the pin introduction looks like

Pin Definition:
insert image description here
Module Instructions:
insert image description here
Usage Steps:
insert image description here

Features:

  • Support I2CBUS interface
  • Spectral sensitivity characteristics close to visual sensitivity
  • Output a digital value corresponding to brightness
  • Corresponds to a wide range of input light. (equivalent to 1-65535lx)
  • Realize low current by reducing power function.
  • Stable measurement is realized by the 50Hz/60Hz light noise reduction function.
  • Support 1.8v logic input interface.
  • No other external parts are required.
  • Light source dependence is weak.
  • There are two optional I2Cslave addresses.
  • Adjustable measurement results The most influential factor is the size of the light entrance.
  • Use this function to calculate the range from 1.1lx to 100000lx max/min.
  • The minimum error variation is ±20%.
  • Less affected by infrared rays.

Two, IIC communication

IIC is a serial communication bus. The IIC serial bus generally has two signal lines, one is the bidirectional data line SDA, and the other is the clock line SCL. All the serial data SDA connected to the I2C bus device are connected to the SDA of the bus, and the clock line SCL of each device is connected to the SCL of the bus. It can be understood that it completes the communication transmission through the two lines of SDA and CLK,

Since this module communicates through the IIC protocol, I will introduce the related drivers of IIC next.

The IIC driver part is common, and each module completes its own communication according to its own device address, configuration, command and other register operations.

The IIC driver part is divided into 6 parts, which are divided into:

  • start signal
  • stop signal
  • send acknowledgment signal
  • receive acknowledgment signal
  • send a byte
  • receive a byte

First of all, let’s look at the timing diagram:
insert image description here
if you don’t understand the timing, don’t worry, let me tell you one by one.

First of all, please remember: SDA and CLK only have two states of "0 and 1"; secondly, the CLK pin should define the output mode when the host sends the signal, and the CLK pin should define the input mode when receiving the signal.

1. Start signal:
For the start signal, you can understand it in this way, SDA is from high level -> low level when CLK is set to high level, this is the start signal, but for the sake of communication stability, it generally jumps The delay is 5us in the middle.

Let's see how the program is designed:

void IIC_Start(void)
{
    
    
	SDA_OUT();     //sda线输出模式
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(5);
 	IIC_SDA=0;   //产生下降沿
	delay_us(5);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	

2. Stop signal:
Same as the start signal, SDA changes from low level -> high level when CLK is high level, and the stop signal is completed.

void IIC_Stop(void)
{
    
    
	SDA_OUT(); //sda线输出
	IIC_SDA=0;  //产生上升沿
 	delay_us(5);
	IIC_SCL=1; 
	IIC_SDA=1; //发送I2C总线结束信号
	delay_us(5);							   	
}

3. Send the response signal:
when SDA is low level, CLK changes from high level -> low level, and completes the response;
when SDA is high level, CLK changes from high level -> low level, and refuses to respond;

Therefore, a variable needs to be set in the program to judge whether to accept the response:

void SendACK(int ack)    
{
    
    
  GPIO_InitTypeDef GPIO_InitStruct;   
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;    //定义输出模式
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Pin = sda;
  GPIO_Init(bh1750_PORT, &GPIO_InitStruct);  
	
	if(ack == 1)   //写应答信号
		SDA=1; 
	else if(ack == 0)
		SDA=0; 
	else
		return;			
  SCL=1;     //拉高时钟线
  delay_us(5);                 //延时
  SCL=0;      //拉低时钟线
  delay_us(5);                //延时
}

4. Receiving the response signal:
SDA remains low during CLK from low level -> high level -> low level

u8 IIC_waitAck()
{
    
    
	u8 ack =0;
	IIC_setSDAMode_In();
	IIC_SCL_OUT(0);             //准备时序
	delay_us(5);
	
	IIC_SCL_OUT(1);
	delay_us(5);
	
	if(IIC_SDA_IN)
	{
    
    
				ack =1;
	}
	else
	{
    
    
				ack =0;	
	}
	IIC_SCL_OUT(0);              //拉低,表示应答完成
	delay_us(5);
	return  ack;
}

5. Send a byte:
Every time CLK completes a high level -> low level transition, the master sends 1 bit. After the 1 byte is sent, it needs to receive the response signal sent back from the slave.

void SendByte(uchar dat)
{
    
    
  uchar i;
  for (i=0; i<8; i++)         //8位计数器
  {
    
    
		if( 0X80 & dat )
      GPIO_SetBits(bh1750_PORT,sda);
    else
      GPIO_ResetBits(bh1750_PORT,sda);
		dat <<= 1;
    SCL=1;               //拉高时钟线
    delay_us(5);             //延时
    SCL=0;                //拉低时钟线
    delay_us(5);            //延时
  }
  RecvACK();
}

6. Receive a byte:
similar to sending a byte, but the pin definition is different, as follows:

u8 IIC_readByte()
{
    
    
  u8 data = 0;
	IIC_setSDAMode_In();
	IIC_SCL_OUT(0);                  //先拉低,为读取数据做准备
	delay_us(5);
	for(int i=0;i<8;i++)
	{
    
    
			IIC_SCL_OUT(1);         // SCL为高期间才可以读取数据
			delay_us(5);
		if(IIC_SDA_IN)
		{
    
    
				data|=(0x01<<(7-i));	
		}else{
    
    
			data &= ~(0x1<<(7-i));
		}	
		IIC_SCL_OUT(0);
		delay_us(5);
	}
	return data;
}

3. Use of BH1750

1. Write signal
First, you need to write to the module, and then initialize. The process of writing operation is: start signal --> send device address + write signal --> send internal register address --> send stop signal.

void Single_Write_BH1750(uchar REG_Address)
{
    
    
  BH1750_Start();                  //起始信号
  BH1750_SendByte(SlaveAddress);   //发送设备地址+写信号
  BH1750_SendByte(REG_Address);    //内部寄存器地址
  BH1750_Stop();                   //发送停止信号
}

2. Initialization
Initialize the module, initially set the SDA and CLK pins to push-pull output, and then power on the module. According to the instruction table, it is known that the power-on designation is 0x01. After power-on, it needs to delay about 180ms for the module to buffer.

void Init_BH1750()
{
    
    
  GPIO_InitTypeDef GPIO_InitStruct;
	 /*开启GPIOB的外设时钟*/ 
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Pin = sda | scl ;
  GPIO_Init(bh1750_PORT,&GPIO_InitStruct); 
	
  Single_Write_BH1750(0x01);  
	delay_ms(180);            //延时180ms
}

3. Read the internal data of the register.
The process of reading data is: start signal --> send device address + read signal --> define array storage data (the last data needs to be rejected) --> send stop signal.

void mread(void)
{
    
       
	uchar i;	
    BH1750_Start();                          //起始信号
    BH1750_SendByte(SlaveAddress+1);         //发送设备地址+读信号
	
	for (i=0; i<3; i++)                      //连续读取3个地址数据,存储中BUF
  {
    
    
      BUF[i] = BH1750_RecvByte();          //BUF[0]存储0x32地址中的数据
      if (i == 3)
    {
    
    
      BH1750_SendACK(1);                //最后一个数据需要回NOACK
    }
    else
    {
    
    		
      BH1750_SendACK(0);                //回应ACK
    }
  }
  BH1750_Stop();                          //停止信号
  delay_ms(5);
}

4. Operate and transfer data

float read_BH1750(void)
{
    
    
    int dis_data;                       //变量	
	float temp1;
	float temp2;
	Single_Write_BH1750(0x01);   // power on
    Single_Write_BH1750(0x10);   // H- resolution mode
    delay_ms(180);            //延时180ms
	mread();       //连续读出数据,存储在BUF中
    dis_data=BUF[0];
    dis_data=(dis_data<<8)+BUF[1]; //合成数据 
	temp1=dis_data/1.2;
	temp2=10*dis_data/1.2;	
	temp2=(int)temp2%10;
	OLED_ShowString(87,2,".",12); 
	OLED_ShowNum(94,2,temp2,1,12);	
	return temp1;
}

5. Call BH17502 in the main function and display it on oled

int main(void)
{
    
     
    float light;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	delay_init();	    	 //延时函数初始化	  
	uart_init(9600);	 	//串口初始化为9600
	LED_Init();				//初始化与LED连接的硬件接口
    Init_BH1750();       //初始化BH1750
	OLED_Init();     //初始化OLED
	OLED_Clear();     //清屏
	
  while(1)
  {
    
    
     light=read_BH1750();  //读取BH1750的光强数据
     OLED_ShowString(0,2,"light:",12);  //显示光照强度
	 OLED_ShowNum(48,2,light,6,12);	
	 OLED_ShowString(110,2,"lx",12);
	 if(light<100)
	{
    
    
		LED1=0;
		OLED_ShowString(38,5,"LED-ON ",12);
	}
	else
	{
    
    
		LED1=1;
		OLED_ShowString(38,5,"LED-OFF",12);
	}
  }		
}	

4. Program source code

The program combines oled display output, if necessary, you can leave a message in the comment area or private message

Guess you like

Origin blog.csdn.net/Dustinthewine/article/details/127540711