Embedded Practical Guide – Visual Night Light Control System

1. Introduction

1.1 Project Development Background

With the deep penetration of smart home technology and the rapid development of embedded microcontroller (MCU) technology, the application of large-scale integrated circuits in the consumer electronics field is becoming increasingly widespread. Home lighting devices are upgrading from “single lighting” to “smart adaptation and humanized services.” As a core lighting device in homes, offices, and study scenarios, desk lamps are used frequently, but traditional desk lamps have many pain points:

Energy Waste: Users often forget to turn off the desk lamp, leading to prolonged idle operation and unnecessary energy consumption;

Inconvenient Operation: In dark environments at night, users need to fumble for the switch, posing a risk of bumping into things;

Poor Light Adaptability: Fixed brightness and color temperature cannot meet the needs of different scenarios (such as reading, drawing, and screen backlighting), leading to visual fatigue over time, and even affecting color judgment in drawing due to color temperature deviation;

The visual night light control system based on the STM32F103RCT6 microcontroller has emerged to address these pain points by integrating four core technologies: human body sensing, light detection, PWM dimming, color temperature adjustment, and alarm control. The system supports multiple mode switching, timed alarms, and automatic sensing start-stop, adapting to scenarios such as reading, drawing, and screen backlighting, providing users with an energy-saving, comfortable, and convenient lighting experience, suitable for home studies, student dormitories, offices, etc., with high practical value and market promotion potential.

Embedded Practical Guide - Visual Night Light Control System

1.2 Functional Design Implementation

This system focuses on the core goals of “intelligent sensing, on-demand dimming, scene adaptation, and controllable timing,” achieving the following functions:

Timed Alarm Function: Users can set the alarm time according to their needs, and the desk lamp can automatically turn on or off when the alarm time is reached.

Human Body Sensing Automatic Start-Stop: The PIR module detects human activity within the range of the desk lamp; when human activity is detected and the ambient light is insufficient, the desk lamp automatically turns on;

Light Sensing Intelligent Adjustment: The system collects ambient light intensity in real-time through a light-sensitive resistor sensor, dynamically adjusting the desk lamp output based on light intensity: increasing brightness when light is weak and decreasing brightness when light is strong.

Intelligent Light Source Mode: Automatically reads ambient light and human activity status to adjust the brightness of the light.

Drawing Mode: Presents a cooler color temperature based on ambient light to reduce color distortion on drawing paper, making drawing more professional.

Reading Mode: Presents a medium color temperature based on ambient light to protect eyesight, preventing fatigue during long reading sessions.

Supplementary Light Mode: Presents a warmer color temperature based on ambient light to neutralize screen blue light, reducing eye strain from screen use.

1.3 Project Hardware Module Composition

(1) Main Control Chip: STM32F103RCT6

Based on the ARM Cortex-M3 architecture, with a main frequency of 72MHz, it has peripherals such as ADC, timers (TIM2/TIM3), GPIO, EEPROM, etc.; responsible for coordinating sensor data collection, RGB light control, alarm management, mode switching, and LCD display, ensuring real-time system response.

(2) Human Body Sensing Module

The SR602 is based on the principle of passive infrared detection, with a detection range of 5 meters and adjustable sensitivity; it outputs high and low level signals (human detected → high level, no human detected → low level), providing trigger conditions for the automatic start-stop of the desk lamp.

(3) Light Sensing Module

Light-sensitive resistor sensor, whose resistance decreases with increasing light intensity; the resistance change is converted into a 0-3.3V voltage signal through a voltage divider circuit, collected by the STM32’s ADC to determine ambient light.

(4) Lighting Module

RGB light + light beads, the RGB light is responsible for brightness and color temperature adjustment, while the auxiliary light beads are used for environmental supplementary light in intelligent light source mode, with low power consumption.

(5) Display Module

1.8-inch TFT-LCD screen, displaying in real-time: current working mode, personnel status, light conditions, etc.

1.4 Design Concept

