An elegant automatic stair lighting (part 2)

Welcome to the second part of our series "elegant stair light control". As always in the project series, the following parts are about improving or extending the function. In today's part, we are improving the function first.

Basically, our stairs go slowly from the bottom to the top, if you enter it from top to bottom or vice versa, from bottom to top. However, it would be nicer if our stairs turned on exactly in the direction as a running light, in which we enter the stairs and then slowly switch off again.

This is precisely what this enlargement is to be about in today's part of the series. The stair light follows our steps as soon as we enter the stairs, regardless of direction.

The parameters and the circuit can be from the first part of the series be taken over. It is a pure software extension.

 

#define Num_Stages 15
#define Delay_Stages 10
#define Delay_ON_to_OFF 5

 

Num_Stages

Defines the number of stairs to be illuminated (maximum 16, counting from 0 to start. Maximum value: 15)

Delay_Stages

Fade period for each stair step -> the smaller the value the greater the period, the slower.

Delay_ON_to_OFF

Period that passes by leaving the stairs in the "on" state.

 

After the values have been customized to your own preferences, the extended code can be uploaded to the Arduino:

 

 

2019 Tobias Kuch GPL 3.0
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
selects a read operation while a logical 0 selects a write operation.
#define OE_Pin  8           Pin for Output Enable
#define CPU_LED_Pin 13
#define PIRA_Pin 2
#define PIRB_Pin 3

#define Num_Stages  15
#define Delay_Stages  5
#define Delay_ON_to_OFF  30  Minimum Delay_ON_to_OFF in Seconds
#define delay_per_Stage_in_ms 200

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;

interrupt Control
Byte A60telSeconds24 = 0;
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 triggered   } else   {     digitalWrite(CPU_LED_Pin, Low);   }
}

Void Init_PWM_Module(Byte PWM_ModuleAddr)
{   pinMode(OE_Pin, Output);   pinMode(CPU_LED_Pin, Output);   digitalWrite(OE_Pin, High); Active LOW Output Activation Pin (OE).   Wire.beginTransmission(PWM_ModuleAddr); Initiate data transfer   Wire.Write(0x00);                       //   Wire.Write(0x06);                       Software Reset   Wire.endTransmission();                 Stop Communication - Send Stop Bit   Delay(400);   Wire.beginTransmission(PWM_ModuleAddr); Initiate data transfer   Wire.Write(0x01);                       Select Mode 2 Register (Command Register)   Wire.Write(0x04);                       Configure Chip: 0x04: dead pole output 0x00: Open drain output.   Wire.endTransmission();                 Stop Communication - Send Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); Initiate data transfer   Wire.Write(0x00);                      Select Mode 1 Register (Command Register)   Wire.Write(0x10);                      Configure SleepMode   Wire.endTransmission();                Stop Communication - Send Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); Initiate data transfer   Wire.Write(0xFE);                       Select PRE_SCALE register   Wire.Write(0x03);                       Set Prescaler. The maximum PWM frequency is 1526 Hz if the PRE_SCALEer the operator is set to "0x03h". Standard: 200 Hz   Wire.endTransmission();                 Stop Communication - Send Stop Bit   Wire.beginTransmission(PWM_ModuleAddr); Initiate data transfer   Wire.Write(0x00);                       Select Mode 1 Register (Command Register)   Wire.Write(0xA1);                       Configure Chip: ERrlaube All Call I2C addresses, use internal clock, / Allow Auto Increment Feature   Wire.endTransmission();                 Stop Communication - Send Stop Bit
}


Void Init_PWM_Outputs(Byte PWM_ModuleAddr)
{   digitalWrite(OE_Pin, High); Active LOW Output Activation Pin (OE).   for ( Int Z = 0; Z < 16 + 1; Z++)   {     Wire.beginTransmission(PWM_ModuleAddr);     Wire.Write(Z * 4 + 6);      Select PWM_Channel_ON_L register     Wire.Write(0x00);                     Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.Write(Z * 4 + 7);      Select PWM_Channel_ON_H register     Wire.Write(0x00);                     Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.Write(Z * 4 + 8);   Select PWM_Channel_OFF_L register     Wire.Write(0x00);        Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_ModuleAddr);     Wire.Write(Z * 4 + 9);  Select PWM_Channel_OFF_H register     Wire.Write(0x00);             Value for above register     Wire.endTransmission();   }   digitalWrite(OE_Pin, Low); Active LOW Output Activation Pin (OE).
}

