Fnordlicht v3

Das Fnordlicht(Der Name wurde aus dem ähnlichen Projekt von www.lochraster.org übernommen, da er mir gut gefiel und mein Fnordlicht v1 ein Nachbau sein sollte.) ist ein DMX gesteuertes 5-Kanal LED-Licht. Damit kann ich RGBWY(Rot, Grün, Blau, Weiß, Gelb) einzeln Dimmen und so sehr viele verschiedene Farben erzeugen. Das genau gleiche Prinzip findet Anwendung bei professionellen LED-Bühnenscheinwerfern. Das Herzstück des Fonrdlichts ist ein Atmega 48 und für das Licht sorgen ~80LEDs. Die Materialkosten pro Einheit würde ich auf ca 15 - 20€ schätzen.

Theorie

Das Fnordlicht besteht damit aus 3 wesentlichen Teilen:

  1. Der DMX Ansteuerung
  2. Dem Dimmen per PWM
  3. Dem Ansteuern der LEDs mit PWM

Punkt 3 ist noch der einfachste, man schaltet 3 - 5 LEDs(je nach Spannung pro LED) in reihe und schließt sie über einen Vorwiderstand an 12V an. Dann wird jedes dieser Cluster über ein Transistor geschaltet. Dieser braucht nun das PWM Signal, damit wir gescheit dimmen können.
Das in Punkt 2 erwähnte PWM(Puls-Weiten-Modulation), das ein verfahren zum Dimmen von DC-Geräten genutzt wird und darauf aufbaut, den Strom in einem Gewissen Verhältnis An, bzw. Aus zu schalten und das so schnell, das wir das z.B bei LEDs nicht mehr wahrnehmen oder bei DC-Motoren der Schwung des Ankers erhalten bleibt. Da Atmel uns sehr entgegen kommt und den Atmegas eine Hardware-PWM Funktion spendiert hat, ist auch das kein großes Problem für den Amateur Elektroniker ;)
Kommen wir nun zum etwas trickreicheren Unterfangen mit dem DMX(Digital Multiplex, ein auf RS485 Aufbauendes Protokoll mit Anwendung in der Bühnen- und Veranstaltungstechnik zum steuern von Beleuchtungsgeräten, das keine Terminitaion benötigt und wo jeder Empfänger parallel zu den Datenleitungen geschaltet wird). Wir brauchen einen RS-485 Transreciver und einen DMX sender(ich verwende ein selbstgebautes uDMX: uDmx Projektseite). Als Transreciever verwende ich einen auf moderner CMOS Technologie basierenden MAX485, der Pingleich mit dem SN75176 ist.
Schaltplan ohne LEDs

LED-Cluster

Code:

#define F_CPU 16000000
 
#define dmx_size 7			// number of used DMX channels
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
 
#define BAUD 250000L		// DMX512          
 
#define UBRR_VAL  ((F_CPU+BAUD*8)/(BAUD*16)-1)  
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) 
 
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
#endif
 
// global variables
 
volatile uint8_t DmxArray[dmx_size];		// DMX data
volatile uint8_t flag;				// new data available
 
 
int main(void) 
{
	DDRB = 0xff;
	DDRD = (0xff & (~(1<<PD0)));
	PORTB = 0;
	PORTD = 0;
	flag = 0;
	//PWM config
	TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
	TCCR0B = (1 << CS02);
 
	TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);
	TCCR1B = (1 << CS12)| (1 << WGM12);
 
	TCCR2A = (1 << COM2A1) | (1 << COM2B1) | (1 << WGM20) | (1 << WGM21);
	TCCR2B = (1 << CS22) | (1 << CS21);
 
	OCR0A = 128;
	OCR0B = 128;
	OCR1B = 128;
	OCR1A = 128;
	OCR2A = 128;
// UART config
 
    UBRR0H = UBRR_VAL >> 8;
    UBRR0L = UBRR_VAL & 0xFF;
    UCSR0B = (1<<RXCIE0) | (1<<RXEN0);
 
	for(int i = 0; i < dmx_size; i++)
	{
		DmxArray[i] = 255;
	}
 
	sei();	 
 
// main loop
 
	while (1) {
		if (!flag) {
			set_sleep_mode(SLEEP_MODE_IDLE);
			sleep_mode();
		}
		else {
			flag=0;
			OCR0A = 255 - DmxArray[0];
			OCR0B = 255 - DmxArray[1];
			OCR1B = 255 - DmxArray[2];
			OCR1A = 255 - DmxArray[3];
			OCR2A = 255 - DmxArray[4];
		}
	}
}
 
// UART RX complete interrupt
 
ISR(USART_RX_vect) {
    static uint16_t dmx_channel=0, dmx_base=1;
    uint8_t status, data;
	int16_t index;
 
    // read UART data, also clears interrupt flag            
    status = UCSR0A;
	data = UDR0;
 
	if (status & (1<<FE0)) {					// frame error
		if (data==0) {						// break -> DMX Reset
			dmx_channel=0;
			dmx_base = /*(~PINB & 0xFF)+1*/1;
			//if (~PIND & (1<<PD6)) dmx_base +=256;
			flag=1;							// trigger update
		}
		else								// rx error
			dmx_channel++;
	}
	else {
		index = dmx_channel-dmx_base;
		if (index>=0 && index<dmx_size)
			DmxArray[index]=data;
		dmx_channel++;
	}
}

Umsetzung

Da 80 LEDs schon eine ganze Menge sind und es mit allen anderen Bauteilen zusammen weit über 100 Teile ergeben hat, habe ich mir ein Layout gemacht und auf Platine geätzt:
Platine Oben

Da mir aber der Ätzvorgang etwas misslungen war, musste ich mit Kupferlackdraht(Gefühlte 500m ;) ) nachhelfen, was zu einem ziemlichen Chaos unter der Platine führte :-) :
Platine Unten

Das Bild zeigt nur einen Ausschnitt des Chaos, mit dem ich mich stundenlang beschäftigte, nur um alle Fehler zu beseitigen. Aber die Arbeit hat sich gelohnt.

Ergebnis

TODO: Bilder vom Laufenden betrieb einfügen