This system is built around the core of “scene-based needs, supported by multi-technology collaboration,” constructing a closed-loop control architecture of “perception – decision – execution – feedback,” with the following specific design concepts:

(1) Core Goal Decomposition

Energy Efficiency: Avoid idle operation through human body sensing + timed control;

Comfort: Multi-mode adaptation to different scenarios, with light brightness and color temperature conforming to ergonomic standards;

Convenience: Automatic sensing reduces manual operation, and the timing function aligns with rest periods;

Visualization: The LCD screen provides real-time feedback on status, and button operations are intuitive.

(2) Key Function Design

This project uses the STM32F103RCT6 as the main control unit, leveraging its rich peripheral resources to meet the demands of multi-sensor data processing and PWM dimming; the SR602 module is used for human activity detection, and the light-sensitive resistor collects light intensity, both working together to provide trigger conditions for automatic mode; the light beads, combined with PWM control, achieve a wide range of brightness adjustment, while RGB is responsible for adjusting the color temperature of the light source, and the TFT-LCD screen with independent buttons forms an intuitive human-machine interaction interface.

Embedded Practical Guide - Visual Night Light Control System

1.5 Development Environment Introduction

Programming Language: C language, with high execution efficiency after compilation, meeting the STM32’s requirements for real-time sensor data collection, precise PWM signal output, and alarm timing, while supporting embedded hardware driver development.

Development Tools: Keil uVision5 (MDK-ARM), with excellent compatibility with STM32F103RCT6 (Cortex-M3 core), supporting syntax highlighting, auto-completion (such as STM32 standard library functions), and generating Hex files; supports J-Link debugging, allowing real-time variable monitoring (such as light values, alarm time);Library Support: Compatible with STM32F1 standard peripheral library, simplifying initialization code for ADC, timers, GPIO, etc.;

2. Hardware Selection and Connection Diagram

2.1 SR602 Human Body Sensing Module

Working Principle: Built-in passive infrared sensor, with a detection range of 5 meters, capable of detecting infrared radiation of about 10μm emitted by the human body; when a person moves, the infrared rays are focused on the sensor through a Fresnel lens, and the internal signal processing circuit amplifies the weak signal before outputting high and low levels.

Embedded Practical Guide - Visual Night Light Control System

Embedded Practical Guide - Visual Night Light Control System

2.2 Light-sensitive Resistor Sensor

Working Principle: Made of cadmium sulfide material, the greater the light intensity, the higher the carrier concentration, and the lower the resistance; the module converts the resistance change into a voltage signal through a voltage divider circuit. Circuit connection

Embedded Practical Guide - Visual Night Light Control System

Embedded Practical Guide - Visual Night Light Control System

2.3 RGB Light Module

The RGB light module can emit red, green, and blue light, controlled by STM32 GPIO push-pull output, compatible with 3.3V power supply, meeting basic lighting needs.

Embedded Practical Guide - Visual Night Light Control System

Embedded Practical Guide - Visual Night Light Control System

2.4 Light Beads

The light beads use PWM dimming, adjusting the brightness through the PWM signal output from the STM32’s timer. The PWM duty cycle ranges from 10% to 100%, with a larger duty cycle resulting in higher brightness.

Embedded Practical Guide - Visual Night Light Control System

Embedded Practical Guide - Visual Night Light Control System

3. STM32 Code Design

3.1 Related Module Driver Code

(1) SR602 Human Body Sensing Module Driver

#include "hr.h"
void HR_Init(void){              // Enable clock
              RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
              GPIO_InitTypeDef       sound_gpio = {0};                     // PC7 input--AO
              sound_gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
              sound_gpio.GPIO_Pin  = GPIO_Pin_7;
              GPIO_Init(GPIOC,&sound_gpio);}
int Hr_Value(void){  int HRvalue = 0;       if(HR_DATA() == 1)       {
              HRvalue = 1;
       }
       else       {
              HRvalue = 0;
       }
       return HRvalue;}

