{"id":4337,"date":"2019-01-23T20:00:26","date_gmt":"2019-01-23T19:00:26","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4337"},"modified":"2025-12-27T20:01:35","modified_gmt":"2025-12-27T19:01:35","slug":"measuring-light-intensity-using-stm32","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/measuring-light-intensity-using-stm32\/","title":{"rendered":"Measuring Light Intensity Using STM32"},"content":{"rendered":"\n<p>Measuring light intensity is common in our everyday life. Probably everyone has an auto dimming\/brightening screen feature in their smartphone. It is based precisely on measuring the light intensity around the device. The measurement is performed continuously while the phone is unlocked. Today I will focus on how we can measure this parameter using three different sensors. Will they produce similar readings?<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Light measurement \u2013 today&#8217;s heroes<\/h1>\n\n\n\n<p>I will measure light with three sensors: <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/bh1750-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=light_sensors&amp;utm_content=Text\">BH1750<\/a>, <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/max44009-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=light_sensors&amp;utm_content=Text\">MAX44009 <\/a>and <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/temt6000-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=light_sensors&amp;utm_content=Text\">TEMT6000<\/a>.<\/p>\n\n\n\n<p>You can download the datasheets for these chips here:<\/p>\n\n\n\n<p><a data-e-disable-page-transition=\"true\" class=\"download-link\" title=\"\" id=\"download-link-547\" data-redirect=\"false\" href=\"https:\/\/msalamon.pl\/download\/547\/?tmstv=1766859694\" rel=\"nofollow\">BH1750FVI Datasheet<\/a><a data-e-disable-page-transition=\"true\" class=\"download-link\" id=\"download-link-544\" data-redirect=\"false\" title=\"\" href=\"https:\/\/msalamon.pl\/download\/544\/?tmstv=1766859694\" rel=\"nofollow\"><br>MAX44009 Datasheet<\/a><a data-e-disable-page-transition=\"true\" class=\"download-link\" id=\"download-link-660\" data-redirect=\"false\" title=\"\" href=\"https:\/\/msalamon.pl\/download\/660\/?tmstv=1766859694\" rel=\"nofollow\"><br>TEMT6000 Datasheet<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Schematic and Cube configuration<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/kategoria-produktu\/dev-boardy\/stm32-nucleo\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=light_sensors&amp;utm_content=nucleo\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg\" alt=\"\" class=\"wp-image-1593\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-768x256.jpg 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>For today\u2019s task I took the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/nucleo-f401re\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=light_sensors&amp;utm_content=Text\">Nucleo with STM32F401RE<\/a> board. Since I am once again working with ready-made Chinese modules, the schematic is quite simple.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"453\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic.jpg\" alt=\"\" class=\"wp-image-647\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic-300x142.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic-768x362.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic-24x11.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic-36x17.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_schematic-160x76.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Two of today\u2019s sensors communicate via the I\u00b2C interface. Additionally, one can assert interrupts, so I will assign a suitable pin for it. The third sensor outputs an analog value, so we need to prepare one of the analog inputs. The final pinout looks like this.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"529\" height=\"500\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube.jpg\" alt=\"\" class=\"wp-image-646\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube.jpg 529w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube-300x284.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube-24x24.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube-36x34.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/light_sensors_cube-85x80.jpg 85w\" sizes=\"auto, (max-width: 529px) 100vw, 529px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>I configure I\u00b2C at 400 kHz. The interrupt will need to react to the falling edge. I will discuss the ADC configuration later with the respective sensor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">BH1750<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/bh1750-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=light_sensors&amp;utm_content=bh1750\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner.jpg\" alt=\"\" class=\"wp-image-1142\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/BH1750_baner-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The first tested sensor is the low-power BH1750 from <em>ROSH Semicondutor<\/em>(<a data-e-disable-page-transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/msalamon.pl\/download\/547\/?tmstv=1766859694\" rel=\"nofollow\" id=\"download-link-547\" data-redirect=\"false\"><br>BH1750FVI Datasheet<\/a><br>). You can talk to it over the I\u00b2C interface with a maximum clock frequency of 400 kHz. It has a built-in ADC that converts the measured light intensity into a digital value. Its measurement range is 1 \u2013 65535 lux. The sensor allows calibration of measurement sensitivity. Thanks to this it can detect as low as 0.11 lux. This setting can also be adjusted to the covering material, e.g. glass. You should know the value of the light transmission through that material. See the datasheet for details.<\/p>\n\n\n\n<p>The sensor can operate in several modes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Continuous high resolution (1 lx)<\/li>\n\n\n\n<li>Continuous high resolution 2\u00a0(0.5 lx)<\/li>\n\n\n\n<li>Continuous low resolution\u00a0(4 lx)<\/li>\n\n\n\n<li>One-time high resolution\u00a0(1 lx)<\/li>\n\n\n\n<li>One-time high resolution 2\u00a0(0.5 lx)<\/li>\n\n\n\n<li>One-time low resolution\u00a0(4 lx)<\/li>\n<\/ul>\n\n\n\n<p>The manufacturer recommends using the high-resolution mode with a 1 lux resolution. Allegedly it handles interference well. I also like it because the value in the measurement registers will not need to be converted. In continuous mode the measurement is performed cyclically at 120 ms or 16 ms intervals depending on the chosen mode. In manual mode, the conversion is triggered only once. You must then wait until the ADC finishes (120 ms for high-res and 16 ms for low-res) before you can read the measurement value. Unlike continuous operation, in manual mode the sensor automatically enters Power Down after the conversion where the current consumption is negligible (typ. 0.01&nbsp;\u00b5A) compared to what is required for conversion (typ. 120&nbsp;\u00b5A). You don\u2019t have to wake the sensor manually. Just request a conversion.<\/p>\n\n\n\n<p>The register table is basically not a register table. You communicate with the sensor using a set of commands without writing anything directly to its memory. Let\u2019s move on to the code.<\/p>\n\n\n\n<p>In the first step, the sensor should be initialized. In addition to passing a pointer to the I\u00b2C interface used, I reset the sensor and set its default <em>measurement time<\/em> value.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_Init(I2C_HandleTypeDef *hi2c);<\/pre>\n\n\n\n<p>The following functions are used to reset the sensor and control the Power Down state<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_Reset(void);\nBH1750_STATUS BH1750_PowerState(uint8_t PowerOn);<\/pre>\n\n\n\n<p>If you need to change the sensor\u2019s sensitivity, use<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_SetMtreg(uint8_t Mtreg);<\/pre>\n\n\n\n<p>Set the mode in which the sensor is to operate with<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_SetMode(bh1750_mode Mode);\n<\/pre>\n\n\n\n<p>using an enum variable with predefined commands. This reduces the risk of mistakes.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">typedef enum\n{\n\tCONTINUOUS_HIGH_RES_MODE = 0x10,\n\tCONTINUOUS_HIGH_RES_MODE_2 = 0x11,\n\tCONTINUOUS_LOW_RES_MODE = 0x13,\n\tONETIME_HIGH_RES_MODE = 0x20,\n\tONETIME_HIGH_RES_MODE_2 = 0x21,\n\tONETIME_LOW_RES_MODE = 0x23\n}bh1750_mode;\n<\/pre>\n\n\n\n<p>If you will be using manual mode, you will need a function that triggers the conversion. In fact, it just sends the command to set the conversion mode because that\u2019s what the sensor requires, but who would remember throughout the project which mode is used \ud83d\ude09<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_TriggerManualConversion(void);<\/pre>\n\n\n\n<p>And the most important one: the function to read the value measured by the sensor. Its usage should be straightforward.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">BH1750_STATUS BH1750_ReadLight(float *Result);\n<\/pre>\n\n\n\n<p>What does a read from the sensor look like? It\u2019s enough to receive data directly from its address. Its address is at the same time the register from which the result is read. There\u2019s no great philosophy here, hence the reading and value conversion are instantaneous. In <em>high resolution 2<\/em> mode with 0.5 lux precision, it takes 0.28 ms for a 100 kHz I\u00b2C clock and 80&nbsp;\u00b5s for 400 kHz.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k.jpg\" alt=\"\" class=\"wp-image-551\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_100k-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>100 kHz:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k.jpg\" alt=\"\" class=\"wp-image-552\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/bh1750_read_400k-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>400 kHz:<\/p>\n\n\n\n<p>Remember that if you want to use manual conversion, you must wait the appropriate time between requesting the measurement and reading it. Of course, the data can be read using DMA. Try to do it yourself \ud83d\ude42<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">MAX44009<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/max44009-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=light_sensors&amp;utm_content=max4409\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner.jpg\" alt=\"\" class=\"wp-image-1145\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/MAX44009_baner-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The next sensor today is the MAX44009 from <em>Maxim<\/em> <em>Integrated<\/em>&nbsp;(<a data-e-disable-page-transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/msalamon.pl\/download\/544\/?tmstv=1766859694\" rel=\"nofollow\" id=\"download-link-544\" data-redirect=\"false\"><br>MAX44009 Datasheet<\/a><br>). Like the BH1750, it has a built-in ADC and an I\u00b2C communication interface. It differs, among other things, in the way the result is encoded. It is stored in floating-point form with a 4-bit exponent and an 8-bit mantissa. I wrote about floating-point numbers <a href=\"http:\/\/msalamon.pl\/ile-kosztuje-uzywanie-float-i-co-daje-fpu\/\">here<\/a>. The way the measurement value is stored allows you to read the result with different precision. You can read two registers and get a high-resolution result, or you can skip the second register, which contains the lower bits of the mantissa, and enjoy a faster result but with lower resolution.<\/p>\n\n\n\n<p>Another difference is the <em>INT<\/em> pin, i.e. the ability for the chip to assert an interrupt to the microcontroller. The interrupt can be asserted after exceeding one of the configurable light intensity thresholds \u2014 upper or lower. At the same time, a minimum time the threshold must be exceeded is defined to decide whether to assert the interrupt. Of course, the thresholds can be set as a window. Importantly, the interrupt will be asserted even if it is operating in manual mode.<\/p>\n\n\n\n<p>Because the MAX44009 is a bit more feature-rich, the library is more extensive. Initialization only assigns the I\u00b2C pointer:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MAX44009_STATUS MAX44009_Init(I2C_HandleTypeDef *hi2c);<\/pre>\n\n\n\n<p>Next are the sensor configuration functions. You can write the appropriate value to the register in one go, or use several convenient self-documenting functions that change only one function.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MAX44009_STATUS MAX44009_ReadConfigurationRegister(uint8_t *Config);\nMAX44009_STATUS MAX44009_WriteConfigurationRegister(uint8_t Config);\n\nMAX44009_STATUS MAX44009_ContinuousMode(uint8_t Enable);\nMAX44009_STATUS MAX44009_ManualConfiguration(uint8_t Enable);\nMAX44009_STATUS MAX44009_CurrentDivisionRatio(uint8_t Enable);\nMAX44009_STATUS MAX44009_IntegrationTime(max44009_timer Timer);<\/pre>\n\n\n\n<p>Note the last function, which takes an enum as an argument:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">typedef enum\n{\n\tINTEGRATION_TIME_6_25_MS = 0x07, \/\/ Manual mode only\n\tINTEGRATION_TIME_12_5_MS = 0x06, \/\/ Manual mode only\n\tINTEGRATION_TIME_25_MS = 0x05, \/\/ Manual mode only\n\tINTEGRATION_TIME_50_MS = 0x04, \/\/ Manual mode only\n\tINTEGRATION_TIME_100_MS = 0x03, \/\/ This is a preferred mode for high-brightness applications\n\tINTEGRATION_TIME_200_MS = 0x02,\n\tINTEGRATION_TIME_400_MS = 0x01,\n\tINTEGRATION_TIME_800_MS = 0x00 \/\/ This is a preferred mode for boosting low-light sensitivity\n} max44009_timer;<\/pre>\n\n\n\n<p>The most important part is of course reading the ambient light value. As I mentioned earlier, it can be done in two ways and I have included both.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MAX44009_STATUS MAX44009_ReadLightLowResolution(float *Result);\nMAX44009_STATUS MAX44009_ReadLightHighResolution(float *Result);<\/pre>\n\n\n\n<p>Here\u2019s a little curiosity. The datasheet says: \u201c<em>If user wants to read both the Lux High-Byte register 0x03 and Lux Low-Byte register 0x04, then the master should not send a STOP command between the reads of the two registers. Instead a Repeated START command should be used.\u201d<\/em> What does this mean? The chip will increment the register address to be read on its own provided that after reading the first one, the master repeats a START sequence on the I\u00b2C bus. Unfortunately, when using the <em>HAL<\/em> function <em>HAL_I2C_Mem_Read<\/em> the microcontroller does not issue a START between consecutive bytes read. As a result, the sensor provides the value of register 0x03 twice instead of 0x04 in the second byte.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong.jpg\" alt=\"\" class=\"wp-image-553\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_wrong-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The simplest solution will be to simply call <em>HAL_I2C_Mem_Read<\/em> twice. Unfortunately, this costs a second addressing of the sensor and specifying the register from which to read.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct.jpg\" alt=\"\" class=\"wp-image-554\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_high_res_correct-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>If it turns out you need to shorten this time for some reason, a solution could be to use <em>HAL_I2C_Master_Sequential_Receive_IT<\/em>. Try to improve the readout with it \ud83d\ude42<\/p>\n\n\n\n<p>Finally, there are functions useful for interrupts.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MAX44009_STATUS MAX44009_ReadInterruptStatus(uint8_t *Status);\nMAX44009_STATUS MAX44009_WriteInterruptEnable(uint8_t Enable);\n\nMAX44009_STATUS MAX44009_SetUpperThreshold(float Threshold);\nMAX44009_STATUS MAX44009_SetLowerThreshold(float Threshold);\nMAX44009_STATUS MAX44009_SetThresholdTimer(uint8_t Timer);<\/pre>\n\n\n\n<p>The interrupt flag in the sensor is cleared automatically after reading the status register or disabling the interrupt. The boundary values that affect interrupt assertion are provided to and stored by the sensor in floating-point form with reduced resolution (4-bit exponent and 4-bit mantissa). <strong>Remember this limitation<\/strong>. The time requirement to assert the interrupt, passed in the argument, is in tens of milliseconds (value * 10 ms). So for a one-second setting, you should pass the value 100.<\/p>\n\n\n\n<p>A few more numbers and plots.<\/p>\n\n\n\n<p>100k low resolution:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_.jpg\" alt=\"\" class=\"wp-image-564\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_100k_-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>400k low resolution:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k.jpg\" alt=\"\" class=\"wp-image-561\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_lowres_400k-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>100k high resolution:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k.jpg\" alt=\"\" class=\"wp-image-563\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_100k-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"285\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k.jpg\" alt=\"\" class=\"wp-image-562\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k-300x89.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k-768x228.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k-36x11.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/12\/max44009_read_highres_400k-160x48.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>400k high resolution:<br><\/p>\n\n\n\n<figure class=\"wp-block-table tablepress tablepress-id-10\"><table class=\"has-fixed-layout\"><thead><tr><td><\/td><th>Low resolution<\/th><th>High resolution<\/th><\/tr><\/thead><tbody><tr><td>100 kHz<\/td><td>0.38 ms<\/td><td>0.78 ms<\/td><\/tr><tr><td>400 kHz<\/td><td>0.1 ms<\/td><td>0.2 ms<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>As you can see, the 400 kHz clock beats 100 kHz hands down. Even the high-resolution read at 400k is faster than the low-resolution read at 100k. Also remember that this readout isn\u2019t optimal yet and can be sped up further.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"685\" height=\"439\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal.jpg\" alt=\"\" class=\"wp-image-649\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal.jpg 685w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal-300x192.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal-24x15.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal-36x23.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold_terminal-125x80.jpg 125w\" sizes=\"auto, (max-width: 685px) 100vw, 685px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>I also tested interrupt thresholds. I set the threshold to 300 lux.&nbsp;<\/p>\n\n\n\n<p>The interrupt is active low.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"238\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold.jpg\" alt=\"\" class=\"wp-image-648\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold-300x74.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold-768x190.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold-24x6.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold-36x9.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/max44009_interrupt_upper_threshold-160x40.jpg 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Works as expected \ud83d\ude42<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TEMT6000<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/temt6000-czujnik-natezenia-swiatla\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=light_sensors&amp;utm_content=temt6000\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner.jpg\" alt=\"\" class=\"wp-image-1143\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/TEMT6000_baner-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The last light sensor discussed today is the TEMT6000 from Vishay. This time it is not a complete IC with a built-in ADC. This element is an NPN phototransistor. The current at its collector is proportional to the amount of incident light. The dependency is 1&nbsp;\u00b5A = 2 lux, which is easy to convert.<\/p>\n\n\n\n<p>We have to perform the sampling and calculations ourselves on the STM32. Fortunately, the MCU has a built-in 12-bit ADC, which makes things easier. The Chinese module has a resistor in series with the emitter so, according to Ohm\u2019s law, the voltage drop across it is proportional to the flowing current, which in turn is proportional to the amount of light falling on the photosensitive base. So it is enough to know the voltage drop across the resistor. A 10 k\u03a9 resistor has been soldered in, unfortunately with a 5% tolerance, which will affect the measurement results. It is definitely better to swallow that half a cent and solder in a 1% tolerance component.<\/p>\n\n\n\n<p>In such a setup, my calculations show that 1 lux = 5 mV on the resistor.<\/p>\n\n\n\n<p>The entire sensor configuration consists of configuring the ADC in the microcontroller. I connected the sensor to channel IN0 of ADC1. It can be configured in three ways in terms of how to read the conversion result.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Polling \u2014 manually request a conversion and wait for it to finish to read the value<\/li>\n\n\n\n<li>Interrupt mode \u2014 read from the ADC after the conversion is complete. Engages the CPU<\/li>\n\n\n\n<li>DMA \u2014 the whole procedure of requesting a conversion and reading from the ADC is automatic and does not engage the CPU<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"639\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration.jpg\" alt=\"\" class=\"wp-image-642\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration.jpg 500w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration-235x300.jpg 235w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration-19x24.jpg 19w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration-28x36.jpg 28w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/sensors_adc_configuration-63x80.jpg 63w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>What to choose? That\u2019s obvious \u2014 DMA \ud83d\ude42 I wouldn\u2019t bother with any other mode for such a simple element.<\/p>\n\n\n\n<p>Configuration in STM32CubeMX is simple. Set the prescaler as low as possible so the ADC will run faster, unless you are building a battery-powered device. Then power consumption matters. Leave the resolution at 12 bits. Enable continuous conversion mode. This way, the ADC will continuously request conversions on its own. You also need to enable DMA requests after the conversion is complete. This pokes the DMA to copy the measurement result to the selected memory location. Next, an important parameter is the Sampling Time. There is a dependency between sampling time and accuracy. As you might guess, shorter time means lower accuracy. I set the maximum time because I care about accuracy.<\/p>\n\n\n\n<p>There is still the DMA and interrupt setup. DMA should be configured for the selected ADC. Enable the <em>Circular<\/em> mode and check the option to increment the memory address \u2014 this will be needed for sample averaging.<\/p>\n\n\n\n<p>In the NVIC settings, make sure you have the interrupt from the <em>DMA Stream<\/em> enabled. If you have the ADC interrupt active \u2014 disable it. It will not be needed in this case.<\/p>\n\n\n\n<p>After these settings, the sensor basically runs on its own. All you have to do is start the conversion and convert the ADC value to lux.<\/p>\n\n\n\n<p>Only two functions are used for this<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">TEMT6000_STATUS TEMT6000_Init(ADC_HandleTypeDef *hadc);\nTEMT6000_STATUS TEMT6000_ReadLight(float *Result);<\/pre>\n\n\n\n<p>Initialization starts the DMA conversion on the given ADC. The readout converts the ADC value to the amount of light falling on the sensor. How to calculate this value?<\/p>\n\n\n\n<p>You need to know what the reference voltage for the ADC is. In the Nucleo board documentation I found that jumper SB57 is responsible for it. By default, it is closed, which means that VDD, i.e. 3.3 V, is applied to the Vref+ pin. The number of possible ADC results is 4096 for 12-bit resolution, so the result should be multiplied by the reference voltage value and divided by the maximum number of counts. The value I obtained this way is the number of volts across the resistor. However, it would be easier to convert in millivolts, so I multiply the result by 1000. Now, knowing that 1 lux = 5 mV, I divide that value by 5. After simplifying, the result looks as follows:<\/p>\n\n\n\n<p class=\"has-text-align-center\">Lux = ((AdcValue * 3.3) \/ 4096) * 200;<\/p>\n\n\n\n<p>I also implemented measurement averaging. The number of samples to average is defined by TEMT6000_ADC_SAMPLES in the header file. This reduces fluctuations on the ADC.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Comparison<\/h2>\n\n\n\n<p>Time to compare these three sensors. I placed them on a single small breadboard so that they would be close to each other. For illumination I used a lamp that provides even light and is placed at a considerable distance from the board. This way the light is distributed evenly to each sensor. STM32 Studio will work perfectly for plots here. The light measurement on my desk with standard room lighting looks as follows.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-1024x616.jpg\" alt=\"\" class=\"wp-image-644\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-1024x616.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-300x180.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-768x462.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-1536x924.jpg 1536w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-24x14.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-36x22.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on-133x80.jpg 133w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on.jpg 1596w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The <a class=\"thirstylink\" title=\"TEMT6000\" href=\"http:\/\/msalamon.pl\/recommends\/temt6000\/\">TEMT6000<\/a> phototransistor, after converting the value, indicates a much lower illumination level than the other sensors tested. Interestingly, the smartphone app shows about 575 lux, which is significantly higher than what all the sensors show. I covered all the sensors with my hand and, as expected, the readings dropped almost to zero and for each of the sensors, including the smartphone, the results are similar (about 10 lux).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-1024x616.jpg\" alt=\"\" class=\"wp-image-643\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-1024x616.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-300x180.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-768x462.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-1536x924.jpg 1536w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-24x14.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-36x22.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch-133x80.jpg 133w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_off_switch.jpg 1596w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-1024x616.jpg\" alt=\"\" class=\"wp-image-645\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-1024x616.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-300x180.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-768x462.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-1536x924.jpg 1536w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-24x14.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-36x22.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch-133x80.jpg 133w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/lux_sensors_light_on_switch.jpg 1596w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>A surprise and a big disappointment comes with stronger illumination of all sensors.<\/p>\n\n\n\n<p>As you can see, each one shows what it wants\u2026 The smartphone sensor shot up to about 2500 lux. Which value is closest to the truth? I can\u2019t say without a professional, calibrated lux meter.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">EDIT: After a deeper analysis<\/h2>\n\n\n\n<p>Alright, I spent a little more time with these sensors and the debug mode in Eclipse. I noticed that the ADC value for a strongly illuminated TEMT6000 is close to the maximum. If so, almost the entire supply voltage is dropping across the resistor. In reality it was about 3 V, because some drops across the collector-emitter junction of the phototransistor. Let\u2019s calculate from Ohm\u2019s law what current flowed through the factory 10 k\u03a9 resistor.<\/p>\n\n\n\n<p class=\"has-text-align-center\"><em>I = 3 [V] \/ 10000 [\u03a9] = 0.0003 [A] = 300 [\u00b5A]<\/em><\/p>\n\n\n\n<p>This implies that the maximum value in lux that the TEMT6000 can show with the factory 10 k\u03a9 resistor is about 600 lux. I took a stronger lamp and indeed that\u2019s the case. The measurement stops a bit before 700 lux. What now?<\/p>\n\n\n\n<p>The resistor should be replaced. With what value? We basically have one constraint \u2014 the maximum collector current, which can be at most 20 mA, which equals about 40000 lux. Such a value is far too high for normal use. It will also reduce measurement resolution because the ADC can measure only 4096 levels. 10000 lux will be a better value. What resistor will be needed? 10000 lux is 5000&nbsp;\u00b5A and to drop 3 V on the resistor at that current, it must have a value of:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><em>R = 3 [V] \/ 0.005 [A] =&nbsp; 600 [\u03a9]<\/em><\/p>\n\n\n\n<p>I don\u2019t have such an SMD resistor on hand, but I do have 1 k\u03a9, which allows up to 6000 lux. And indeed the measurement works better, but the sensor still shows a much lower value than the other two \u2014 the digital ones. I wondered what else could influence this.<\/p>\n\n\n\n<p>I checked the spectral response of these sensors. I took the graphs from each datasheet and put them on one chart. I also added the curve corresponding to how the human eye perceives light.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"300\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-300x300.jpg\" alt=\"\" class=\"wp-image-688\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-300x300.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-150x150.jpg 150w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-768x768.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-24x24.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-36x36.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie-80x80.jpg 80w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/01\/Zlozenie.jpg 1000w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Unfortunately, measuring light is subjective. The rule in this type of measurement is that the sensor should have a response as close as possible to the human eye. As you can see, all my sensors today deviate somewhat from the \u2018norm\u2019. The TEMT6000 in general picks up a lot of light from the infrared range. I even checked the reaction of all three with a TV remote, and only the TEMT6000 reacted to the IR diode.<\/p>\n\n\n\n<p>Unfortunately, I\u2019m not good at photoelectronics and I won\u2019t explain why the TEMT6000, despite being more sensitive over a wider range, gives much lower results. It would be great if someone could explain it in the comments. However, for accurate measurement of visible light I would cross out the TEMT6000. It may at most be suitable for dimming a display, and such an application is indeed listed in the datasheet.<\/p>\n\n\n\n<p>Digital sensors have built-in circuits that process the signal falling on the photodiodes\/phototransistors. There is probably some magic processing and compensation in them, hence the results are close to each other.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Light sensors that convert the amount of incident light into lux are very tempting devices. However, as direct comparisons have shown, although each responds to the amount of light as intended (the more light, the higher the indication), the absolute values vary. I would very much like to perform a comparison against a decent, certified lux meter. This would make it possible to determine which of the sensors tested today is worth buying. These sensors cost pennies, so I didn\u2019t expect miracles from them. I wouldn\u2019t use them to build a precise meter.<\/p>\n\n\n\n<p>However, I wouldn\u2019t completely write off each of them. As general-purpose sensors, when we want to check, for example, whether it is darker or brighter, they can work perfectly. It is not always necessary to know how many lux there are around. For example, the smartphone by default does not display the light intensity value anywhere. Its sensor only needs to determine whether it is bright or dark and, on that basis, set the backlight brightness. Such calibration can be performed for each sensor and as a result they can operate with roughly similar effect.<\/p>\n\n\n\n<p>The project with code for all sensors is on my GitHub: <a href=\"https:\/\/github.com\/lamik\/Light_Sensors_STM32\" target=\"_blank\" rel=\"noopener\">link<\/a><\/p>\n\n\n\n<p><span>If you noticed any mistake, disagree with something, would like to add something important or simply feel like discussing the topic, write a comment. Remember that the discussion should be polite and in accordance with the rules of the Polish language.<\/span><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4337&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;Measuring Light Intensity Using STM32&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Measuring light intensity is common in our everyday life. Probably everyone has an auto dimming\/brightening screen feature in their smartphone. It is based precisely on measuring the light intensity around the device. The measurement is performed continuously while the phone is unlocked. Today I will focus on how we can [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3108,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,176,174],"class_list":["post-4337","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-programming","tag-stm32"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4337","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4337"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4337\/revisions"}],"predecessor-version":[{"id":4448,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4337\/revisions\/4448"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3108"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4337"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4337"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}