BH1750 Light Sensor Library for Proteus V1.1: two Arduino UNOs with blue GY-302 BH1750 boards, the BH1750 Advance pop-up on its Light page at 30000 lx and the TEP Serial Monitor in its Simple interface

BH1750 Light Sensor Library for Proteus V1.1 (GY-302 + Arduino)

2.5K Views
40
700
60
25
60
PCBWay

Hello friends, I hope you all are doing great. Today, I am going to share the new BH1750 Light Sensor Library for Proteus V1.1. The BH1750 is ROHM's small digital light sensor, best known on the blue GY-302 module: it measures how much light falls on it and gives your Arduino the result in lux over I2C. With this BH1750 Light Sensor Library for Proteus, you set the light with a slider or a light scene, and your Arduino reads it with the same claws BH1750 library you use on real hardware.

Version 1.1 replaces the first version of this post. You now get two devices: BH1750 Simple, with a light panel on the schematic, and BH1750 Advance, with a pop-up window and four measured light test tools. The model now takes the real measurement time and averages the light over every measurement, like the real sensor. The new BH1750 Arduino Proteus demo is a night lamp on two Arduino UNOs, one sensor at each I2C address, shown in the compact Simple interface of our TEP Serial Monitor. Have you read version 1.0? Then jump to "What's New" below.

NOTICE: This library is very special to our team. Our BH1750 model measures with the real timing, averages the light over every measurement like the real photodiode and logs every I2C transaction your sketch sends. It took our team a lot of hard work, many test runs and many design changes. Your feedback is the fuel that keeps us going, so please tell us what you think in the comments below or in the BH1750 Library board of our forum. And if our free libraries help you, you can buy us a coffee. So, let's get started with the BH1750 Light Sensor Library for Proteus:

BH1750 Light Sensor Library for Proteus V1.1: two Arduino UNOs with blue GY-302 BH1750 boards, the BH1750 Advance pop-up on its Light page at 30000 lx and the TEP Serial Monitor in its Simple interface
Figure: The BH1750 demo in Proteus 8.5: NODE 1 (Simple, 0x23) and NODE 2 (Advance, 0x5C), U2's Light page stepped from 500 to 30000 lx, and Serial Monitor U4 in the Simple interface with the two-line STATUS.

What is the BH1750 Light Sensor?

The BH1750FVI, made by ROHM, is a digital ambient light sensor. It measures illuminance, the light arriving at a surface, in lux (lx). A photodiode collects the light, the chip turns it into a 16-bit number, and your Arduino reads that number over I2C, a 2-wire bus with a clock line (SCL) and a data line (SDA). You can build a light-controlled lamp, a brightness display or a light logger with it.

This is different from an LDR (light-dependent resistor) on an analog pin. An LDR gives a voltage that your sketch must interpret; the BH1750 hands over a finished measurement, and the library turns it into lux. The common board is the blue GY-302: the BH1750 with its optical window in the middle, a 662K 3.3 V regulator, two 4.7 k pull-up resistors and a 5-pin header, VCC GND SCL SDA ADDR.

The BH1750 at a Glance