Void Setup()
{   Initalization   Serial.Begin(9600);   pinMode(PIRA_Pin, Input);   pinMode(PIRB_Pin, Input);   Serial.Begin(9600);   Wire.Begin(); Initalisia I2C Bus A4 (SDA), A5 (SCL)   Init_PWM_Module(PWM_Module_Base_Addr);   Init_PWM_Outputs(PWM_Module_Base_Addr);   noInterrupts();   attachInterrupt(0, ISR_PIR_A, Change);   attachInterrupt(1, ISR_PIR_B, Change);   TCCR1A = 0x00;   TCCR1B = 0x02;   TCNT1 = 0;      Initialize register with 0   OCR1A =  33353;      Pre-documents Output Compare Register   TIMSK1 |= (1 << OCIE1A);  Enable Timer Compare Interrupt   Interrupts();
}

Void Down_to_Up_ON()
{   Pwm_Channel = 0;   Pwm_Channel_Brightness = 0;   while (Pwm_Channel < Num_Stages + 1)   {     Wire.beginTransmission( PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 8);   Select PWM_Channel_0_OFF_L register     Wire.Write((Byte)Pwm_Channel_Brightness & 0xff);        Value for above register     Wire.endTransmission();     Wire.beginTransmission( PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 9);  Select PWM_Channel_0_OFF_H register     Wire.Write((Pwm_Channel_Brightness >> 8));             Value for above register     Wire.endTransmission();     If (Pwm_Channel_Brightness < 4095)     {       Pwm_Channel_Brightness = Pwm_Channel_Brightness + Delay_Stages;       If (Pwm_Channel_Brightness > 4095) {         Pwm_Channel_Brightness = 4095;       }     } else If ( Pwm_Channel < Num_Stages + 1)     {       Pwm_Channel_Brightness = 0;       Delay(delay_per_Stage_in_ms);       Pwm_Channel++;     }   }
}

Void Down_to_Up_OFF()
{   Pwm_Channel = 0;   Pwm_Channel_Brightness = 4095;   while (Pwm_Channel < Num_Stages + 1)   {     Wire.beginTransmission( PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 8);   Select PWM_Channel_0_OFF_L register     Wire.Write((Byte)Pwm_Channel_Brightness & 0xff);        Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 9);  Select PWM_Channel_0_OFF_H register     Wire.Write((Pwm_Channel_Brightness >> 8));             Value for above register     Wire.endTransmission();     If (Pwm_Channel_Brightness > 0)     {       Pwm_Channel_Brightness = Pwm_Channel_Brightness - Delay_Stages;       If (Pwm_Channel_Brightness < 0) {         Pwm_Channel_Brightness = 0;       }     } else If ( Pwm_Channel < Num_Stages + 1)     {       Pwm_Channel_Brightness = 4095;       Delay(delay_per_Stage_in_ms);       Pwm_Channel++;     }   }
}

Void Up_to_DOWN_ON()
{   Pwm_Channel = Num_Stages;   Pwm_Channel_Brightness = 0;   while (Pwm_Channel > -1)   {     Wire.beginTransmission( PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 8);   Select PWM_Channel_0_OFF_L register     Wire.Write((Byte)Pwm_Channel_Brightness & 0xff);        Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 9);  Select PWM_Channel_0_OFF_H register     Wire.Write((Pwm_Channel_Brightness >> 8));             Value for above register     Wire.endTransmission();     If (Pwm_Channel_Brightness < 4095)     {       Pwm_Channel_Brightness = Pwm_Channel_Brightness + Delay_Stages;       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;       }     }   }
}



