Modelspoor lichteffecten met Arduino en PCA9685

Modelspoor lichteffecten met Arduino en PCA9685
april 13, 2025 Geen reacties Creatief admin

Dit artikel is voor u vertaald en komt van de website Digital Town – Model Railway Light Effects using PCA685 and LED’s with Arduino or ESP32

Modelspoor lichteffecten met PCA9685 en LED’s met Arduino of ESP32

Ik gebruik al jaren LED’s op mijn modelspoorbaan, maar voor mijn nieuwste modelspoorbaan wilde ik verschillende effecten toevoegen en de helderheid van alle LED’s op de baan via mijn bedieningspaneel kunnen aanpassen. De reden voor een instelbare helderheid is dat de baan tentoongesteld zal worden en ik de lichtinstellingen eenvoudig wilde kunnen aanpassen aan de tentoonstelling locatie.

Op mijn nieuwe modelspoorbaan ben ik alle gebouwen zelf aan het bouwen, zodat ik LED’s op verschillende plaatsen kan plaatsen. Ik wil niet alleen verlichting binnen en buiten de gebouwen, maar ik wilde ook bepaalde effecten, zoals flikkerend vuur en booglassers. Bovendien wilde ik het hele project herbruikbaar maken zonder elke keer dat als ik iets toevoegde, tonnen code zou moeten herschrijven.

Veel lampen van welk type dan ook in een modelspoorbaan brengen kosten met zich mee: bedrading, en wel heel veel. Daarom wilde ik de bedrading tot een minimum beperken, dus besloot ik PCA9685-printplaten te gebruiken. Deze boards maken het mogelijk om 16 LED’s per board aan te sturen, maar hebben als voordeel dat ze doorgelust kunnen worden, waardoor er 62 boards per Arduino/ESP32 kunnen worden aangestuurd, wat neerkomt op 992 LED’s.

Omdat de PCA9685 de LED’s direct op het board kan aansluiten zonder weerstand, worden er minder componenten gebruikt en kan elk board met slechts 5 draden worden aangestuurd.

Enkele voorbeelden.

1) Vuurflikker
2) Standaardlamp
3) Booglasapparaat
4) Verkeerslichten voor een kruispunt.

De code wordt zo geschreven dat nieuwe LED’s en zelfs extra OCA9685-printplaten snel en eenvoudig kunnen worden toegevoegd.

De code werkt op Arduino of ESP32 en andere apparaten met kleine aanpassingen.

Voorbeeld 1: PCA9685LED_Effectsv1.ino, download: kies voor opslaan als bestand!

—Code—–

/* PCA9685LED_Effectsv1
06/05/2022

Schets om eenvoudige LED-effecten voor modelspoorbanen te produceren
De code gebruikt millis() in plaats van delay() voor timing, zodat geen enkel effect interfereert met andere effecten. Dit maakt het ook mogelijk om knoppen of andere ingangen te gebruiken om effecten in en uit te schakelen.

Kolenvuur
Standaardlamp
Booglasser
Verkeerslichten voor een kruispunt.

Schets getest op Arduino Uno en ESP32 Dev Module

Voor aansluitingen en pin-outs voor ESP32, Arduino UNO en Mega, zie
http://www.digitaltown.co.uk/components16-PCA9685LED.php

—Code begin—

*/
//Libraries required
#include “Wire.h”
#include “Adafruit_PWMServoDriver.h”

//stel board addres in, PCA9685 komen met adres 0x40 als standaard
Adafruit_PWMServoDriver station = Adafruit_PWMServoDriver(0x40, Wire);//station gebouw LED’s
//2nd board example at address 50
//Adafruit_PWMServoDriver gShed = Adafruit_PWMServoDriver(0x41, Wire);//goederenloods LED’s

unsigned long currentMillis;

//stel vuur leds in.
int stationfireFlickerLED = 0;//channel zero on station
int gShedfireFlickerLED = 4;//channel zero on goods shed
unsigned long fireFlickerTimer;
int fireFlickerTimerPeriod;

//kolenvuur flikkering functie
void fireFlicker() {
currentMillis = millis();
if (currentMillis – fireFlickerTimer > fireFlickerTimerPeriod) {
fireFlickerTimer = currentMillis;
fireFlickerTimerPeriod = random(500);
station.setPWM(stationfireFlickerLED, 0, random(4095));
//gShed.setPWM(gShedfireFlickerLED, 0, random(4095));// shows how LED on different PCA9685 would be added in
}
}

//controle alle vuur leds
int stationArcWeldLED = 2;//channel zero on station
int gShedArcWeldLED = 5;//channel zero on goods shed
unsigned long arcTimer;
int arcTimerPeriod;
int arcLEDState;
unsigned long arcBreakTimer;
int arcBreakTimerPeriod;
int arcBreakTimerState;
int arcBreakCounter;
int arcBreakCounterTarget;