BH1750 in numbers
FeatureValue
InterfaceI2C at address 0x23 (ADDR LOW or open) or 0x5C (ADDR HIGH)
ModesContinuous or one-time, each in H-resolution, H-resolution2 or L-resolution
Measurement time120 ms in H-resolution and H-resolution2, 16 ms in L-resolution (typical; the data sheet's maximum is 180 / 24 ms), times MTreg / 69
ResultA 16-bit count, 0 - 65535, read as 2 bytes, high byte first
Sensitivity1.2 counts per lux typical (0.96 - 1.44) at MTreg 69; MTreg 31 - 254
Resolution at MTreg 690.83 lx (H-resolution), 0.42 lx (H-resolution2), 3.33 lx (L-resolution)
Range at MTreg 690 - 54612 lx (H-resolution), 0 - 27306 lx (H-resolution2)
Supply (GY-302)3.3 V or 5 V: the module has its own 3.3 V regulator

Light Levels: The Five Scenes of Our Panels

Our panels have five light scenes, and the board's sky shows a picture for each range:

The light scenes (the slider covers 0 lx and 0.1 lx to 100 klx)
SceneLightCounts at MTreg 69The sky on the board
NIGHT1 lx1A moon (below 10 lx)
ROOM150 lx180A lamp (below 1000 lx)
OFFICE500 lx600A lamp
OVERCAST2000 lx2400A sun behind a cloud (below 10 klx)
SUN30000 lx36000The sun

Light Sensor Terms You Will See in This Article

Light sensor and I2C terms
TermMeaning
Illuminance, lux (lx)The light falling on a surface, and its unit; 1 klx = 1000 lx
CountOne step of the sensor's 16-bit result; at MTreg 69, 1.2 counts make 1 lx
Data registerThe chip's 2-byte result; it holds the last finished measurement
Measurement timeHow long the photodiode collects light for one result
MTregThe measurement time register, 31 - 254 (default 69): higher = slower, more sensitive, finer steps
H-resolution, H-resolution2, L-resolutionThe three resolutions: the sketch calls them 1, 0.5 and 4 lx steps; with 1.2 counts per lux, one step is 0.83, 0.42 and 3.33 lx
Continuous, one-timeMeasure again and again, or measure once and then go to Power Down
Power DownThe chip's sleep state: no measuring, the data register is kept
SaturationThe count stops at 65535, the brightest light the mode and MTreg can show
In-between readingA result measured while the light changed, between the old and the new value
ACK, NACKThe I2C "got it" bit after each byte; no ACK means no device answers at that address
Pull-up resistorKeeps SDA and SCL HIGH; the devices only pull the lines LOW (open drain)

How the BH1750 Measures Light

Opcodes: How the Arduino Talks to the BH1750

The BH1750 is simple to talk to: the Arduino writes one-byte opcodes (instructions) to it and reads two bytes back. The claws BH1750 library names them in its header:

BH1750 opcodes in hex
OpcodeMeaning
00 / 01Power Down / Power On
07Reset (ignored in Power Down)
10 / 11 / 13Continuously H-resolution / H-resolution2 / L-resolution
20 / 21 / 23One Time H-resolution / H-resolution2 / L-resolution
4x and 6xMTreg: its 3 high bits in 01000xxx (4x), its 5 low bits in 011xxxxx (6x)

So MTreg 69 (binary 010 00101) travels as 42 and 65. A read returns the data register, high byte first: 02 58 means 2 x 256 + 88 = 600 counts.

From Counts to Lux

At MTreg 69 in H-resolution, the sensor makes 1.2 counts per lux, and the library divides by 1.2: 600 counts are 500.0 lx, and 36000 counts are 30000.0 lx. One count is 0.83 lx, so 1 lx on the sensor reads 0.8 lx. H-resolution2 makes twice the counts and the library divides by 2 as well, so it has half the step but saturates at half the light, 27306.2 lx. L-resolution counts in steps of 4.

Measurement Time and MTreg

MTreg sets how long the photodiode collects light: a higher MTreg gives more counts per lux and finer steps, but it is slower and saturates earlier. The library divides by MTreg / 69 too, so it prints the same lux at any MTreg:

MTreg in H-resolution (from the Lux sweep tool)
MTregTime (H-resolution)StepFull scale
3154 ms1.85 lx121557 lx
69 (default)120 ms0.83 lx54612 lx
138240 ms0.42 lx27306 lx
254442 ms (663 ms maximum)0.23 lx14836 lx

Continuous or One-Time?

In a continuous mode, the sensor starts the next measurement as soon as one ends, so the data register always holds a recent result. In a one-time mode, it makes one measurement and goes to Power Down: the sketch must send the mode again, wait the measurement time and then read. A read before the first measurement has finished gives 0 lx, on the real chip too.

The Light Is Averaged over Each Measurement

The photodiode collects light for the whole measurement, so the result is the average light of those 120 ms. If the light changes in the middle, one result lands between the old and the new value. Version 1.1 models this; v1.0 used the light at the moment of reading. You will meet these in-between readings in the panels, on the monitor and in the Step response tool.

The ADDR Pin: Two Sensors on One Bus

ADDR LOW or open selects 0x23 (the module has a pull-down), ADDR HIGH selects 0x5C. So two BH1750s can share one I2C bus, one at each address; a transaction to the other address gets no ACK. Our demo uses both: U1 has ADDR to GND, U2 has ADDR to VCC.

What's New in BH1750 Light Sensor Library for Proteus V1.1

If you used version 1.0, here is what has changed:

  • Two devices in TEPBH1750.LIB: BH1750 Simple (BH1750TEP, the v1.0 device, so old designs keep working) and BH1750 Advance (BH1750ADVTEP) with a pop-up window.
  • A redrawn board: the blue GY-302 instead of v1.0's square board, with a sky that shows the light, a glowing sensor window, a MEAS bar, a live ADDR box and PWR / I2C LEDs (a TEP addition).
  • Real measurement timing: 120 ms in H-resolution, 16 ms in L-resolution, times MTreg / 69, with MTreg changing the counts per lux; one-time modes go to Power Down after their measurement.
  • The light is averaged over each measurement, so a change gives one in-between reading.
  • The ADDR pin (0x23 or 0x5C, shown on the board) and an I2C transaction log with the opcodes decoded and the SCL clock measured.
  • A log slider up to 100 klx (v1.0: 0 - 2000 lx, linear), five light scenes, a live chart and the new ACCURACY and TIMING properties.
  • Four measured test tools, Settings and Help on the Advance.
  • A two-UNO demo with the TEP Serial Monitor instead of the Virtual Terminal, with a night lamp on A0 and Serial Monitor commands.
  • Fixes: Simulation Log lines (v1.0 wrote none), and the panel no longer changes the light while the simulator reads it.
  • Lighter package: about 1.45 MB, without the C++ source code (v1.0: about 7.6 MB).

BH1750 Light Sensor Library for Proteus: Simple vs Advance

Both devices run the same model with the same properties; only the panel differs:

BH1750 Simple vs Advance
FeatureSimpleAdvance
Full BH1750 model (0x23 / 0x5C, six modes, MTreg, real timing, light averaged over each measurement)✔✔
Blue GY-302 board with the sky, glowing window, MEAS bar, ADDR box and PWR / I2C LEDs✔✔
Light panel on the schematic (log slider, five scenes, 5 s chart, last I2C transactions)✔✘
Pop-up window you can move, resize and minimise✘✔
Light page: Dark and five scenes, Darker / Brighter, THE SENSOR card, 10 s chart✘✔
I2C check, Timing, Step response and Lux sweep✘✔
TEP Dark / Light theme, text size, Help page with Copy diagnostics✘✔
Same device name as v1.0 (old designs keep working)✔✘

Choose Simple to keep the light control beside your circuit, and Advance when your sheet is full or you want hard numbers. The demo has one of each.

Download BH1750 Light Sensor Library for Proteus

Click the button below to download BH1750-Light-Sensor-Library-for-Proteus-v1.1.zip (about 1.45 MB, without the C++ source code):

BH1750 Light Sensor Library for Proteus V1.1
  • README.txt: the full guide, from the wiring and the test tools to real hardware.
  • Proteus Library Files: TEPBH1750.LIB (both devices), TEPSERIALMON.LIB and our Arduino UNO library ArduinoV3TEP.LIB / ArduinoV3TEP.IDX.
  • Proteus Model Files: TEPBH1750.DLL and TEPSERIALMON.DLL.
  • Proteus Simulation: BH1750-ArduinoUnoV3.pdsprj, BH1750_Demo.hex and copies of both DLLs.
  • Arduino Code: BH1750_Demo.ino and the BH1750 library 1.3.0 by Christopher Laws (claws), unmodified, with its examples, under the MIT licence (LICENSE).

No Proteus yet? Read How to Download and Install Proteus 7 and 8. New to libraries? Follow How to Install a New Library in Proteus.

How to Install BH1750 Light Sensor Library for Proteus

  1. Close Proteus and extract the whole zip file.
  2. Copy the four files from Proteus Library Files into the LIBRARY folder, usually C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Professional\LIBRARY (on some PCs C:\ProgramData\Labcenter Electronics\Proteus 8 Professional\LIBRARY).
  3. Copy TEPBH1750.DLL and TEPSERIALMON.DLL into the MODELS folder.
  4. Start Proteus, press P and search for BH1750. You get the Simple and the Advance device (category Sensors > Light, as in v1.0).

Updating from v1.0? Replace TEPBH1750.LIB and TEPBH1750.DLL, and delete TEPBH1750.IDX if there is one in LIBRARY. A v1.0 design keeps its v1.0 symbol: it runs with the new model and shows the v1.0 slider panel exactly as before, without the v1.1 board parts; re-pick the part to get the v1.1 board. Tested in Proteus 8.5; Proteus 7 is not supported.

The BH1750 (GY-302) Board in Proteus

We designed the sensor as a clean TEP board in the blue and the tall shape of the GY-302: the BH1750 with its optical window in the middle, the 662K regulator and capacitors on the left, the two 472 (4.7 k) pull-ups on the right and two gold mounting holes. Above the board, a round sky with 12 rays sends three beams down to the window. Here is U1, the Simple device, a moment after I clicked OFFICE:

BH1750 Simple board in Proteus at OFFICE 500 lx: a lamp in the sky, the glowing sensor window, PWR and I2C LEDs lit, ADDR 0x23 and the BH1750 LIGHT CONTROL panel with 500 lx on the sensor, 500.0 lx read and 600 COUNTS
Figure: U1 (Simple) at OFFICE: a lamp in the sky, 600 counts = 500.0 lx, and a violet in-between dot at the step from 100 lx.

The sky shows a lamp, the rays are lit two segments of three, and the window glows. The green I2C LED flashes as the Arduino reads, the cyan MEAS bar fills during each 120 ms measurement, and the ADDR box says ADDR 0x23.

Pinout

BH1750 pins in Proteus (VCC GND SCL SDA ADDR, the order of the GY-302 header, as in v1.0)
PinFunctionDemo connection
VCCPower (3.3 V or 5 V on a real GY-302)Supply terminal
GNDGroundGND
SCLI2C clock from the ArduinoArduino A5
SDAI2C data, both ways (open drain)Arduino A4
ADDRAddress select: LOW or open = 0x23, HIGH = 0x5CU1: GND; U2: VCC

Sky, Window and LEDs

Board animations (the same on both devices)
IndicatorWhat it shows
SkyDARK at 0 lx, a moon below 10 lx, a lamp below 1000 lx, a sun behind a cloud below 10 klx, then the sun
12 rays and 3 beams0, 1, 2 or 3 segments of every ray light up as the light grows; the beams run down to the window
Sensor window and haloGlow from dim amber to white-yellow with the light; sparkle rays from about 200 lx
MEAS barFills during every measurement: cyan in H-resolution, violet in H-resolution2, amber in L-resolution
ADDR boxThe address the ADDR pin selects, 0x23 or 0x5C
PWR LED (red)Lit while VCC and GND are powered
I2C LED (green)Lights for 0.3 s (simulation time) after every transaction to this sensor
PANEL / OPEN PANEL, SIMPLE / ADVANCEThe panel button and the device badge

Both LEDs are a TEP addition: the real GY-302 has no LED.

Component Properties

BH1750 properties (double-click the sensor > Edit Properties; the same on Simple and Advance)
PropertyMeaningDefault
LUXThe light at the start of a run, lx100
LUX2The light after the timed step, lx1000
STEP_TIMEThe step time in seconds, 0 = no step0
LUX_MAXThe slider's maximum, lx (v1.0: 2000 on a linear slider; a v1.0 design keeps its value)100000
TIMINGTYP (120 / 16 ms) or MAX (the data sheet's 180 / 24 ms)TYP
ACCURACYCounts per lux at MTreg 69, 0.96 - 1.44 (the library always divides by 1.2)1.2

LUX, LUX2 and STEP_TIME work as in v1.0: with LUX 100, LUX2 1000 and STEP_TIME 3, the light steps to 1000 lx at 3 s. A slider or scene click overrides the step for the rest of the run, and every run starts again from LUX. Set ACCURACY to 1.44 to try a sensor that reads 20 % high.

BH1750 Simple: The Light Panel on the Sheet

Beside the Simple board sits the BH1750 LIGHT CONTROL panel (on the right of the image above):

The BH1750 Simple light panel
PartWhat it shows
Header, red XBH1750 LIGHT CONTROL; the X closes the panel
State barCONTINUOUS H-RES - 120 MS, ONE-TIME ..., POWER DOWN - WAITING FOR THE SKETCH or NO POWER - CHECK VCC / GND
LIGHT ON THE SENSOR / THE SENSOR READSThe light you set and the last result, with its counts, mode, MTreg and address
Log sliderDrag or click: 0 lx at the left stop, then 0.1 lx to 100 klx
Five scenesNIGHT 1, ROOM 150, OFFICE 500, OVERCAST 2000 and SUN 30000 lx
Chart, last 5 sThe light as an orange line, every measurement as a blue dot, an in-between one in violet
LAST I2C TRANSACTIONSThe reads decoded, for example R 23: 02 58 = 600 COUNTS

From OFFICE to SUN

In the image above, the chart shows the step from 100 to 500 lx and, right at the step, one violet dot: the measurement that was running when I clicked. Now click SUN:

BH1750 Simple board in Proteus at SUN 30000 lx: the sun with all rays lit, a bright sensor window and the panel with 30000 lx on the sensor, 30000.0 lx read, 36000 COUNTS and R 23: 8C A0 = 36000 COUNTS
Figure: SUN: the sun with every ray lit; 36000 counts = 30000.0 lx, and again one violet dot at the step from 500 lx.

The sky turns into the sun, every ray is lit, and the window shines white-yellow. The sensor makes 36000 counts (8C A0 in hex), and the library prints 30000.0 lx. That is still below the 65535 limit; full sunlight up to 100 klx would saturate the sensor at 54612.5 lx.

NIGHT: The Night Lamp Lights

Click NIGHT (1 lx):

BH1750 Proteus simulation at NIGHT: a moon in the sky, the panel with 1.0 lx on the sensor, 0.8 lx read and 1 COUNT, and the green night-lamp LED D1 on A0 of the Arduino UNO lit
Figure: NIGHT on NODE 1: the moon, 1 count = 0.8 lx, and the night lamp D1 on A0 is on.

The sky shows a moon, and the sensor makes just 1 count. One count is 0.83 lx, so 1.0 lx reads 0.8 lx, a 17 % error that only matters in the dark. That is below the sketch's 50 lx threshold, so UNO 1 switches on the night lamp, the green LED D1 on A0. The image also shows the wiring of NODE 1: SCL to A5, SDA to A4 and ADDR to ground.

Closing the Panel

Need room on the sheet? Click the red X: the board button says PANEL: CLOSED with a grey dot, and the sensor keeps measuring. PANEL brings it back.

BH1750 Simple board in Proteus with the light panel closed: PANEL: CLOSED with a grey dot, the sun in the sky, the PWR and I2C LEDs lit and ADDR 0x23
Figure: The panel closed: PANEL: CLOSED; the sun, the I2C LED and the MEAS bar still show the sensor at work.

BH1750 Advance: The Pop-Up Light Panel

The Advance device keeps only the board on the schematic. Here is U2:

BH1750 Advance board in Proteus: the blue GY-302 with a lamp in the sky, the MEAS bar, OPEN PANEL, ADDR 0x5C, the ADVANCE badge and the ADDR pin wired to a power terminal
Figure: U2 (Advance): ADDR goes to VCC, so the ADDR box says 0x5C; OPEN PANEL reopens the pop-up.

ADDR goes to a power terminal, so the box says ADDR 0x5C. At Run, the "TEP BH1750 Advance" pop-up opens with the look of our Serial Monitor and no Windows title bar: move it by its header, resize it, minimise it, and reopen it with OPEN PANEL. Its header shows the state (for example U2 · CONT H-RES, POWER DOWN or TESTING), the Light and Test tabs and the theme, Settings and Help icons.

The Light Page

BH1750 Advance Light page in Proteus: 500 lx OFFICE on the slider, THE SENSOR card with 0x5C ADDR pin HIGH and 600 counts = 500.0 lx, the live chart of the last 10 seconds and the I2C transactions with a read of 586 counts
Figure: The Light page at OFFICE: 600 counts = 500.0 lx; the I2C list shows the step from 120 counts over 586 to 600.

LIGHT ON THE SENSOR has the value, the log slider, Dark and the five scenes, and Darker x 0.5 / Brighter x 2. THE SENSOR shows what the chip is doing: power, mode, the measurement time with a progress bar, MTreg, the address and ADDR pin, the data register (600 counts = 500.0 lx), the resolution and range, and the measurements and I2C LED flashes so far.

LIVE - THE LAST 10 SECONDS draws the light, every measurement, the in-between ones and the sketch's reads as green rings. The I2C list tells the story of my click on Office 500: the sketch read 120 counts (100 lx) every 500 ms, then 586 counts, an in-between measurement that saw 500 lx for most of its 120 ms (the library makes 488.3 lx of it), and then 600 counts.

The Test Page: Four Measured Light Test Tools

The four tools on the Test tab only set the light and read the sensor's own logs: the finished measurements and the I2C transactions. They never talk to your Arduino, so every number is what your sketch and the sensor really did, measured with the simulation clock. Each tool ends with a "Good for:" line. All results below come from U2.

1. I2C Check: What Does Your Sketch Send?

This tool is live: it decodes the SDA and SCL pins while the sketch runs.

BH1750 I2C check in Proteus: address 0x5C ADDR HIGH, SCL clock measured 93.1 kHz, the sketch's set-up with W 23: no ACK, the address probe of 0x5C, opcodes 10, 42, 65, 10 and the last transactions R 5C: 02 58 = 600 counts
Figure: I2C check: SCL 93.1 kHz measured; the set-up W 23 no ACK, the 0x5C probe, then 10, 42, 65 and 10.

The top row says 0x5C ADDR HIGH, an SCL clock of 93.1 kHz measured from its rising edges (Wire is set to 100 kHz), 174 transactions to this sensor and 1 to another address. WHAT THE SKETCH SENT counts 2 mode writes, 2 MTreg bytes, 168 reads and 1 address probe.

THE SKETCH'S SET-UP lists the first transactions after power-up. At 65.4 ms, the sketch tried 0x23 and got no ACK, because U2 sits at 0x5C. Then its probe of 0x5C got an ACK, and begin() sent 10, about 10 ms later 42 and 65 (MTreg 69) and 10 again. The first read, at 428.1 ms, got 00 78 = 120 counts, that is 100 lx. Below, the last 16 transactions: 600 counts every 500 ms. Good for: checking which commands your sketch really sends, to which address, and how fast the clock is.

2. Timing: Does Your Sketch Read Fresh Results?

Choose a capture of 2, 5 or 10 s and click Run test. Here is 5 s with the demo's continuous H-resolution:

BH1750 timing test in Proteus: measurement time 120.0 ms, 10 reads by the sketch every 500 ms, 10 fresh, 0 again, 0 early, the value 55 ms old on average, 42 measurements and the H, H2 and L table
Figure: Timing, 5 s: 42 measurements of 120.0 ms, 10 reads every 500 ms, all fresh, the value 55 ms old on average.

The sensor finished 42 measurements of exactly 120.0 ms (8.3 per second), and the sketch read 10 times, every 500 ms. All 10 reads were fresh, a measurement the sketch had not read before. None was the same value again (a sketch that reads faster than the sensor measures) and none came too early. The value read was 55 ms old on average (13 - 113 ms): 500 ms is not a multiple of 120 ms, so each read lands at another point of the measurement cycle. The timeline shows the first 2 s, and the table lists the three resolutions at the MTreg in use.

Now click ONCE and MTREG 254 on U4 and capture again:

BH1750 timing test in one-time mode with MTreg 254: measurement time 441.7 ms, 8 reads every 674 ms, 8 fresh, 0 again, 0 early, the value 231 ms old, mode writes on the timeline and the table at MTreg 254
Figure: ONCE + MTreg 254: 441.7 ms per measurement, 8 reads every 674 ms, all fresh, every value 231 ms old.

The header now says U2 · ONCE H-RES. One measurement takes 441.7 ms (120 x 254 / 69), and the sketch read 8 times, every 674 ms, all fresh and never too early. Before each read, the sketch sends the mode (a violet line), the library waits 10 ms, and the sketch waits 663 ms, the data sheet's maximum at MTreg 254. So every value is 231 ms old (673 - 441.7 ms), and the interval grows from 500 to 674 ms, because the sketch waits inside its reading. Between measurements, the chip sits in Power Down. Good for: checking that your sketch waits for a fresh result, and seeing how old the value it reads is.

3. Step Response: How Fast Does a Change Reach Your Sketch?

Choose a step (100 to 1000, 1000 to 100, 10 to 10k or 0 to 500 lx) and 3, 5 or 10 runs; each run steps at a different moment against the measurements. 100 to 1000 lx, five runs:

BH1750 step response test in Proteus, 100 to 1000 lx in 5 runs: an in-between value in 5 of 5 runs after 66 ms, the first full result after 186 ms, the sketch has the new light after 436 ms, and a chart of the newest run
Figure: Step response: an in-between value in 5 of 5 runs (66 ms), the first full result after 186 ms, the sketch after 436 ms.
Step response, 100 to 1000 lx (U2; every time counts from the step)
RunIn-betweenFull resultSketch has the new light
152 ms: 486.7 lx172 ms485 ms
285 ms: 734.2 lx205 ms438 ms
3117 ms: 974.2 lx237 ms390 ms
424 ms: 276.7 lx144 ms456 ms
556 ms: 516.7 lx176 ms409 ms

In all 5 runs, the measurement running at the step ended with an in-between value, 66 ms after the step on average. Its value depends on how much of its 120 ms was left: in run 3, 117 ms of it saw 1000 lx, and it read 974.2 lx; in run 4, only the last 24 ms did, and it read 276.7 lx. The next measurement, the first full result, ended 120 ms later, 186 ms after the step on average. The sketch saw the change after 436 ms on average (390 - 485 ms), because it reads only every 500 ms, and here its first changed read was already the full 1000.0 lx. Good for: seeing how long a change of light takes to reach your sketch: the measurement plus its read interval.

4. Lux Sweep: Resolution, Range and Saturation

Choose Dim 0 - 10 lx, Indoor 0 - 1000 lx or Full 0.1 lx - 100 klx (log). At every point, the tool waits until the sketch has read a full measurement made at that light (3 s at most). Full, 14 points:

BH1750 lux sweep in Proteus from 0.1 lx to 100 klx: H-RES / MTreg 69, 0.83 lx per step, saturates at 54612 lx, largest error 16.7 %, the counts chart and the MTreg 31, 69, 138 and 254 table
Figure: Lux sweep, Full: 1.0 lx = 1 count (0.8 lx); 60 and 100 klx read 65535 counts = 54612.5 lx, saturated.

At 0.1 and 0.3 lx, the sensor makes 0 counts, and the sketch reads 0.0 lx. 1.0 lx gives 1 count = 0.8 lx, the largest error of the sweep, 16.7 %, and 3.0 lx gives 4 counts = 3.3 lx (+11.1 %). From 10 lx on, every reading is exact: 120 counts at 100 lx, 36000 at 30 klx. At 60 and 100 klx, the counts stop at 65535, and the sketch reads 54612.5 lx: the sensor is saturated. The MTreg table shows the trade-off: MTreg 31 reaches 121557 lx with 1.85 lx steps, while MTreg 254 has 0.23 lx steps but stops at 14836 lx. Good for: seeing the resolution and the range of your mode and MTreg, and where the sensor saturates.

Settings and Help

The gear opens Settings: theme (TEP Dark or Light), text size, open the panel at Run and the window size, saved for your Windows user. Look at the header: U2 · POWER DOWN. I opened Settings while U4 ran one-time readings, and the sensor sleeps between them.

Settings page of the BH1750 Advance pop-up: theme TEP Dark or Light, text size, open the panel at Run, window size, and the header showing U2 POWER DOWN
Figure: Settings, saved under HKCU\Software\TheEngineeringProjects\TEP BH1750 Advance; the header shows POWER DOWN between one-time measurements.

The ? icon opens Help & Support: eight cards with their links (report a bug and suggest a feature on the BH1750 board of our forum, this article, the user guide, updates, donate, website, forum) and Copy diagnostics for a bug report. A links.ini next to the DLL can change the links.

Help and Support page of the BH1750 Advance: eight cards with their links to the BH1750 forum board, this article, the donate page, the website and the forum, and the Copy diagnostics button
Figure: Help & Support: every card shows its link; TEP BH1750 Advance v1.1, build 2026-10-08, TEPBH1750.DLL.

BH1750 Night Lamp with Arduino in Proteus

Open BH1750-ArduinoUnoV3.pdsprj from the Proteus Simulation folder, with the .hex file and both DLLs beside it. Its two Arduino UNOs from our Arduino Library for Proteus V3.0 both run BH1750_Demo.hex:

  • NODE 1 - SIMPLE, ADDR LOW = 0x23: UNO 1 (ARD1) with the BH1750 Simple (U1), the night lamp D1 on A0 and Serial Monitor U3.
  • NODE 2 - ADVANCE, ADDR HIGH = 0x5C: UNO 2 (ARD2) with the BH1750 Advance (U2), the night lamp D2 on A0 and Serial Monitor U4.
BH1750 Arduino Proteus circuit running: two Arduino UNOs, the BH1750 Simple at night with the moon and the green night lamp D1 lit, the BH1750 Advance in sunlight with D2 off, and two TEP Serial Monitors
Figure: The whole circuit while it runs, with the windows moved aside: U1 at NIGHT (moon, D1 on), U2 in SUN (D2 off).

Wiring

Demo wiring (the same on both UNOs except ADDR)
FromToWhy
BH1750 VCC / GNDSupply / groundPower
BH1750 SCL / SDAArduino A5 / A4I2C clock and data (the UNO's I2C pins)
U1 ADDRGroundAddress 0x23 (open works too)
U2 ADDRSupplyAddress 0x5C
LED + 220 ΩA0 to GNDThe night lamp
Serial Monitor RXD / TXD / GNDArduino D1 / D0 / groundShows what the Arduino prints, sends what you type

In Proteus, the UNO's Wire library uses its internal pull-ups on A4 / A5, as in the v1.0 demo; the model only pulls SDA LOW. RXD2, the monitor's second input, is not used: I2C has no serial line to watch. See our Introduction to Arduino UNO for the pins.

The Arduino Code

The sketch needs Wire and the BH1750 library by Christopher Laws, included in the package:

#include <Wire.h>
#include <BH1750.h>

BH1750 lightMeter;

New in v1.1, the sketch finds the sensor at either address. A bare address write, a probe, that gets an ACK means a device answers there:

byte findSensor() {
  const byte candidates[2] = {0x23, 0x5C};
  for (byte i = 0; i < 2; i++) {
    Wire.beginTransmission(candidates[i]);
    if (Wire.endTransmission() == 0) return candidates[i];
  }
  return 0;
}

In setup(), Wire runs at 100 kHz with a 25 ms timeout, as in v1.0:

  Wire.begin();
  Wire.setClock(100000);
  Wire.setWireTimeout(25000, true);

Then begin() starts continuous H-resolution at the address found:

  sensorAddress = findSensor();
  sensorReady = sensorAddress && lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, sensorAddress);

begin() sends 10 and sets MTreg 69, which sends 42, 65 and the mode again: exactly the set-up the I2C check showed. The loop() reads every 500 ms with millis() instead of delay(), so typed commands stay responsive:

void loop() {
  readCommands();
  if (sensorReady && every && millis() - lastReading >= every) {
    lastReading = millis();
    takeReading();
  }
}

takeReading() is the v1.0 reading plus a one-time branch: send the mode, wait for the measurement, then read:

void takeReading() {
  if (oneTime) {                        // one-time: start a measurement, wait for it, then read (the chip powers down after it)
    lightMeter.configure(modeFor(true, resolution));
    delay(measureMs(true));
  }
  const float lux = lightMeter.readLightLevel();

The night lamp switches on below NIGHT lx (50 by default):

  if (!lampOn && lux < nightLux) {
    lampOn = true;
    digitalWrite(A0, HIGH);

It switches off only above 1.2 times the threshold, so it cannot flicker around it (hysteresis), and it prints a line only when it switches:

  } else if (lampOn && lux > nightLux * 1.2) {
    lampOn = false;
    digitalWrite(A0, LOW);

To change the sketch, export a new HEX file and load it into both UNOs; see How to get the HEX file from Arduino. New to Arduino? Start with our Arduino Tutorial for Beginners.

A Bug in the BH1750 Library: MTreg above 182

While building v1.1, we found a bug in the claws library 1.3.0. measurementReady(true) tells a one-time sketch when the maximum measurement time has passed, and it computes 180 x MTreg in an int. On the UNO, an int has 16 bits and holds at most 32767. Up to MTreg 182, 180 x 182 = 32760 fits; at MTreg 183, 180 x 183 = 32940 overflows to a negative number. Stored in the library's unsigned long, that becomes a wait of about 49 days, so measurementReady(true) never says ready, and a one-time sketch that waits for it hangs.

The demo avoids the bug: it does not call measurementReady(), but works out the wait itself in unsigned long (32 bits):

// the measurement time of the mode in use at this MTreg (datasheet maximum: 180 / 24 ms at MTreg 69)
unsigned long measureMs(bool maximum) {
  const unsigned long base = resolution == 2 ? (maximum ? 24UL : 16UL) : (maximum ? 180UL : 120UL);
  return base * mtreg / 69 + 1;
}

180UL makes the multiplication 32-bit: 180 x 254 / 69 + 1 = 663 ms at MTreg 254. The sketch's header notes it, too:

// Note: the library's measurementReady(true) computes 180 * MTreg in a 16-bit int on AVR and overflows for MTreg > 182, so
// the one-time wait below is computed here in unsigned long.

In your own one-time sketches, compute the wait the same way, or keep MTreg at 182 or below.

Serial Monitor Commands

Commands of the demo sketch (quick buttons: U3 STATUS, MODE L, MODE H, NIGHT 200; U4 STATUS, ONCE, CONT, MTREG 254)
CommandWhat it does
HELPThe command list (two lines)
STATUSAddress, mode, MTreg, reading interval, readings, the last value and the night lamp (two lines)
MODE H / H2 / LH-resolution (1 lx steps, 120 ms), H-resolution2 (0.5 lx), L-resolution (4 lx, 16 ms)
ONCE / CONTA one-time measurement before every reading (the sensor powers down between) / continuous
MTREG n31 - 254 (69 = default): more sensitive, finer and slower
EVERY msThe reading interval, 100 - 10000 ms (0 = pause)
NIGHT lxThe night lamp's threshold (default 50 lx, 0 = lamp off)
READOne reading now

Commands are not case-sensitive; an unknown one gets "Unknown command: X - type HELP". Every line the sketch prints is shorter than 80 characters, so it fits the Serial Monitor's Simple interface.

How to Run the Demo

  1. Press Run. Both Serial Monitors (9600 baud) and U2's pop-up open, and the I2C LEDs flash with every reading.
  2. On U1's panel, click NIGHT (D1 lights), then SUN; close and reopen the panel.
  3. On U3, click STATUS, MODE L, MODE H and NIGHT 200 (try ROOM and OFFICE); type MODE H2 at SUN, EVERY 0 and READ.
  4. On U4, click ONCE and MTREG 254, then STATUS.
  5. In U2's pop-up, try the Light page, then run the four tools on the Test tab.

BH1750 Proteus Simulation Results

The Serial Monitor in Its Simple Interface

Both monitors run in the Simple interface of our TEP Serial Monitor, as in every monitor screenshot here: only the log, the send box and one slim toolbar row (baud rate, follow, pause, search, clear) stay visible, so the window stays small next to your schematic.

  • Switch to it: right-click the log and choose Simple interface, or press Ctrl+Shift+U.
  • Back to the full view: click the corner button (the expand arrows at the top right), press Esc or Ctrl+Shift+U, or right-click and choose Full interface.
  • Your choice is remembered.

Type commands such as STATUS or MODE H2 in the send box and press Enter; the quick buttons return with the full view. Lines you send carry a blue TX tag, the Arduino's lines a green RX tag. Read all about the monitor in TEP Serial Monitor Advance for Proteus.

Start-Up: The Sensor Is Found

After Run, U3 prints the banner, the address it found and the commands:

BH1750 Arduino Proteus start-up in the TEP Serial Monitor Simple interface: TEP BH1750 light sensor demo v1.1, BH1750 found at 0x23 (ADDR LOW), the two-line command list and Light: 100.0 lx
Figure: U3 in the Simple interface: the sensor found at 0x23 (ADDR LOW), the two-line HELP and 100.0 lx.
TEP BH1750 light sensor demo v1.1
BH1750 found at 0x23 (ADDR LOW): continuous H-resolution, MTreg 69
Serial Monitor: HELP, STATUS, MODE H / H2 / L, ONCE, CONT,
  MTREG n, EVERY ms, NIGHT lx, READ
Light: 100.0 lx
Light: 100.0 lx

Then "Light: 100.0 lx" follows every 500 ms, because LUX starts at 100. U4 prints the same with "found at 0x5C (ADDR HIGH)".

The Night Lamp at Work

Next, I clicked OFFICE, NIGHT and SUN on U1's panel:

BH1750 night lamp in the TEP Serial Monitor Simple interface: Light: 500.0 lx, Night lamp OFF, Light: 0.8 lx, Night lamp ON (0.8 lx below 50 lx), an in-between Light: 14104.2 lx, Night lamp OFF and Light: 30000.0 lx
Figure: U3: OFFICE, NIGHT (Night lamp ON), then SUN with one in-between reading of 14104.2 lx.
Light: 0.8 lx
Light: 500.0 lx
Night lamp OFF (500.0 lx)
Light: 500.0 lx
Light: 500.0 lx
Light: 0.8 lx
Night lamp ON (0.8 lx < 50 lx)
Light: 0.8 lx
Light: 0.8 lx
Light: 14104.2 lx
Night lamp OFF (14104.2 lx)
Light: 30000.0 lx
Light: 30000.0 lx

OFFICE switched the lamp off. NIGHT gave 0.8 lx and Night lamp ON (0.8 lx < 50 lx), and D1 lit. Then SUN: the next reading, 14104.2 lx, is an in-between measurement. The step fell in the middle of it, so it saw roughly half 0.8 lx and half 30000 lx. That is far above 60 lx (1.2 x 50), so the lamp went off at once. The step from 500 to 0.8 lx gave no in-between line: in 500 ms the sensor finishes about four measurements, and the sketch reads only one of them.

STATUS

Type STATUS (or click its quick button) at night, and U3 answers in two lines:

BH1750 STATUS in the TEP Serial Monitor Simple interface: Status: 0x23 (ADDR LOW), continuous H-resolution, MTreg 69, every 500 ms, last: 0.8 lx after 99 readings, night lamp on (below 50 lx)
Figure: STATUS at night: 0x23, continuous H-resolution, MTreg 69, 0.8 lx after 99 readings, night lamp on.
STATUS
Status: 0x23 (ADDR LOW), continuous H-resolution, MTreg 69, every 500 ms
  last: 0.8 lx after 99 readings, night lamp on (below 50 lx)

MODE H2: Finer Steps, Half the Range

At SUN, I typed MODE H2:

BH1750 MODE H2 in the TEP Serial Monitor Simple interface at SUN: Light: 30000.0 lx, MODE H2, Mode: continuous H-resolution2 (0.5 lx steps, 120 ms), then Light: 27306.2 lx, saturated
Figure: MODE H2 at SUN: the readings stop at 27306.2 lx, the full scale of H-resolution2.
Light: 30000.0 lx
MODE H2
Mode: continuous H-resolution2 (0.5 lx steps, 120 ms)
Light: 27306.2 lx
Light: 27306.2 lx

H-resolution2 counts twice as fine, so 30000 lx would need 72000 counts. The sensor stops at 65535, and the library prints 27306.2 lx: saturated. MODE H goes back. Right after a mode change, one reading can be off by a factor of 2 (at SUN: 15000.0 lx once): the library switches its formula at once, but the data register holds the old mode's result until the first new measurement ends. The real sensor does the same, so wait one measurement time after a mode change. In this run, the first read came late enough.

ONCE and MTREG 254 on U4

On U4, I clicked ONCE and MTREG 254, then typed STATUS:

BH1750 one-time mode with MTreg 254 in the TEP Serial Monitor Simple interface on U4: One-time mode, MTreg 254: 3.68 x sensitivity, 441 ms per measurement, Light: 500.1 lx and the STATUS lines with 0x5C (ADDR HIGH)
Figure: U4: ONCE, MTREG 254 (3.68 x sensitivity, 441 ms per measurement), 500.1 lx and STATUS.
One-time mode: a new H-resolution measurement before every reading
Light: 500.0 lx
Light: 500.0 lx
Light: 500.0 lx
MTREG 254
MTreg 254: 3.68 x sensitivity, 441 ms per measurement
Light: 500.1 lx
Light: 500.1 lx
STATUS
Light: 500.1 lx
Status: 0x5C (ADDR HIGH), one-time H-resolution, MTreg 254, every 500 ms
  last: 500.1 lx after 241 readings, night lamp off (below 50 lx)

MTREG 254 makes the sensor 3.68 times as sensitive (254 / 69), and the library divides by 3.68 again, so the readings stay at 500 lx. The extra 0.1 lx is rounding: 500 x 1.2 x 254 / 69 = 2208.7 counts, rounded to 2209, gives 500.07 lx. After STATUS, one more Light line came first, because the sketch was waiting for a one-time measurement when the command arrived.

Your v1.0 Designs Keep Working

I opened the v1.0 release demo (the v1.0 symbol, the v1.0 sketch and the Virtual Terminal) with the v1.1 TEPBH1750.DLL:

BH1750 v1.0 design running on the v1.1 DLL in Proteus: the v1.0 board with its LIGHT LEVEL panel at 1180.0 lx, 0 - 2000 lx, DRAG TO CHANGE, and the Virtual Terminal printing Light: 100.0 lx and then Light: 1180.0 lx
Figure: A v1.0 design on the v1.1 DLL: the v1.0 panel and sketch; a slider click to 1180.0 lx, and the terminal follows.

It shows the v1.0 panel exactly as before and printed "Light: 100.0 lx"; a click on the slider set 1180.0 lx, and the terminal printed "Light: 1180.0 lx". Re-pick the part when you want the v1.1 board.

Troubleshooting

  • "Sensor not found: check VCC, GND, SDA, SCL and ADDR.": check VCC / GND (the PWR LED must be lit), SCL on A5, SDA on A4 and the address against the ADDR pin (the ADDR box shows it); restart the simulation after the fix.
  • "Light: 0.0 lx" right after the start: a read before the first measurement is done returns 0, on the real chip too.
  • A reading between the old and the new light: correct; the BH1750 averages the light over its measurement.
  • The reading stops at 54612.5 lx (27306.2 in H-resolution2): the sensor is saturated; use MTREG 31 for bright light.
  • Your one-time sketch hangs with MTreg above 182: the measurementReady(true) bug above.
  • The Test tab says "Cannot start: ...": no power, the sketch has not started a measurement yet, or another test runs.
  • No panel, pop-up or monitor: a DLL is missing from MODELS and the project folder; click OPEN PANEL or OPEN MONITOR, or turn "Open the panel at Run" back on in Settings.
  • The board looks like v1.0 (no red X): the design holds the v1.0 symbol; replace the LIB, delete TEPBH1750.IDX and re-pick the part.
  • A lamp drawn near the sensor changes nothing: the slider, the scenes and the LUX properties are the light; the model has no optics.

Things to Know Before Using a Real BH1750 (GY-302)

The demo sketch uses only Wire and the claws library, so it runs on a real UNO and GY-302, too. Keep in mind:

  • Supply: VCC 3.3 V or 5 V. The GY-302 has a 3.3 V regulator (662K), and most boards work from a 5 V UNO directly, but check yours: some sellers recommend a level shifter.
  • Pull-ups: the GY-302 carries 4.7 k pull-ups on SCL and SDA. In Proteus, the demo relies on the UNO's internal pull-ups instead.
  • Address: ADDR LOW or open = 0x23, ADDR HIGH (at least 0.7 x VCC) = 0x5C; two sensors on one bus need one of each.
  • Accuracy: 1.2 counts per lux typical, 0.96 - 1.44, so a real sensor can read up to 20 % high or low; calibrate it against a known light meter.
  • Range: about 0.8 - 54612 lx in H-resolution at MTreg 69. Direct sunlight (up to 100 klx) saturates it, so use MTreg 31 (121557 lx) or put a diffuser in front of it.
  • Slow at high MTreg: MTreg 254 takes 442 ms typical, 663 ms maximum.
  • Flicker: 50 / 60 Hz flicker averages out over a 120 ms H-resolution measurement; a 16 ms L-resolution measurement does not average it.

Limitations of the Simulation

  • Not modelled: light flicker, spectral response and angle, temperature drift, the DVI reset pin (tied on the GY-302), the real chip's 400 kHz I2C limit and bus capacitance, and the 3.3 V regulator.
  • The model is our own implementation, written from ROHM's published BH1750FVI data sheet; it contains no ROHM code.
  • Tested in Proteus 8.5 on 8 Oct 2026 with this package's demo (both panels, the four tools, a v1.0 design and every screenshot here) and with 1,475 automatic PC checks, all passed, 58 of them with the unmodified claws library and 50 with the real demo sketch on two UNOs. Proteus 7 is not supported.

Need temperature, humidity and pressure next to the light? See our BME280 Sensor Library for Proteus. To send your readings to another Arduino by radio, add our HC-12 Library for Proteus.

So, that was all about the BH1750 Light Sensor Library for Proteus V1.1. I hope the sky over the board, the in-between readings and the four test tools make light measurement much easier to understand, so your night lamp or light logger works the first time you wire a real GY-302. If you use the BH1750 Light Sensor Library for Proteus in a project, please share your feedback in the comments or in our forum, and if you have any questions, ask in the comments and I will help you out. Till the next tutorial, take care and have fun!


Comments

0

Join the conversation