AVR -> DMX

Beim schlendern durch das größte Kaufhaus des Internets bei der E-Bucht, fiel mir eine Chinesische Reisfeldbeleuchtung auf, auch Umgangssprachlich Sphärischer LED-Pinspot genannt. Für die Steuerung verfügt dieser über einen DMX (Digital Multiplex) Anschluss. Da mich meine Frau sowieso für einen Elektroschott Messie hält, habe ich kurzum das gute Gerät ersteigert. Solche Spots (Eurolite LED PST-9W RGB DMX 6° Pinspot) und LED Strahler (PAR-36 RGB LED) gibt es schon ab 39€ im Handel (RockShop).

Sphärischer LED-Pinspot

 

Natürlich wollte ich gleich den Spot über einen AVR Mikrocontroller(µC) ATmega88  (Experimentierboard V1) ansteuern. Dieses kann mit einer relativ einfachen Schaltung erfolgen. Der differentielle Pegel (DMX Ausgang) der Schaltung liegt zwischen +/-1V und +/-5V. Die nachfolgende Schaltung generiert aus dem ankommenden TTL Pegel des µC ein Symmetrisches Signal (RS485). Der Ausgangsstrom beträgt maximal 60mA. Das sollte für etwa 32 Geräte reichen. Für mehr Geräte benötigt man einen DMX Booster.

Hier wurden die Signale TXD vom µC kommend, sowie die DMX Signale aufgenommen. Eigentlich kommt nur ein zweiter invertierter Ausgang hinzu. Ein Inverter hätte evt. in diesem Fall als Lowcost Lösung ausgereicht. Allerdings könnte man in diesem Fall nicht 32 Geräte direkt ansprechen.

 

 

Nachdem ich die Schaltung aufgebaut und an mein ATmega88 Testboard angeschlossen hatte, benötigte ich auch eine entsprechende Software/Firmware für den µC. Die Software/Firmware muss das zeitliche Protokoll der USITT (United States Institute for Theatre Technology) DMX-512/1990 abbilden.

Das DMX 512 Protokoll für den LED-Pinspot nachzubilden ist relativ einfach. Ich sende  dazu für die Kanäle 1 – 512 die 512Bytes hintereinander über den USART0 des ATmega88 raus. Die USART Einstellungen sind dabei 250kbit/s (4µs pro Bit), 8 Datenbits, kein Parity-Bit und zwei Stoppbits.

main.c
80
81
82
83

84
//Init usart DMX-BUS
UBRR0	= (F_CPU / (DMX_BAUD * 16L) - 1);
DDRD    |= (1<<PD1); //Output TXD Pin ATmega88
UCSR0B  |=(1<<TXEN0)|(1<<TXCIE0);	// TXEN0 Transmitter enable 
				// TXCIE0 TX complete interrupt enable 
UCSR0C  |=(1<<USBS0); //USBS0 2 Stop bits

Jedes mal wenn der USART das Datenwort gesendet hat löst dieser einen Interrupt aus. In der Interruptroutine wird dann das nächste Datenwort versendet. Vor jeden 512Byte Datenbolck gehört noch ein Startbyte sowie eine Breakphase welche den Start einleitet. Das Startbyte entspricht den Wert 0. In der Breakphase wird der Bus mindestens 88µs auf "LOW" gezogen und danach mindestens 8µs auf "HIGH". Die Breakphase generiere ich in dem ich das Datenwort 0 mit 80000Baud sende. Das alles erfolgt in der Interruptroutine mittels einer State Machine. 

main.c
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//############################################################################
//DMX Senderoutine
ISR (USART_TX_vect)
//############################################################################
{
	static unsigned int  dmx_channel_tx_count = 0;
	static unsigned char dmx_tx_state = 0;
 
	switch (dmx_tx_state)
	{
		case (0):
			UBRR0   = (F_CPU / (DMX_BAUD_BREAK * 16L) - 1);
			UDR0 = 0; //RESET Frame
			dmx_tx_state = 1;
			break;
 
		case (1):
			UBRR0   = (F_CPU / (DMX_BAUD * 16L) - 1);
			UDR0 = 0; //Start Byte
			dmx_tx_state = 2;
			break;
 
		case (2):
			_delay_us(10);
			//Ausgabe des Zeichens
			UDR0 = dmx_buffer[dmx_channel_tx_count];
			dmx_channel_tx_count++;
 
			if(dmx_channel_tx_count == 512)
			{
				dmx_channel_tx_count = 0;
				dmx_tx_state = 0;
			}
			break;
	}
}

Zu guter letzt funktionierte nun damit mein LED Spot, und ein Samstagnachmittag war gerettet. ;-)

Dateien, DMX Empfangs und Senderoutinen, DMX Mixer

Layout, Source Code uvm. (22.12.2011)

 

DMX minimal nur für Testzwecke