Karosseriebeleuchtung mit PCA9685
Vom Gedanken bis zur Umsetzung zeigte sich ein deutliche höherer Aufwand beim Verkabeln mehrere Leitungen und beim Programmieren des PWM Moduls, als gedacht.
Benötigt
- Arduino
- PWM Modul PCA9685
- LEDs und Widerstände
Ziel
Standlicht, Fahrlicht, Blinker und Flutlichter sollten alle individull an-steuerbar sein. Hier sollen die Lichter immer durch ein Fade-Effekt abgebildet werden.
Initialisieren
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
void setup() {
pwm.begin();
pwm.setPWMFreq(1600);
Wire.setClock(400000);
// schaltet alle aus
for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) {
pwm.setPWM(pwmnum, 0, 4095);
}
}
Fade-In und Fade-Out
Leider kann man nicht einfach einen Wert von 0 bis 256 in den Controller eingeben, um Animationsverläufe darin abzubilden. Wenn man versucht auf diese Weise die LEDs anzusteuern, dann funktioniert das schlecht oder gar nicht. Zum Glück ist bereits ein Beispiel Code in den Sourcen für das PCA9685 Modul integriert, dass genau diese Funktion darstellt.
Mit dem Adafruit Beispiel 'pwmtest' wird gezeigt, wie das Zuweisen um-gesetzt wird. Dort sieht man, dass nicht immer plus eins, sondern immer plus acht addiert wird. Das ist sicherlich auf die 12Bit pro Port zurück zu führen.
void loop() {
int stepAdd = 10;
int leds = 4;
for (uint16_t i=0; i<4096; i += stepAdd) {
for (uint8_t pwmnum=0; pwmnum < leds; pwmnum++) {
pwm.setPWM(pwmnum, 0, 4096 - i);
}
}
delay(1000);
for (uint16_t i=0; i<4096; i += stepAdd) {
for (uint8_t pwmnum=0; pwmnum < leds; pwmnum++) {
pwm.setPWM(pwmnum, 0, i);
}
}
delay(1000);
}
Asynchroner Ablauf
Für mein Ziel wird mehr als eine LED und neben dem Modul noch WS2812b RGB LEDs eingesetzt. Damit ich nicht für jede LED einen eigenen Controller benötige, muss ich sicherstellen, wie schnell etwas aus- oder eingeblendet werden soll.
unsigned long mCurrentMillis;
unsigned long mLastMillis_LED_1;
unsigned long mLastMillis_LED_2;
uint16_t mValueLED_1 = 0;
uint16_t mValueLED_2 = 0;
void loop() {
uint16_t endValue = 4096;
int stepAdd = 10;
int leds = 4;
mCurrentMillis = millis();
if(mCurrentMillis - mLastMillis_LED_1 > 5) {
if(mValueLED_1 < endValue) {
mValueLED_1 += stepAdd;
pwm.setPWM(0, 0, mValueLED_1);
}
else {
mValueLED_1 = 0;
}
mLastMillis_LED_1 = mCurrentMillis;
}
if(mCurrentMillis - mLastMillis_LED_2 > 10) {
if(mValueLED_2 < endValue) {
mValueLED_2 += stepAdd;
pwm.setPWM(1, 0, mValueLED_2);
}
else {
mValueLED_2 = 0;
}
mLastMillis_LED_2 = mCurrentMillis;
}
}
Blinker
Einfaches Ein- und Ausschalten ist nicht schwer zu programmieren. Mit einem schnelle Fade-In, Fade-Out war nur etwas ausprobieren nötig. Zuerst hatte ich das Problem. dass die LEDs nie ganz ausgingen, womit das Blinken selbst weniger deutlich zu sehen waren, wenn der Blinker betätigt wurde.
Im Grunde war das ein Denkfehler, weil ich die Schrittweite zum Fade-Out nicht berücksichtigt habe und, um eine Iteration zu früh den Vorgang verlassen habe.
unsigned long mCurrentMillis;
unsigned long mLastMillis_LED_1;
unsigned long mLastMillis_LED_2;
uint16_t mValueLED_1 = 0;
bool mFlashingLED_2 = false;
void loop() {
uint16_t endValue = 4096;
int stepAdd = 10;
int leds = 4;
mCurrentMillis = millis();
if(mCurrentMillis - mLastMillis_LED_1 > 5) {
if(mValueLED_1 < endValue) {
mValueLED_1 += stepAdd;
pwm.setPWM(0, 0, mValueLED_1);
}
else {
mValueLED_1 = 0;
}
mLastMillis_LED_1 = mCurrentMillis;
}
if(mCurrentMillis - mLastMillis_LED_2 > 200) {
mFlashingLED_2 = !mFlashingLED_2;
if(mFlashingLED_2) {
pwm.setPWM(1, 0, 4095);
}
else {
pwm.setPWM(1, 0, 0);
}
mLastMillis_LED_2 = mCurrentMillis;
}
}
Viel aus-probieren
Erst am Ende, wenn alles im Programmcode eingegeben ist, muss die Geschwindigkeit der Animationen eingestellt werden. Damit dies geht, sollte möglichst am Anfang diese Einstellungen zentral eingehalten werden, um das Nachjustieren zu beschleunigen.
Kommentare