Last Updated: 26/01/2024
#63 Arduino Uno, PCA685, LED's Gas Lights Effects
Components >> #63 Arduino Uno, PCA685, LED's Gas Lights Effects
#63 Arduino Uno, PCA685, LED's Gas Lights Effects
After creating a number of LED lighting efects using the PCA9685 board I was asked if I could come up with some code for a gas lamp.
I thought this ould be easy, and to a degrree the effect was easy to create. The issue is that unlike a fire flicker in a building, there could be multiple lights and I wanted to avoid the effect of all of them doing the same effects at the same time, in other words they would all flicker at exactly the same time. This with a large number of LED's would be very obvious and look wrong so each LED in the system needed to have it's own random effect.
There are some gas lamps that are alive and still running on gas in the UK. London has about 1500 including one powered off the sewers in Carting Lane, the pictures below are of a couple of gas lamps in Malvern, again still gas powered, you can see the mantles lit by the pilot lights. These are the ones that are thought to have inspired C.S Lewis for the lamp post in his book "The Lion, the Witch, and the wardrobe".
This code uses the PCA9685 servo board that can control 16 LED's, however as multiple boards can be used together (62 Maximum) it would be possible to have 992 LED's all on their unique flicker code. At 200mm spacings (50ft in 4mm scale) that would give enough to light 193 metres of road.... enough for most layouts.
The code is Non Blocking so could be run no the same Arduino as other lighting effects.
Pinout and wiring diagrams
The PCA9685 circuit is shown below.
Please note that the 5v IS NOT supplied by the Arduino. You will need a seperate supply due to the power draw being more than an Arduino can handle.
Also note the PCA9685 have both the VCC and V+ conected to 5V.
Only 3 wires should go to the Arduino, Gnd, A5 and A4 from the SDA/SCl of all boards connected.
Leds locations are set in the code and are for illustration purposes only.
If you are using multiple PCA9685 boards don't forget to solder accross the tabs top right in different positions on each board to change the I2C address.
Pins
A5 to PCA9685 SCL
A4 to PCA9685 SDA
Make sure you have 5v going to the PCA9685 board as well as the VCC and GND. One powers the circuitry, the other supply powers the servo.
Wiring:for a few common boards
SDA/SCL connections
Arduino UNO:
A4 (SDA), A5 (SCL)
:
Arduino Mega 2560:
20 (SDA), 21 (SCL)
:
ESP32: 21(SDA), 22 (SCL)
For other Arduino boards see:https://www.arduino.cc/en/reference/wire
Set ups for different boards
The DCC decoder circuit
Connection Test 1 ...IMPORTANT
Bad wiring is one of the biggest problems with Arduino projects so run this test to make sure your board is being found before doing anythine else.
Once you have connected your board up as shown above check that it can be found.
If you are using an Arduino board go to File>Examples>
Wire>I2c_scanner and upload the skecth to your board.
if all goes well your serial Monitor will display something like
Scanning...
I2C device found at address 0x40 !
done
NOTE: if you have multipl boards you will see other addresses depending on the tabs soldered across that set the boards I2C address.
Once your device has been found it's time to add the LED's
Connection Test 2 ...Board and Servo Test
First make sure you have the Adafruit PWM Servo Library installed.
Tools>Manage Libraries>
Type Adafruit PWM Servo Library in the serach bar.
If it is not installed install it.
Example 1: PCA9685GasLightsV1.ino
Click to Download code: PCA9685GasLightsV1.ino
This sketch controls 16 leds, ports 0-7 are running as street lights, ports 8-15 are running as house lights (dimmer)
/* 25/01/2024
*
* PCA9685GasLightsV1
*
Single PCA9685 board
*
*/
#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"
//pca9685 settings
Adafruit_PWMServoDriver ledBoard1 = Adafruit_PWMServoDriver(0x40);
unsigned long currentMillis;
const int streetnormalBrightness = 4000;// Maximum brightness is 4095
const int streetminBrightness = 1500;// minimum is 0 OFF Gas lights Reduce value to make more aggressive flicker
unsigned long streetgasTimerArray[16];
int streetgasChangeLength[16][2];//length //flickerState 0 = normalBrightness 1 = flicker
//street gas lamps flicker function
void streetGasLights() {
int q;
for(q=0;q < 8;q++){
if(currentMillis - streetgasTimerArray[q] >= streetgasChangeLength[q][0]){
streetgasTimerArray[q] = currentMillis;
if(streetgasChangeLength[q][1] < 1){//currently at max brightness
ledBoard1.setPWM(q, 0, random(streetminBrightness,streetnormalBrightness));
streetgasChangeLength[q][0] = random(100,500);//flicker will last 0.1 - 0.5 secs
streetgasChangeLength[q][1] = 1;
}else{
ledBoard1.setPWM(q, 0,random(streetnormalBrightness - 300,streetnormalBrightness));
streetgasChangeLength[q][0] = random(1000,5000);//1-5 secs before next flicker
streetgasChangeLength[q][1] = 0;
}
}
}
}
const int housenormalBrightness = 1000;// Maximum brightness is 4095
const int houseminBrightness = 300;// minimum is 0 OFF Gas lights Reduce value to make more aggressive flicker
unsigned long housegasTimerArray[16];
int housegasChangeLength[16][2];//length //flickerState 0 = normalBrightness 1 = flicker
//house gas lamps flicker function...dimmer than street version
void houseGasLights() {
int q;
for(q=8;q < 16;q++){
if(currentMillis - housegasTimerArray[q] >= housegasChangeLength[q][0]){
housegasTimerArray[q] = currentMillis;
if(housegasChangeLength[q][1] < 1){//currently at max brightness
ledBoard1.setPWM(q, 0, random(houseminBrightness,housenormalBrightness));
housegasChangeLength[q][0] = random(100,500);//flicker will last 0.1 - 0.5 secs
housegasChangeLength[q][1] = 1;
}else{
ledBoard1.setPWM(q, 0,random(housenormalBrightness - 300,housenormalBrightness));
housegasChangeLength[q][0] = random(1000,5000);//1-5 secs before next flicker
housegasChangeLength[q][1] = 0;
}
}
}
}
void setup() {
Serial.begin(115200);
Serial.println("PCA9685GasLightsV1");
//start led board
ledBoard1.begin();
ledBoard1.setPWMFreq(1600);
}
void loop() {
currentMillis = millis(); //get current time since board started in milliseconds
streetGasLights(); //calls the gas function
houseGasLights(); //calls the gas function
}
Example 2: PCA9685GasLightsV2.ino
Click to Download code: PCA9685GasLightsV2.ino
This sketch is controlling 8 PCA9685 boards controlling 128 leds to demonstrate how more boards would be used.
/* 25/01/2024
*
* PCA9685GasLightsV2
*
Multiple PCA9685 board...4 houselights, 4 street lights (128 leds)
*
*/
#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"
//pca9685 settings
Adafruit_PWMServoDriver streetLights1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver streetLights2 = Adafruit_PWMServoDriver(0x42);
Adafruit_PWMServoDriver streetLights3 = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver streetLights4 = Adafruit_PWMServoDriver(0x43);
Adafruit_PWMServoDriver houselights1 = Adafruit_PWMServoDriver(0x48);
Adafruit_PWMServoDriver houselights2 = Adafruit_PWMServoDriver(0x50);
Adafruit_PWMServoDriver houselights3 = Adafruit_PWMServoDriver(0x45);
Adafruit_PWMServoDriver houselights4 = Adafruit_PWMServoDriver(0x56);
unsigned long currentMillis;
const int streetnormalBrightness = 4000;// Maximum brightness is 4095
const int streetminBrightness = 1500;// minimum is 0 OFF Gas lights Reduce value to make more aggressive flicker
unsigned long streetgasTimerArray[16];
int streetgasChangeLength[16][2];//length //flickerState 0 = normalBrightness 1 = flicker
//street gas lamps flicker function
void streetGasLights() {
int q;
for(q=0;q < 16;q++){
if(currentMillis - streetgasTimerArray[q] >= streetgasChangeLength[q][0]){
streetgasTimerArray[q] = currentMillis;
if(streetgasChangeLength[q][1] < 1){//currently at max brightness
streetLights1.setPWM(q, 0, random(streetminBrightness,streetnormalBrightness));
streetLights2.setPWM(q, 0, random(streetminBrightness,streetnormalBrightness));
streetLights3.setPWM(q, 0, random(streetminBrightness,streetnormalBrightness));
streetLights4.setPWM(q, 0, random(streetminBrightness,streetnormalBrightness));
streetgasChangeLength[q][0] = random(100,500);//flicker will last 0.1 - 0.5 secs
streetgasChangeLength[q][1] = 1;
}else{
streetLights1.setPWM(q, 0,random(streetnormalBrightness - 300,streetnormalBrightness));
streetLights2.setPWM(q, 0,random(streetnormalBrightness - 300,streetnormalBrightness));
streetLights3.setPWM(q, 0,random(streetnormalBrightness - 300,streetnormalBrightness));
streetLights4.setPWM(q, 0,random(streetnormalBrightness - 300,streetnormalBrightness));
streetgasChangeLength[q][0] = random(1000,5000);//1-5 secs before next flicker
streetgasChangeLength[q][1] = 0;
}
}
}
}
const int housenormalBrightness = 1000;// Maximum brightness is 4095
const int houseminBrightness = 300;// minimum is 0 OFF Gas lights Reduce value to make more aggressive flicker
unsigned long housegasTimerArray[16];
int housegasChangeLength[16][2];//length //flickerState 0 = normalBrightness 1 = flicker
//house gas lamps flicker function...dimmer than street version
void houseGasLights() {
int q;
for(q=0;q < 16;q++){
if(currentMillis - housegasTimerArray[q] >= housegasChangeLength[q][0]){
housegasTimerArray[q] = currentMillis;
if(housegasChangeLength[q][1] < 1){//currently at max brightness
houselights1.setPWM(q, 0, random(houseminBrightness,housenormalBrightness));
houselights2.setPWM(q, 0, random(houseminBrightness,housenormalBrightness));
houselights3.setPWM(q, 0, random(houseminBrightness,housenormalBrightness));
houselights4.setPWM(q, 0, random(houseminBrightness,housenormalBrightness));
housegasChangeLength[q][0] = random(100,500);//flicker will last 0.1 - 0.5 secs
housegasChangeLength[q][1] = 1;
}else{
houselights1.setPWM(q, 0,random(housenormalBrightness - 300,housenormalBrightness));
houselights2.setPWM(q, 0,random(housenormalBrightness - 300,housenormalBrightness));
houselights3.setPWM(q, 0,random(housenormalBrightness - 300,housenormalBrightness));
houselights4.setPWM(q, 0,random(housenormalBrightness - 300,housenormalBrightness));
housegasChangeLength[q][0] = random(1000,5000);//1-5 secs before next flicker
housegasChangeLength[q][1] = 0;
}
}
}
}
void setup() {
Serial.begin(115200);
Serial.println("PCA9685GasLightsV2");
//start led boards
streetLights1.begin();
streetLights1.setPWMFreq(1600);
streetLights2.begin();
streetLights2.setPWMFreq(1600);
streetLights3.begin();
streetLights3.setPWMFreq(1600);
streetLights4.begin();
streetLights4.setPWMFreq(1600);
houselights1.begin();
houselights1.setPWMFreq(1600);
houselights2.begin();
houselights2.setPWMFreq(1600);
houselights3.begin();
houselights3.setPWMFreq(1600);
houselights4.begin();
houselights4.setPWMFreq(1600);
}
void loop() {
currentMillis = millis(); //get current time since board started in milliseconds
streetGasLights(); //calls the street lights function
houseGasLights(); //calls the house lights function
}
Additional Resource Links
Model Railway Light Effects using PCA685 and LED's with Arduino or ESP32
Multiple PCA9685 PWM Servo Boards with servos and LED's
Lesson 4: Using "for loop" to control code 21/07/2021
Comments
To ask a question please comment on YouTube or email the address in this image:
![](images/address.gif)