//arc lasser effect
void arcWelder() {
currentMillis = millis();
if (currentMillis – arcTimer > arcTimerPeriod) {
arcTimer = currentMillis;
if (arcLEDState < 1) { if (arcBreakTimerState > 0) { //only allow the LED to light if not on a break… does not apply to turn off state;
station.setPWM(stationArcWeldLED, 0, 4095);//turn LED on full brightness
arcLEDState = 1;
arcTimerPeriod = random(40, 100);
}
} else {
//led must turn off on a break…otherwise it could get stuck in an ON position
station.setPWM(stationArcWeldLED, 0, 4096);//turn LED off
arcLEDState = 0;
arcTimerPeriod = random(20, 80);
}
}
//The following section controls the breaks between the arc flashing sessions
//2 types of break…pauses betwen welds and long…gone for tea break…looking at plans breaks
if (currentMillis – arcBreakTimer > arcBreakTimerPeriod) {
arcBreakTimer = currentMillis;
if (arcBreakTimerState < 1) {
arcBreakTimerState = 1;
} else {
arcBreakTimerState = 0;//stop arc welder
arcBreakCounter++;
if (arcBreakCounter < arcBreakCounterTarget) { //break during welding…between 1 and 6 seconds…pauses in welding arcBreakTimerPeriod = random(1000, 6000); } else { //long break…welder gone for cup of tea arcBreakCounter = 0; arcBreakCounterTarget = random(5, 25); //vary the amount of welding the man does arcBreakTimerPeriod = random(10000, 20000); //LONG BREAKS break between 10 and 20 seconds for testing } } } } //knipper LED’s int triggerCrossingLights = 0; //0 = lights off 1= lights flashing int crossingLeftLED = 3;//led for one half of the crossing int crossing2LeftLED = 12;//led for one half of the crossing int crossing3LeftLED = 14;//led for one half of the crossing int crossingRightLED = 4;//led for the other half int crossing2RightLED = 13;//led for the other half int crossing3RightLED = 15;//led for the other half int crossingTimerPeriod = 500;//set to 0.5 seconds int crossingState; unsigned long crossingTimer; void crossingLights() { currentMillis = millis(); //if (triggerCrossingLights > 0) { // if triggerCrossingLights is set to zero lights will stop
if (currentMillis – crossingTimer > crossingTimerPeriod) {
crossingTimer = currentMillis;
if (crossingState < 1) { crossingState = 1; //left hand lights //add more leds in here as required if (triggerCrossingLights > 0) { // if triggerCrossingLights is set to zero lights will stop
station.setPWM(crossingLeftLED, 0, 4095);//turn LED on
station.setPWM(crossing2LeftLED, 0, 4095);//turn LED on
station.setPWM(crossing3LeftLED, 0, 4095);//turn LED on
}
//right hand light
//add more leds in here as required
station.setPWM(crossingRightLED, 0, 4096);//turn LED off
station.setPWM(crossing2RightLED, 0, 4096);//turn LED off
station.setPWM(crossing3RightLED, 0, 4096);//turn LED off
} else {
//sets lights to opposite state
crossingState = 0;
//left hand lights
//add more leds in here as required
station.setPWM(crossingLeftLED, 0, 4096);//turn LED off
station.setPWM(crossing2LeftLED, 0, 4096);//turn LED off
station.setPWM(crossing3LeftLED, 0, 4096);//turn LED off
//right hand light

//add more leds in here as required
if (triggerCrossingLights > 0) { // if triggerCrossingLights is set to zero lights will stop
station.setPWM(crossingRightLED, 0, 4095);//turn LED on
station.setPWM(crossing2RightLED, 0, 4095);//turn LED on
station.setPWM(crossing3RightLED, 0, 4095);//turn LED on
}
}

}
//}
}

void setup() {
Serial.begin(9600);
Serial.println(“PCA9685LED_Effectsv1”);

Wire.begin();
station.begin();//start the PCA9685 for the station building
station.setPWMFreq(1600); // This is the maximum PWM frequency and suited to LED’s

//gShed.begin();//start the PCA9685 for the goods shed
//gShed.setPWMFreq(1600); // This is the maximum PWM frequency and suited to LED’s

station.setPWM(1, 0, 4095);//turn LED on
}

unsigned long myTimer;
void loop() {

fireFlicker();//calls the fire flicker function
arcWelder();//creates arc weld effect
crossingLights();

//This bit of code just simulates something turning the crossing lights on and off
//This would normally be a sensor or button changing the value of triggerCrossingLights

currentMillis = millis();
if (currentMillis – myTimer > 5000) {
myTimer = currentMillis;
if (triggerCrossingLights < 1) {
triggerCrossingLights = 1;
Serial.println(“crossing on”);
} else {
triggerCrossingLights = 0;
Serial.println(“crossing off”);
}
}

}

—Code einde—

Over de schrijver

Leave a reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.