ESP32 I2C and ADC – Light sensor digital and analog

Even the brightness or light values are not really important for a weather station,






I added this information as well in my first ESP32 project. I did it mainly because I could learn how to use the I2C connection and the analog to digital converter of the ESP32.

I had two sensors laying around for this, one is a TSL2561, a sensor that measures light and returns the values in Lux. I have a module that I purchased from Adafruit. The second is a simple LDR, an electronic component that changes it resistance with the amount of light it receives.



The hardware – schematic

The TSL2561 has an I2C interface. The module I used accepts power supply from 3V to 5V and has level-shifters and pull-up resistors for the I2C lines already integrated. Therefor the connection to the ESP32 is very simple. I used the default I2C pins of the ESP32 to connect the module.

  • SDA -> GPIO21
  • SCL -> GPIO22

To use the LDR, it has to connected with an resistor voltage divider to the analog to digital converter input of the ESP32. I used ADC0 of the chip to read the voltage.

Here is the very simple schematic:


The source code

As the TSL2561 is a widely used sensor it was not difficult to find matching libraries on the internet. The one that worked best was from Adafruit. However, it was not optimized to work with the ESP32 and in addition, it needs a second library, the Adafruit Unified Sensor library. I wanted to have it a little bit more simple, so I created my own small library based on the code from Adafruit. The result is a TSL2561.cpp and a TSl2561.h, which has the same functionality as the original Adafruit library, but doesn’t need the additional unified sensor library.

Here is an extract of the header file TSL2561.h. If you select the copy function, the whole code will be copied (including not shown lines).

And here is an extract of  TSL2561.cpp. Again, if you select the copy function, the whole code will be copied (including not shown lines).

The usage and available functions of the library are the same as the original Adafruit library.


TSL2561 – simplified library

The TSL2561 is quite easy to initialize and has two functions that helps to adapt the sensor readings to changing brightness and to avoid saturation of the sensor. One is the option to change the gain (x1 for bright environment, x16 for dark environment) and the second one is the option to change the integration time between 13ms (very bright), 101ms and 402ms (very dark). For more information about this check the datasheet of the TSL2561 (courtesy of Adafruit).

The library offers the option to enable automatic gain changes depending on the light values that are measured. For the integration time I developed a logic that switches between the different possibilities depending on the light values that I receive from the sensor.

Here are the code extracts used to read light measurement values from the TSL2561:

To use the library, of course we need to include the header file

Then we need to add the class and the I2C interface (called TwoWire within Arduino world).

The following function configures the sensor

And this function reads the light values and adapts the integration time if necessary 

The readLux() function will be called frequently and returns the measured value in Lux in the range of 0 to 65535, if the sensor reading failed or the sensor is saturated (can happen in bright sun light) 65536 is returned as an error value.



LDR ‘sensor’ software

A LDR is a resistor that changes it resistance depending on the brightness. To read a value from it the LDR must be inserted into an voltage divider between Vcc (3.3V here) and GND. Different LDR’s have different minimum (at highest brightness) and maximum (at darkness/no light) resistances. The one I had has a maximum resistance of 2MΩ and a minimum resistance of 5kΩ. Here the schematic how I connected the sensor:

I didn’t calculate the resistors, as I my goal was to learn how to use the analog to digital converter (ADC) of the ESP32 and not to calculate the brightness from the measured voltage. Anyway with the above settings I read values between 260 and 3300 ( the ADC outputs values from 0 to 4096 between 0V and 3.3V).

The software to read the voltage from the ADC is quite simple.

First we define the GPIO/ADC channel to be used

Then we initialize the port and ADC channel

The resolution of the ADC was reduced to 11 bits (instead of 12 bits) and the attenuation was set to 6dB. Without that, the signal can be very noisy and non-linear (Reference: Espressif BBS Linearity of esp 32 and ESP32 ADC Calibration curves?

 To read the value is a simple call of

Next would be to calculate the voltage from the read value and try to convert it into a Lux value. But I didn’t go there.


Leave a Reply

Your email address will not be published. Required fields are marked *

Free Link Directory