(2) Light-sensitive Resistor Sensor Driver

#include "light.h"
int light = 0;
void Light_Config(void){       //1. GPIO initialization
       GPIO_InitTypeDef GPIO_InitStruct = {0};
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
       GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
       GPIO_Init(GPIOA,&GPIO_InitStruct);
       //2. Configure ADC clock --> 6 prescaler  12MHZ
       RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,ENABLE);
       //3. ADC configuration
       ADC_InitTypeDef ADC_InitStructure = {0};
       // ADC mode  independent mode
       ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
       // Scan mode  ENABLE    Single mode  DISABLE  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
       // Continuous mode  ENABLE   Single mode  DISABLE  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
       // Software trigger  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
       // Right alignment  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
       // Number of channels   1  ADC_InitStructure.ADC_NbrOfChannel = 1;
       // ADC initialization  ADC_Init(ADC2, &ADC_InitStructure);
       // Regular channel configuration
       // Channel 11  Regular sequence 1  55.5 sampling cycles  ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5);
       //ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_28Cycles5);
       // Enable ADC  ADC_Cmd(ADC2, ENABLE);
       // Initialize calibration register   ADC_ResetCalibration(ADC2);
       // Wait for calibration register initialization to complete  while(ADC_GetResetCalibrationStatus(ADC2));   // Start calibration  ADC_StartCalibration(ADC2);
       // Wait for calibration to complete  while(ADC_GetCalibrationStatus(ADC2));}
int Get_Adc(void)   {
                                       ADC_SoftwareStartConvCmd(ADC2, ENABLE); // Enable specified ADC1 software conversion start function
              while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC )); // Wait for conversion to complete
       return ADC_GetConversionValue(ADC2);// Return the result of the last ADC1 regular group conversion}
float Get_Adc_Average(int count){
       int sum_val=0;
       int lu = 0;
       char t;
       float lightv = 0;
       float value = 0;
       for(t=0;t <count;t++)                                 </count;t++)// Loop to read times
       {
              sum_val+=Get_Adc();
       // Calculate total value
              Delay_ms(5);                 // Delay
       }
       lightv = (sum_val/count)*3.3/4096;
       value = (lightv * 1000)/(3.3-lightv);// Resistance value
       lu = sum_val/count;
       if(lu > 4095)       {
              lu = 4095;
       }
       return 4095-lu;        // Return average value
       //return value;}

(3) RGB Light Driver

#include "rgb.h"
#include "delay.h" // RGB initialization function, pins
       R--PC3,G--PC4,B--PC5
void RGB_Config(void){
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);// Enable clock
       GPIO_InitTypeDef  gpioc_init ={0};
       // Define IO structure
       gpioc_init.GPIO_Mode        =GPIO_Mode_Out_PP;
       // Push-pull output
       gpioc_init.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;// Configure pins 0,1,2
       gpioc_init.GPIO_Speed       =GPIO_Speed_50MHz;// Speed 50MHZ
       GPIO_Init(GPIOC,&gpioc_init);
       Red(0);
       Blue(0);
       Green(0);}

(4) Light Bead Driver

void HW269_Config(void){
       GPIO_InitTypeDef GPIO_InitStructure = {0};
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
              GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
       GPIO_Init(GPIOB,&GPIO_InitStructure);
        TIM_TimeBaseInitTypeDef TIM_BaseInitStructure = {0};
       TIM_OCInitTypeDef TIM_OCInitStructure = {0};
              RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
              TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
              // Prescaler: determines the parameter for the digital filter sampling frequency, used when input capture function is involved
       TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
       // Count up
       TIM_BaseInitStructure.TIM_Period = 999;
       // Reload value
       TIM_BaseInitStructure.TIM_Prescaler = 71;
       // Internal auto increment of the prescaler
       TIM_TimeBaseInit(TIM3, &TIM_BaseInitStructure);
       TIM_ARRPreloadConfig(TIM3, ENABLE);// ARR preload enable
               // Output compare configuration
       TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
       // PWM1
       TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// Active high
       TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// Output to corresponding pin
       TIM_OCInitStructure.TIM_Pulse = 0;                            // Compare value
       TIM_OC3Init(TIM3, &TIM_OCInitStructure);
       TIM_OC3PreloadConfig(TIM3, ENABLE);// CCR preload enable
        TIM_Cmd(TIM3, ENABLE);       // Enable timer
       HW269_OFF;       }