Void Up_to_DOWN_OFF()
{   Pwm_Channel = Num_Stages;   Pwm_Channel_Brightness = 4095;   while (Pwm_Channel > -1)   {     Wire.beginTransmission(PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 8);   Select PWM_Channel_0_OFF_L register     Wire.Write((Byte)Pwm_Channel_Brightness & 0xff);        Value for above register     Wire.endTransmission();     Wire.beginTransmission(PWM_Module_Base_Addr);     Wire.Write(Pwm_Channel * 4 + 9);  Select PWM_Channel_0_OFF_H register     Wire.Write((Pwm_Channel_Brightness >> 8));             Value for above register     Wire.endTransmission();     If (Pwm_Channel_Brightness > 0)     {       Pwm_Channel_Brightness = Pwm_Channel_Brightness - Delay_Stages;       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;       }     }   }
}





Void Loop()
{   If ((Motion_Trigger_Down_to_Up) and !(On_Delay) )   {     Seconds24 = 0;     On_Delay = True;     Down_to_Up_ON();   }   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) )   {     Seconds24 = 0;     On_Delay = True;     Up_to_DOWN_ON();   }   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;   }
}

 

 

I wish you a lot of fun rebuilding this project and until the next part.

 

 

For arduinoProjekte für fortgeschritteneSensors

6 comments

Peter Wenk

Peter Wenk

Hallo Freunde im Blog,
ich habe mir die Treppenbeleuchtung auf dem Steckbrett nachgebaut und es funktioniert wunderbar.
Jetzt würde ich gern die helligkeit aller leds reduzieren. Es müsste doch über die PWM Taktung funktionieren also nicht mit 100% sondern nach wunsch nur 50% Taktung.
Kann mir einer helfen wie ich den Skretch umschreiben muss?
Würde mich über Hilfe freuen.
LG
Peter

Maik

Maik

@Thomas
Realisiere das doch mit einer separaten Steuerung, dann kannst Du dir den Flur nach deinen Wünschen ausleuchten.

Strotty

Strotty

Hallo,

ich bekomme bei ISR folgende Fehlermeldung:
exit status 1
expected unqualified-id before string constant
kann mir jemand einen Tipp geben?

Thomas

Thomas

Das Treppenlicht ist eine wirklich tolle Idee, mit der ich schon viele Jahre liebäugele. Aber wie es immer so ist, das, was man sucht, findet man dann doch in der Form nicht und sich zu kompletter Eigenentwicklung aufzuraffen bleibt bei mir meist auf der Strecke. Ich habe nun auch mit dem Kommentar bis zum 2. Teil gewartet, da mir im 1. Teil die Beschränkung auf die eine „Einschaltrichtung“ auffiel und die erwartungsgemäß nun ergänzt wurde. Jetzt würde ich gerne meine Idee anbringen, die mit dem Rettungsdienst-Kommentar von Wolfgang konform geht:
Unser Flur im 1. OG ist nachts erbärmlich dunkel und auf dem Weg durch den Flur auch ohne Treppenbenutzung wäre es super, wenn eben am oberen Ende der Treppe die Beleuchtung der obersten Stufe mit einem zusätzlichen (dritten) Sensor verbunden wäre, der eben nur die eine Stufe schaltet, wenn sich jemand oben im Flur bewegt. Damit hat man dann nachts ausreichend Orientierung im Flur und es ist als Funktion abgegrenzt von der Treppenbenutzung. Aber die Stufe sollte trotzdem wie in der beschriebenen Lösung integriert bleiben.
Ein Ausschalten am Ende des „Treppenganges“ wäre für mich nicht sinnvoll, da es wegen mehrerer Bewohner und Hund zwangsläufig zu Situation kommen wird, wo jemand dann im Dunklen auf der Treppe steht.

Markus

Markus

Was ist wenn ich mir auf der hälfte der Treppe einfällt ich muss noch mal runter ?

Wolfgang Hauf

Wolfgang Hauf

Hi,
du hast in der ersten Zeile die “#” vergessen !!

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