An elegant automatic stair lighting (Teil4)

Hello and welcome to the penultimate part of the “elegant automatic staircase lighting” series.

 

Today we are expanding our control system with a light-sensitive resistor, which should act as a brightness sensor. From a brightness value that can be set in the code with the parameter "DayLight_Brightness_Border", whereby a higher number symbolizes a higher brightness, the automatic staircase is deactivated from this value, so that the stairs are only illuminated when it is dark. By using an LDR instead of an I2C sensor, the whole thing is somewhat less sensitive to external interference.

As a further small improvement in this version, the fading time between two levels when switching on and off can be set separately with the parameters "Delay_Stages_ON" and "Delay_Stages_OFF". Respectable results can be achieved, for example, by selecting the parameter for switching off the individual steps higher than that for switching on.


The following picture shows how the LDR and the pre-resistor must be connected:

Circuit with photoresistor

 

For today's part of the project we need:

number

description

annotation

2

PIR module HC-SR501 PIR

Motion sensor

to 62

PCA9685 16 channel 12 bit PWM driver

Number depending on the number of stairs / 16

1

Nano V3

 

1

MB102 power supply adapter

For breadboard construction

to 992

IRF520 MOS Driver Module 0-24V 5A

Number depending on the number of stairs

1

Power supply for LED / lamps for the steps

24 volts maximum

1

10 KOhm resistance

 

1

LDR

Photo resistance

 

All references from the previous parts also apply in today's part.

After making your own adjustments and adding the LDR's, the code can be uploaded:

 

#include <Wire.H>

#define PWM_Module_Base_Addr 0x40 // 10000000b The last bit of the address byte defines the operation to be performed. When set to logical 1 0x41 module 2 etc. Address range 0x40 - 0x47 
// a read operation is selected, while a logical 0 selects a write operation.
#define OE_Pin  8                 // Pin for output enable 
#define CPU_LED_Pin 13            // Internal board LED at pin 13 (for debugging purposes)
#define PIRA_Pin 2
#define PIRB_Pin 3
#define Num_Stages_per_Module 16
#define LDR_Pin A2                // Analog pin, via which the brightness should be measured. (LDR resistance)
#define DEBUG
#define L_Sens_Scope 50

// Adaptable operating parameters (constants)

int Delay_ON_to_OFF = 10;          // Minimum waiting time until "From sequence" in seconds
int Overall_Stages =  8;         // maximum number of steps: 62 x 16 = 992
int delay_per_Stage_in_ms = 100;
int DayLight_Brightness_Border = 600; // Automatic brightness limit - higher value - higher brightness
byte Delay_Stages_ON = 20;
byte Delay_Stages_OFF = 20;


// Global variables
int Pwm_Channel = 0;
int Pwm_Channel_Brightness = 0;
bool Motion_Trigger_Down_to_Up = false;
bool Motion_Trigger_Up_to_Down = false;
bool On_Delay = false;
bool DayLight_Status = true;
bool DLightCntrl = true;
byte PWM modules = 0;
byte StagesLeft = 0;
// interrupt control
volatile byte A60telSeconds24 = 0;
volatile byte Seconds24;

ISR(TIMER1_COMPA_vect)
{   A60telSeconds24++;   if (A60telSeconds24 > 59)   {     A60telSeconds24 = 0;     Seconds24++;     if (Seconds24 > 150)     {       Seconds24 = 0;     }   }
}

