Freitag, 25. Februar 2011

automatische Dimmung der QLOCKTWO

Ein offener Punkt in dem QLOCKTWO-Nachbau ist immer noch die lichtabhängige Dimmung. Eberhard hat die Idee gehabt, dazu den "Output Enable"-Pin der 74HC595-Shift-Register zu nehmen. Mit Hilfe dieses Pins kann man die Ausgänge der Shift-Register ein- und ausschalten. Verbindet man ihn mit einem Pin vom Arduino, der PWM (Pulse Width Modulation) kann, sollte man die Matrix dimmen können.

Eberhard hatte seine OE-Pins allerdings schon fest an Ground gelegt und als Alternative die Stromversorgung der UDN2981A-Verstärker-Chips über einen Transistor an einen PWM-Pin vom Arduino angeschlossen. Bezüglich der Dimmung scheint das gut zu funktionieren, allerdings brennen ihm aus bislang ungeklärten Gründen immer wieder mal LEDs durch.

Ich habe daraufhin versucht, die Dimmung über die OE-Pins mit meiner Test-QLOCKTWO zu implementieren. Dabei hat sich gezeigt, daß die Taktung des Matrix-Multiplexings und die Taktung des PWM-Signals interferieren und es dadurch zum Flackern kommt.

Weitere Nachforschungen haben ergeben, daß die Methode digitalWrite() eher langsam ist (weil sie einige Prüfungen vornimmt). Das ist meistens kein Problem, möchte man allerdings hochfrequent eine Matrix ansteuern, kann es zu langsam sein. Es gibt einige Stellen im Web, die sich mit schnellerem Schreiben auf die Ports beschäftigen, wie z.B.

aber der Code hat bei mir nicht funktioniert. Ich habe daraufhin in dem Source-Code von Arduino nachgesehen, wie die Funktion digitalWrite() aufgebaut ist (Open-Source sei dank):


void digitalWrite(uint8_t pin, uint8_t val) {
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;

if (port == NOT_A_PIN) return;

// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);

out = portOutputRegister(port);

if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*out |= bit;
SREG = oldSREG;
}
}


Mit der Hilfe dieses Code-Schnipsels und ein paar Initialisierungen im Konstruktor kann man sich dann schnelle Funktionen bauen (hier am Beispiel des Schreibens auf die Serial-Clock-Leitung):


void ShiftRegister::fastDigitalWriteToClock(uint8_t val) {
if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*_clockOut &= ~_clockBit;
SREG = oldSREG;
}
else {
uint8_t oldSREG = SREG;
cli();
*_clockOut |= _clockBit;
SREG = oldSREG;
}
}


Jetzt sind die Interferenzen nicht mehr bei jeder "Dimmstufe" so stark wahrzunehmen. Ich muß noch ein bisschen experimentieren, um die richtigen, interferenzfreien Stufen zu finden, aber als Zwischenschritt bin ich schon mal ganz zufrieden.

Keine Kommentare:

Kommentar veröffentlichen