3.2 Main Function Framework Code

int main(){
       JTAG_SWD_Config();// Disable JTAG function, enable SWD function
       SysTick_Config(72000);// Timer initialization
       NVIC_SetPriorityGrouping(5);// Interrupt priority grouping
        USART1_Config(115200);// Serial port initialization
       RTC_Config();
       KEY_Config();
       GPIO_Config();// GPIO initialization function
       Beep_Config();// Buzzer initialization function
       HR_Init();
       RGB_Config();
       Light_Config();
       HW269_Config();
              LCD_Init();// LCD screen initialization function
       LCD_Fill(0,0,128,160,WHITE);
       LCD_ShowPicture(0,0,128,160,gImage_tu);
       LCD_ShowChinese(0,50,(u8 *)"Desk Lamp Brightness Adjustment System",BLACK,WHITE,16,0);
       LCD_ShowChinese(0,70,(u8 *)"Personnel Status",BLACK,WHITE,16,0);
       LCD_ShowChinese(0,90,(u8 *)"Light Condition",BLACK,WHITE,16,0);
       LCD_ShowChinese(0,110,(u8 *)"Mode",BLACK,WHITE,16,0);
       WIFI_Init();
       Delay_ms(1000);
       Connect_And_Send_Data();// Connect to cloud server
       Delay_ms(1000);
       BAFA_Subscribe(TOPIC);// Subscribe
       Delay_ms(1000);
       while(1)       {
                     if(rtc_runtime>1000)              {
                     sec_time = RTC_GetCounter();
                     now_time = *localtime(&sec_time);// localtime function converts the returned seconds into the current time;
                     sprintf((char *)buf,"%d/%02d/%02d %02d:%02d:%02d",now_time.tm_year+1900,now_time.tm_mon+1,now_time.tm_mday,now_time.tm_hour,now_time.tm_min,now_time.tm_sec);
                     LCD_ShowString(0,140,(const u8*)buf,BLACK,WHITE,12,0);
                     rtc_runtime = 0;
              }                            if(sr602_runtime > 100)              {
                     value = Hr_Value();
                     if(value == 1)                     {
                            LCD_ShowChinese(70,70,(u8 *)"Human Detected",BLACK,WHITE,16,0);
                            HW365(800);
                            LED1(1);
                     }                     else                     {
                            LCD_ShowChinese(70,70,(u8 *)"No Human",BLACK,WHITE,16,0);
                            LED1(0);
                            HW365(0);
                     }                            sr602_runtime = 0;
              }              if(led_runtime > 100)              {
                     light = Get_Adc_Average(10);
                     printf("light:%d\r\n",light);
                     if(light>1500)                     {
                            LCD_ShowChinese(70,90,(u8 *)"Light Detected",BLACK,WHITE,16,0);
                     }                     else if(light<1500)                     {
                            LCD_ShowChinese(70,90,(u8 *)"No Light",BLACK,WHITE,16,0);
                     }                     led_runtime = 0;
              }              if(key_runtime > 20)              {
                     key_value = KEY_Scan();
                     if(key_value == 1)// Short press key 1                     {
                            mode++;
                            if(mode == 4)                            {
                                   mode = 1;
                            }
                            HW365(0);
                     }                     if(key_value == 3)// Long press key 1                     {
                            alarm += 30;
                            if(alarm>300)                            {
                                   alarm = 60;
                            }
                     }                     if(key_value == 2)// Short press key 2                     {
                                   switch(count)                                   {
                                          case 0:LCD_ShowChinese(60,110,(u8 *)"Sleep Mode",BLACK,WHITE,16,0);Red(0);Green(0);Blue(0);break;
                                          case 1:LCD_ShowChinese(60,110,(u8 *)"Drawing Mode",BLACK,WHITE,16,0);Red(0);Green(0);Blue(1);break;
                                          case 2:LCD_ShowChinese(60,110,(u8 *)"Reading Mode",BLACK,WHITE,16,0);Red(0);Green(1);Blue(0);break;
                                          case 3:LCD_ShowChinese(60,110,(u8 *)"Supplementary Light Mode",BLACK,WHITE,16,0);Red(1);Green(0);Blue(0);break;
                                   }
                                   count++;
                                   count %= 4;
                     }                     if(key_value == 4)// Long press key 2                     {
                            alarm -= 30;
                            if(alarm<0)                            {
                                   alarm = 60;
                            }
                     }                     key_runtime = 0;
              }              if(mode == 1)              {
                     LCD_ShowChinese(60,110,(u8 *)"Alarm Mode",BLACK,WHITE,16,0);
                     if(sec_time > 1761622763 + alarm)// Timed to light up in 1 minute                     {
                            HW365(800);
                     }
              }              if(mode == 2)              {
                     LCD_ShowChinese(60,110,(u8 *)"Smart Mode",BLACK,WHITE,16,0);
                     if(light < 1500)                     {
                            HW365(800);
                     }                     else if(light >= 1500 && light <3000)                     {
                            HW365(500);
                     }                     else if(light >= 3000)                     {
                            HW365(0);
                     }                     else                     {
                            HW365(0);
                     }
              }              // BAFA cloud publish data              if(Bafa_runtime>2000)              {
                     printf("aaaaaaa%d\r\n",light);
                     BAFA_publish(TOPIC,light);
                     Bafa_runtime=0;
              }
       }

Running Result Image:

Embedded Practical Guide - Visual Night Light Control System

BAFA Cloud Data:

Embedded Practical Guide - Visual Night Light Control System

WeChat Mini Program Data:

Embedded Practical Guide - Visual Night Light Control System

3.3 Core Code Explanation

System Initialization: Sequentially initializes each hardware module, ensuring that peripherals (ADC, timers, GPIO) are in a ready state; after LCD initialization, it displays the system title and initial interface, enhancing user interaction experience.

Button Interaction Logic: Non-blocking reading of buttons through functions enables mode cycling, brightness adjustment, and alarm setting; mode switching automatically synchronizes the corresponding color temperature.

Sensing and Dimming Collaboration: Collects human status and light values every 100ms; when someone is present, it dynamically adjusts brightness based on the mode, and turns off the light when no one is present, balancing energy saving and convenience.

Status Display: The LCD screen updates the mode and personnel status in real-time, allowing users to intuitively grasp the system status and reduce operational blind spots.

4. Conclusion

This system, based on the STM32F103RCT6 microcontroller, successfully constructs an integrated platform for “sensing – control – timing – interaction” for automatic desk lamp brightness adjustment. The core value is reflected in three aspects, addressing pain points: avoiding fumbling in the dark to turn on the light through human sensing, reducing energy waste through timed control, and effectively solving the inconvenience and energy waste issues of traditional desk lamps by adapting to different lighting needs in various scenarios; technology integration: integrating dimming and color temperature adjustment, ADC light collection, and passive infrared human sensing technologies to achieve multi-dimensional collaborative control.

User Experience: The 1.8-inch LCD screen provides intuitive status feedback, and buttons meet the needs for mode switching and parameter setting, with an overall design that balances practicality and usability.

This system has a simple structure, high stability, and can be widely applied in homes, student dormitories, offices, etc., providing a low-cost, high-cost performance solution for the smart home lighting field.

Embedded Practical Guide - Visual Night Light Control SystemEmbedded Practical Guide - Visual Night Light Control System

Leave a Comment