void ISR_PIR_A()
{   bool PinState = digitalRead(PIRA_Pin);   if (PinState)   {     if (!(Motion_Trigger_Up_to_Down) and !(Motion_Trigger_Down_to_Up))     {       digitalWrite(CPU_LED_Pin, HIGH);       Motion_Trigger_Down_to_Up = true;     } // PIR A triggered   } else   {     digitalWrite(CPU_LED_Pin, LOW);   }
}

void ISR_PIR_B()
{   bool PinState = digitalRead(PIRB_Pin);   if (PinState)   {     if (!(Motion_Trigger_Down_to_Up) and !(Motion_Trigger_Up_to_Down))     {       digitalWrite(CPU_LED_Pin, HIGH);       Motion_Trigger_Up_to_Down = true;     } // PIR B ausgelöst   } else   {     digitalWrite(CPU_LED_Pin, LOW);   }
}

void Init_PWM_Module(byte PWM_ModuleAddr)
{   digitalWrite(OE_Pin, HIGH); // Active LOW-Ausgangsaktivierungs-Pin (OE).   Wire.beginTransmission(PWM_ModuleAddr); // Datentransfer initiieren   Wire.write(0x00);                       //   Wire.write(0x06);                       // Software Reset   Wire.endTransmission();                 // Stoppe Kommunikation - Sende Stop Bit   delay(400);   Wire.beginTransmission(PWM_ModuleAddr); // Datentransfer initiieren   Wire.write(0x01);                       // Wähle  Mode 2 Register (Command Register)   Wire.write(0x04);                       // Konfiguriere Chip: 0x04:  totem pole Ausgang 0x00: Open drain Ausgang.   Wire.endTransmission();                 // Stoppe Kommunikation - Sende Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); // Datentransfer initiieren   Wire.write(0x00);                      // Wähle Mode 1 Register (Command Register)   Wire.write(0x10);                      // Konfiguriere SleepMode   Wire.endTransmission();                // Stoppe Kommunikation - Sende Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); // Datentransfer initiieren   Wire.write(0xFE);                       // Wähle PRE_SCALE register (Command Register)   Wire.write(0x03);                       // Set Prescaler. Die maximale PWM Frequent ist 1526 Hz wenn das PRE_SCALEer Regsiter auf "0x03h" gesetzt wird. Standard : 200 Hz   Wire.endTransmission();                 // Stoppe Kommunikation - Sende Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); // Datentransfer initiieren   Wire.write(0x00);                       // Wähle Mode 1 Register (Command Register)   Wire.write(0xA1);                       // Konfiguriere Chip:  ERrlaube All Call I2C Adressen, verwende interne Uhr,                                           // Erlaube Auto Increment Feature   Wire.endTransmission();                 // Stoppe Kommunikation - Sende Stop Bit
}


void Init_PWM_Outputs(byte PWM_ModuleAddr)
{   digitalWrite(OE_Pin, HIGH); // Active LOW-Ausgangsaktivierungs-Pin (OE).   for ( int z = 0; z < 16 + 1; z++)   {     Wire.beginTransmission(PWM_ModuleAddr);     Wire.write(z * 4 + 6);      // Wähle PWM_Channel_ON_L register     Wire.write(0x00);                     // Wert für o.g. Register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.write(z * 4 + 7);      // Wähle PWM_Channel_ON_H register     Wire.write(0x00);                     // Wert für o.g. Register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.write(z * 4 + 8);   // Wähle PWM_Channel_OFF_L register     Wire.write(0x00);        // Wert für o.g. Register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.write(z * 4 + 9);  // Wähle PWM_Channel_OFF_H register     Wire.write(0x00);             // Wert für o.g. Register     Wire.endTransmission();   }   digitalWrite(OE_Pin, LOW); // Active LOW-Ausgangsaktivierungs-Pin (OE).
}

void setup()
{   //Initalisierung   Serial.begin(9600);   pinMode(PIRA_Pin, INPUT);   pinMode(PIRB_Pin, INPUT);   pinMode(OE_Pin, OUTPUT);   pinMode(CPU_LED_Pin, OUTPUT);   pinMode(LDR_Pin, INPUT);   PWMModules = Overall_Stages / 16;   StagesLeft = (Overall_Stages % 16) - 1;   if (StagesLeft >= 1) {     PWMModules++;   }   Wire.begin(); // Initalisiere I2C Bus A4 (SDA), A5 (SCL)   for (byte ModuleCount = 0; ModuleCount < PWMModules; ModuleCount++)   {     Init_PWM_Module(PWM_Module_Base_Addr + ModuleCount);     Init_PWM_Outputs(PWM_Module_Base_Addr + ModuleCount);   }   noInterrupts();   attachInterrupt(0, ISR_PIR_A, CHANGE);   attachInterrupt(1, ISR_PIR_B, CHANGE);   TCCR1A = 0x00;   TCCR1B = 0x02;   TCNT1 = 0;      // Register mit 0 initialisieren   OCR1A =  33353;      // Output Compare Register vorbelegen   TIMSK1 |= (1 << OCIE1A);  // Timer Compare Interrupt aktivieren   interrupts();   Serial.println(F("Init_Complete"));
}

bool DayLightStatus ()
{   int SensorValue = 0;   bool ReturnValue = true;   SensorValue = analogRead(LDR_Pin);
#ifdef DEBUG   Serial.print(F("DayLightStatus: "));   Serial.print(SensorValue);
#endif   if (SensorValue > DayLight_Brightness_Border)   {     if ((DayLight_Status) and (SensorValue > DayLight_Brightness_Border + L_Sens_Scope))     {       ReturnValue = false;       DayLight_Status = false;     } else if (!(DayLight_Status))     {       ReturnValue = false;       DayLight_Status = false;     }
#ifdef DEBUG     Serial.println(F(" OFF"));
#endif   } else   {     if ((DayLight_Status) and (SensorValue > DayLight_Brightness_Border - L_Sens_Scope))     {       ReturnValue = true;       DayLight_Status = true;     } else if (!(DayLight_Status))     {       ReturnValue = true;       DayLight_Status = true;     }
#ifdef DEBUG     Serial.println(F(" ON"));
#endif   }   return ReturnValue;
}

void Down_to_Up_ON()
{
#ifdef DEBUG   Serial.println(F("Down_to_Up_ON"));
#endif   byte Calc_Num_Stages_per_Module = Num_Stages_per_Module;   for (byte ModuleCount = 0; ModuleCount < PWMModules; ModuleCount++)   {     Pwm_Channel = 0;     Pwm_Channel_Brightness = 4095;     if ((StagesLeft >= 1) and (ModuleCount == PWMModules - 1))     {       Calc_Num_Stages_per_Module = StagesLeft;     }     else     {       Calc_Num_Stages_per_Module = Num_Stages_per_Module;     }     Pwm_Channel = 0;     Pwm_Channel_Brightness = 0;     while (Pwm_Channel < Calc_Num_Stages_per_Module + 1)     {       Wire.beginTransmission( PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 8);   // Wähle PWM_Channel_0_OFF_L register       Wire.write((byte)Pwm_Channel_Brightness & 0xFF);        // Wert für o.g. Register       Wire.endTransmission();       Wire.beginTransmission( PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 9);  // Wähle PWM_Channel_0_OFF_H register       Wire.write((Pwm_Channel_Brightness >> 8));             // Wert für o.g. Register       Wire.endTransmission();       if (Pwm_Channel_Brightness < 4095)       {         Pwm_Channel_Brightness = Pwm_Channel_Brightness + Delay_Stages_ON;         if (Pwm_Channel_Brightness > 4095) {           Pwm_Channel_Brightness = 4095;         }       } else if ( Pwm_Channel < Num_Stages_per_Module + 1)       {         Pwm_Channel_Brightness = 0;         delay(delay_per_Stage_in_ms);         Pwm_Channel++;       }     }   }
}

void Up_to_DOWN_ON()
{
#ifdef DEBUG   Serial.println(F("Up_to_DOWN_ON "));
#endif   byte Calc_Num_Stages_per_Module = Num_Stages_per_Module;   int ModuleCount = PWMModules - 1;   while (ModuleCount >= 0)   {     Pwm_Channel_Brightness = 0;     if ((StagesLeft >= 1) and (ModuleCount == PWMModules - 1))     {       Calc_Num_Stages_per_Module =  StagesLeft;     }     else     {       Calc_Num_Stages_per_Module = Num_Stages_per_Module;     }     Pwm_Channel = Calc_Num_Stages_per_Module;     while (Pwm_Channel > -1)     {       Wire.beginTransmission( PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 8);   // Wähle PWM_Channel_0_OFF_L register       Wire.write((byte)Pwm_Channel_Brightness & 0xFF);        // Wert für o.g. Register       Wire.endTransmission();       Wire.beginTransmission(PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 9);  // Wähle PWM_Channel_0_OFF_H register       Wire.write((Pwm_Channel_Brightness >> 8));             // Wert für o.g. Register       Wire.endTransmission();       if (Pwm_Channel_Brightness < 4095)       {         Pwm_Channel_Brightness = Pwm_Channel_Brightness + Delay_Stages_ON;         if (Pwm_Channel_Brightness > 4095) {           Pwm_Channel_Brightness = 4095;         }       } else if ( Pwm_Channel >= 0)       {         Pwm_Channel_Brightness = 0;         delay(delay_per_Stage_in_ms);         Pwm_Channel--;         if ( Pwm_Channel < 0)         {           Pwm_Channel = 0;           break;         }       }     }     ModuleCount = ModuleCount - 1;   }
}


void Down_to_Up_OFF()
{
#ifdef DEBUG   Serial.println(F("Down_to_Up_OFF"));
#endif   byte Calc_Num_Stages_per_Module = Num_Stages_per_Module;   for (byte ModuleCount = 0; ModuleCount < PWMModules; ModuleCount++)   {     Pwm_Channel = 0;     Pwm_Channel_Brightness = 4095;     if ((StagesLeft >= 1) and (ModuleCount == PWMModules - 1))     {       Calc_Num_Stages_per_Module = StagesLeft;     }     else     {       Calc_Num_Stages_per_Module = Num_Stages_per_Module;     }     while (Pwm_Channel < Calc_Num_Stages_per_Module + 1)     {       Wire.beginTransmission( PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 8);   // Wähle PWM_Channel_0_OFF_L register       Wire.write((byte)Pwm_Channel_Brightness & 0xFF);        // Wert für o.g. Register       Wire.endTransmission();       Wire.beginTransmission(PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 9);  // Wähle PWM_Channel_0_OFF_H register       Wire.write((Pwm_Channel_Brightness >> 8));             // Wert für o.g. Register       Wire.endTransmission();       if (Pwm_Channel_Brightness > 0)       {         Pwm_Channel_Brightness = Pwm_Channel_Brightness - Delay_Stages_OFF;         if (Pwm_Channel_Brightness < 0) {           Pwm_Channel_Brightness = 0;         }       } else if ( Pwm_Channel < Num_Stages_per_Module + 1)       {         Pwm_Channel_Brightness = 4095;         delay(delay_per_Stage_in_ms);         Pwm_Channel++;       }     }   }
}


void Up_to_DOWN_OFF()
{
#ifdef DEBUG   Serial.println(F("Up_to_DOWN_OFF"));
#endif   byte Calc_Num_Stages_per_Module = Num_Stages_per_Module;   int ModuleCount = PWMModules - 1;   while (ModuleCount >= 0)   {     Pwm_Channel_Brightness = 4095;     if ((StagesLeft >= 1) and (ModuleCount == PWMModules - 1))     {       Calc_Num_Stages_per_Module = StagesLeft;     }     else     {       Calc_Num_Stages_per_Module = Num_Stages_per_Module;     }     Pwm_Channel = Calc_Num_Stages_per_Module;     while (Pwm_Channel > -1)     {       Wire.beginTransmission(PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 8);   // Wähle PWM_Channel_0_OFF_L register       Wire.write((byte)Pwm_Channel_Brightness & 0xFF);        // Wert für o.g. Register       Wire.endTransmission();       Wire.beginTransmission(PWM_Module_Base_Addr + ModuleCount);       Wire.write(Pwm_Channel * 4 + 9);  // Wähle PWM_Channel_0_OFF_H register       Wire.write((Pwm_Channel_Brightness >> 8));             // Wert für o.g. Register       Wire.endTransmission();       if (Pwm_Channel_Brightness > 0)       {         Pwm_Channel_Brightness = Pwm_Channel_Brightness - Delay_Stages_OFF;         if (Pwm_Channel_Brightness < 0) {           Pwm_Channel_Brightness = 0;         }       } else if ( Pwm_Channel >= 0)       {         Pwm_Channel_Brightness =  4095;         delay(delay_per_Stage_in_ms);         Pwm_Channel--;         if ( Pwm_Channel < 0)         {           Pwm_Channel = 0;           break;         }       }     }     ModuleCount = ModuleCount - 1;   }
}

void Stages_Light_Control ()
{   if ((Motion_Trigger_Down_to_Up) and !(On_Delay))   {     DLightCntrl = DayLightStatus();     if (DLightCntrl)     {       Seconds24 = 0;       On_Delay = true;       Down_to_Up_ON();     } else {       Motion_Trigger_Down_to_Up = false;     }   }   if ((On_Delay) and (Seconds24 > Delay_ON_to_OFF) and (Motion_Trigger_Down_to_Up) )   {     Down_to_Up_OFF();     Motion_Trigger_Down_to_Up = false;     On_Delay = false;     Seconds24 = 0;   }   if ((Motion_Trigger_Up_to_Down) and !(On_Delay))   {     DLightCntrl = DayLightStatus();     if (DLightCntrl)     {       Seconds24 = 0;       On_Delay = true;       Up_to_DOWN_ON();     } else {       Motion_Trigger_Up_to_Down = false;     }   }   if ((On_Delay) and (Seconds24 > Delay_ON_to_OFF) and (Motion_Trigger_Up_to_Down))   {     Up_to_DOWN_OFF();     Motion_Trigger_Up_to_Down = false;     On_Delay = false;     Seconds24 = 0;   }
}

void loop()
{   Stages_Light_Control ();

}

 

Zur Fehlerdiagnose steht eine serielle Schnittstelle mit 9600 Baud zur Verfügung an der einige Informationen zum aktuellen Status ausgegeben werden:

Output on the serial monitor

Ich wünsche viel Spaß beim Nachbau und bis zum letzten Teil der Reihe.

Wie immer findet Ihr auch alle vorherigen Projekte unter der GitHub Seite https://github.com/kuchto

 

 

For arduinoProjects for advancedSensors

1 comment

Arnie

Arnie

Servus an alle Treppenbeleuchter,
wer den neuen Code so übernimmt:
- auf 8 Stufen eingestellt
- Ausschaltzeit beträgt 10 sec
- die Überblendungen sind sehr flott
- ich habe einen LDR von 3,9 kohm eingesetzt

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN