PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ambilight für den PC



Homer Jay
30.09.2008, 18:39
Hi Leute,

nachdem ich hier nun schon fleißig mitgelesen habe und die eine oder andere Frage losgeworden bin, wird es Zeit, dass ich mein erstes großes Projekt hier mal vorstelle. Seit einiger Zeit verfolge ich diesen (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=12700&highlight=ambilight) Beitrag, da sich dort im Moment allerdings nicht viel Neues tut, habe ich mich entschlossen, mein eigenes Ambilight für meinen PC zu entwickeln:

Im Netz habe ich Boblight (http://lx.divxstation.com/article.asp?aId=151&page=3) gefunden, welches über die RS232 Schnittstelle die RGB Daten für den rechten, oberen und linken Teil des Bildschirms bereitstellt. Somit musste ich mich um die PC-seitige Software nicht kümmern. Dies hätte ich eh nicht hingekriegt. Ich musste also nur noch einen µC so programmieren, dass er die Daten empfängt und als PWM auf die LED-Leisten gibt. Aber erstmal zu den LED-Leisten selbst:

http://img151.imageshack.us/img151/834/bersichtlm6.jpg (http://imageshack.us)
http://img151.imageshack.us/img151/bersichtlm6.jpg/1/w640.png (http://g.imageshack.us/img151/bersichtlm6.jpg/1/)

Als RGB Leisten habe ich welche von ebay (http://cgi.ebay.de/ws/eBayISAPI.dll?ViewItem&item=8072031482&ru=http%3A%2F%2Fshop.ebay.de%3A80%2F%3F_from%3DR40 %26_trksid%3Dm38.l1313%26_nkw%3D8072031482%26_saca t%3DSee-All-Categories%26_fvi%3D1) genommen. Auf einem Strip sind drei Cluster mit je 3x3 Superflux Leds und den entsprechenden Widerständen für einen direkten Betrieb an 12V angebracht. Die Strips lassen sich zwischen den Clustern trennen. Für rechts und links an meinem 22" Monitor passt genau ein Strip, für oben habe ich zwei Strips zusammengefügt, so dass dieser aus 5 Clustern besteht. Die Streifen sind beweglich auf einem, bzw. zwei Alustreifen (Baumarkt-Meterware) gelagert, so dass ich die Strips ausrichten kann. Dazu habe ich 3mm Messingdraht an den Alustreifen geklebt und auf die überstehenden Enden Messingrohrstücke gesteckt, die ich vorher an den Enden etwas zusammengequetscht habe. An diesen Rohrstücken sind die Strips festgeklebt. So lassen sich die Strips ausrichten, ohne dass sie ihre Position aufgrund der Schwerkraft ändern. Die Alustreifen habe ich mit Tesa-Powerstrips auf dem Monitor befestigt.

http://img505.imageshack.us/img505/3821/detailcz2.jpg (http://imageshack.us)
http://img505.imageshack.us/img505/detailcz2.jpg/1/w640.png (http://g.imageshack.us/img505/detailcz2.jpg/1/)

Die Hardware besteht aus zwei Mega88, einer empfängt die Daten über UART und bedient die linke Seite, sowie den blauen Kanal, Mitte. Die übrigen Daten werden an den zweiten Mega88 per UART weitergesendet, dieser dient nur als PWM-Chip. Es ist vorgesehen, über ein Poti die Helligkeit zu regeln, des Weiteren soll es ebenfalls möglich sein, anstatt der Steuerung über den PC, mit einem Poti die Farbe einzustellen, so dass man eine einheitliche Hintergrundfarbe für den Monitor einstellen kann. Dies hab ich aber noch nicht implementiert.

Boblight sendet ein Paket von 9 Bytes, die die Farbinformationen halten. Die einzelnen Bytes kommen in einem Abstand von ca. 0.001 Sekunden an, zwischen den Paketen ist ein Abstand von ca. 0,01 Sekunden (einstellbar). Die Software für die Megas funktioniert bereits sehr gut, normaler Desktopbetrieb, Videos und DVD(mit dem VLC-Player) und Spiele, alles ist möglich. Da ich leider keine Videos aufnehmen kann, hier nur ein paar Standbilder, die vor allem die Ausleuchtung und Farbe der RGB-Leisten demonstrieren:

http://img528.imageshack.us/img528/5181/blauyc0.jpg (http://imageshack.us)
http://img528.imageshack.us/img528/blauyc0.jpg/1/w640.png (http://g.imageshack.us/img528/blauyc0.jpg/1/)

http://img522.imageshack.us/img522/7097/grngo1.jpg (http://imageshack.us)
http://img522.imageshack.us/img522/grngo1.jpg/1/w640.png (http://g.imageshack.us/img522/grngo1.jpg/1/)

http://img522.imageshack.us/img522/867/pinkkv4.jpg (http://imageshack.us)
http://img522.imageshack.us/img522/pinkkv4.jpg/1/w640.png (http://g.imageshack.us/img522/pinkkv4.jpg/1/)

http://img528.imageshack.us/img528/4733/rotuk1.jpg (http://imageshack.us)
http://img528.imageshack.us/img528/rotuk1.jpg/1/w640.png (http://g.imageshack.us/img528/rotuk1.jpg/1/)

http://img444.imageshack.us/img444/9518/trkiszg7.jpg (http://imageshack.us)
http://img444.imageshack.us/img444/trkiszg7.jpg/1/w640.png (http://g.imageshack.us/img444/trkiszg7.jpg/1/)

Nur Gelb hat meine Kamera irgendwie nicht gemocht, das sah total komisch aus (also aufm Bild, in Echt ist es super)

Da die Leisten keine RGB Leds, sondern rote, grüne und blaue Leds nebeneinandern haben, sieht man bei Mischfarben ein paar Streifen oben und unten, aber das stört nicht wirklich.

Mit einem Problem habe ich allerdings noch zu kämpfen, ab und zu geht die Beleuchung kurz aus und sofort wieder an. Dieses flackern ist recht unangenehm, erklären kann ich es mir aber nicht. Vielleicht könnt ihr ja mal einen Blick über den Code werfen, vielleicht fällt euch ja was auf, worans liegen kann. Dies ist übrigens die "schnelle" Version, ich habe auch noch eine langsamere Version, die vor der Weitergabe der Daten die empfangene Anzahl an Bytes pro Paket checkt, da taucht das Flackern nicht auf. Da aber die Leds auch bei der schnellen Version aktiv ausgeschaltet werden müssen (also per 0 0 0 0 0 0 0 0 0 von Boblight), kann ich mir das Flackern echt nicht erklären.

Hier der Code für den Master: (an dem hängts, dass es flackert....)

ambilight.c:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdavr.h>
#include "fifo.h"
#include "uart.h"

#define F_CPU 14745600
#define BAUDRATE 9600

void initialize_IO(void);
void initialize_IRQ(void);
void initialize_TIMER0(void);
void initialize_TIMER1(void);
void initialize_TIMER2(void);
//void initialize_ADC(void);

int main(void)
{
initialize_IO();
initialize_IRQ();
//initialize_ADC();
initialize_TIMER0();
initialize_TIMER1();
initialize_TIMER2();
initialize_UART(BAUDRATE);

// enable global interrupts
sei();

while(1);

return 0;
}

void initialize_IO(void)
{
// PWM-Pins als Output setzen
DDRD |= (1<<PD3)|(1<<PD5)|(1<<PD6);
DDRB |= (1<<PB3);
}

void initialize_IRQ(void)
{
// enable Timer1 Overflow Interrupt
TIMSK1 = (1<<TOIE1);

// enable AD-Converter Interrupt
//ADCSRA |= (1<<ADIE);
}

void initialize_TIMER0(void)
{
// Timer0-Register
TCNT0 = 0;

// Output Compare Pin Behaviour:
// clear OC0A and OC0B on compare match and set on TOP
TCCR0A |= (1<<COM0A1)|(1<<COM0B1);

// Wave Form Generation:
// Fast PWM with TOP at 0xFF.
TCCR0A |= (1<<WGM01)|(1<<WGM00);

// Initialy set the Ouput Compare Registers to zero:
OCR0A = 0x00;
OCR0B = 0x00;

// Start Timer with Prescaler of 256 --> f_Timer0 = 225Hz
TCCR0B |= (1<<CS02);
}

void initialize_TIMER1(void)
{
// Timer1-Register initialisieren
TCNT1H = 0x00;
TCNT1L = 0x00;
}

void initialize_TIMER2(void)
{
// Timer0-Register
TCNT2 = 0;

// Output Compare Pin Behaviour:
// clear OC02A and OC2B on compare match and set on TOP
TCCR2A |= (1<<COM2B1)|(1<<COM2A1);

// Wave Form Generation:
// Fast PWM with TOP at 0xFF.
TCCR2A |= (1<<WGM21)|(1<<WGM20);

// Initialy set the Ouput Compare Registers to zero:
OCR2A = 0x00;
OCR2B = 0x00;

// Start Timer with Prescaler of 256 --> f_Timer2 = 225Hz
TCCR2B |= (1<<CS22);
}

/*void initialize_ADC(void)
{
// Voltage Reference = AREF --> no Bit need to be set
// PC0 as first AD-Conversion --> no Bit need to be set

// Set ADC Prescaler to 128 (--> F_ADC = 14745.6/128 = 115.2kHz)
// Set ADC Prescaler to 64 (--> F_ADC = 8000/128 = 125kHz)
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

// Set Auto Trigger Source to Timer1 Overflow --> at each new Datablock the ADC will be run
ADCSRB |= (0<<ADTS2)|(0<<ADTS1);

//Digital Input Disable
//### write to 1, when digital input on this pin is not needed ###
//DIDR0 = (1<<ADC0D)|(1<<ADC1D)|(1<<ADC2D)|(1<<ADC3D)|(1<<ADC4D)|(1<<ADC5D);

// Auto Trigger Enable
ADCSRA |= (1<<ADATE);

// Left-adjust result for 8-bit accuracy
ADMUX |= (1<<ADLAR);

// Enable ADC
ADCSRA |= (1<<ADEN);

//Start Conversion
ADCSRA |= (1<<ADSC);
}*/



/*ISR(SIG_ADC)
{
if(BIT_IS_SET(ADMUX, MUX0)) { // if ADC1 was selected
adc_value[COLOUR] = ADCH;
CLEAR_BIT(ADMUX, MUX0); // select ADC0 as new ADC-Channel
}
else { // if ADC0 was selected
adc_value[BRIGHTNESS] = ADCH;
SET_BIT(ADMUX, MUX0); // select ADC1 as new ADC-Channel
}
}*/

ISR(SIG_OVERFLOW1)
{
/* Timer1 läuft nach 0,00444 Sekunden über. Da er in der UART-
Empfangs-ISR immer wieder zurückgesetzt und neu gestartet wird,
läuft Timer1 nur zwischen zwei Datenpaketen über. Dann wird
der Counter der UART-Empfangs-ISR zurückgesetzt, um die richtige
Zuordnung der PWM-Werte sicherzustellen */
uart_clear_counter();
}

uart.c:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdavr.h>
#include "uart.h"
#include "fifo.h"

#define START_TIMER1 SET_BIT(TCCR1B, CS10) //prescaler = 1
#define STOP_TIMER1 TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10))
#define CLEAR_TIMER1 TCNT1 = 0

// FIFO-Objekt und Puffer für die Ausgabe
#define BUFSIZE_OUT 5
uint8_t outbuf[BUFSIZE_OUT];
fifo_t outfifo;

// Counter-Variable
volatile uint8_t k = 0;

void initialize_UART(const uint16_t baudrate)
{
uint8_t sreg = SREG;
//uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16L*baudrate) - 1);
uint16_t ubrr = (uint16_t) ((uint32_t) 14745600/(16L*baudrate) - 1);

UBRR0H = (uint8_t) (ubrr>>8);
UBRR0L = (uint8_t) (ubrr);

// Interrupts kurz deaktivieren
cli();

// UART Receiver und Transmitter anschalten, Recieve-Interrupt aktivieren
// Data mode 8N1, asynchron
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
UCSR0C = (1<<USBS0) | (3<<UCSZ00);

//Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
do
{
UDR0;
}
while (UCSR0A & (1<<RXC0));

// Rücksetzen von Receive und Transmit Complete-Flags
UCSR0A = (1<<RXC0)|(1<<TXC0);

// Global Interrupt-Flag wiederherstellen
SREG = sreg;

// FIFO für Ausgabe initialisieren
fifo_init (&outfifo, outbuf, BUFSIZE_OUT);
}


int uart_putc(const uint8_t c)
{
int ret = fifo_put(&outfifo, c);

UCSR0B |= (1<<UDRIE0);

return ret;
}

void uart_clear_counter(void)
{
k = 0;
}


ISR(SIG_USART_RECV)
{
STOP_TIMER1;
CLEAR_TIMER1;
START_TIMER1;

switch (k++)
{
case 0:
OCR0B = UDR0; // Rot, Links
break;
case 1:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Rot, Mitte)
break;
case 2:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Rot, Rechts)
break;
case 3:
OCR0A = UDR0; // Grün, Links
break;
case 4:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Grün, Mitte)
break;
case 5:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Grün, Rechts)
break;
case 6:
OCR2B = UDR0; // Blau, Links
break;
case 7:
OCR2A = UDR0; // Blau, Mitte
break;
case 8:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Blau, rechts)
break;
}
}


// Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
// Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA_IRQ getriggert
// Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
ISR(SIG_USART_DATA)
{
if (outfifo.count > 0)
UDR0 = _inline_fifo_get(&outfifo);
else
UCSR0B &= ~(1<<UDRIE0);
}

Der Rest vom Code ist im Anhang.


So, ich hoffe, euch gefällts!

Markus

Felix.
30.09.2008, 23:51
irgendwie traut sich hier wohl keiner zu schreiben ;) sind wohl alle vor ehrfurcht erstarrt.

also das is mal ein geniales ambilight! fetten respekt! die farbangleichung scheint ja super zu funktionieren. da kriegt man echt lust so ein reil auch mal aufzubauen. (hinter meinem monitor is noch alles dunkel ;) )

so long an thanks for all the fish

ps: nonplusultra wäre, wenn du das layout mal als gif reinstellst, mein eagle macht da irgendwie blöedsinn ;)

Homer Jay
02.10.2008, 11:02
Hi Felix, danke für Dein Lob!

ja, es funktioniert echt gut, bis auf wie gesagt das Flackern. Mit einer anderen Version der Software tritt das nicht auf, dafür reagiert es mit ner geschätzten 1/10 Sekunde langsamer. Mal schauen, ob ich noch rausfinde, worans liegt.

Das die eagle-Dateien nicht gehen ist klar. Mein Fehler. Habe eigene Libs verwendet. Hier die Bilder:

http://img100.imageshack.us/img100/6839/brainschjk2.png (http://imageshack.us)

http://img20.imageshack.us/img20/8449/brainbrdap5.png (http://imageshack.us)

Markus

Spion
02.10.2008, 20:39
Hallo Markus

Erstmal Respekt, ist wirklich super geworden. Hat mich so begeistert, dass ich mir auch so eins baue.

Wer die Ledleisten nicht bei Ebay kaufen will kann dies auch über Ledsee (http://ledsee.com/index.php?page=shop.product_details&flypage=shop.flypage&product_id=169&category_id=22&manufacturer_id=0&option=com_virtuemart&Itemid=27) (selber Händler) tun.

Hast du BobLight auch schon mit 2 Bildschirmen ausprobiert? Ich habe gesehen das man da Display0 und Display1 auswählen kann, was das aber genau zu bedeuten hat weiss ich leider nicht.

Gibt BobLight pro Seite eine Farbe an oder mehrere?

mfg Luca

dremler
03.10.2008, 10:50
hallo...das projekt gefällt mir.....

könntest du deinen bildschirm eventuell mal drehen , sodass man sieht wie hell das licht ist wenn es ca 2-3 m von einer wand entfernt ist? auch wäre es schön wenn du mal 2 der 3 leisten zuhalten könntest (stück pappe oder so) das man die helligkeit einer leiste sieht:)

danke dir...;)

Homer Jay
06.10.2008, 18:27
Hallo,

@Spion: leider habe ich nur einen Monitor, deswegen kann ich nicht sagen, was die Umschaltung zwischen display0 und display1 bewirkt und ob boblight ggf. die daten bei Anschluss zweier Monitore richtig berechnet.

@dremler: also meinen Monitor brauche ich nicht zu drehen, um dir zu sagen, dass du in 2-3 Metern Entfernung nix mehr von den Leds sehen wirst. Dazu sind die viel zu schwach und auch der Austrittswinkel der Leds ist dafür zu groß. Aber dafür ist das Ambilight ja auch nicht gedacht. In der Regel steht der Fernseher oder der Monitor an der Wand. Bei dir nicht? Bei mir beträgt die Entfernung zwischen Monitor und Wand ca. 14cm. Für diese Entfernung und bestimmt auch noch bis zu einer Entfernung von 20-25cm sind die Leds ausreichend stark. Bilder, bzw. Fotos sind sowieso nicht sehr aussagekräftig, da man die Wirkung der Leds auf dem Bild mit der Einstellung über Belichtungszeit und Blende stark beeinflusse kann. Ich habe die Fotos so aufgenommen, dass sie ungefähr die wirkliche Ausleuchtung widergeben. Daran kannst Du dich orientieren. Mir langen die Leds von der Leistung. Wenn du mehr brauchst, kannst du ja zwei Leisten nebeneinander verwenden.

@all: Berichtet dann mal von euren Ergebnissen, wenn ihr das Ambilight gebaut habt!

Viele Grüße, Markus

dremler
06.10.2008, 18:39
naja ich wollts ne für ein ambilight haben sondern sner art deckenstrahler bauen;)

trotzdem danke;)

unleashed
06.10.2008, 21:09
hi tolles Projekt, sieht echt klasse aus.

ich hab gestern mal kurz nach dem Boblight gegoogled und leider nicht gefunden in welches Reihenfolge die Bytes gesendet werden. könntest du die mir bitte mal posten?

Homer Jay
06.10.2008, 21:14
switch (k++)
{
case 0:
OCR0B = UDR0; // Rot, Links
break;
case 1:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Rot, Mitte)
break;
case 2:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Rot, Rechts)
break;
case 3:
OCR0A = UDR0; // Grün, Links
break;
case 4:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Grün, Mitte)
break;
case 5:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Grün, Rechts)
break;
case 6:
OCR2B = UDR0; // Blau, Links
break;
case 7:
OCR2A = UDR0; // Blau, Mitte
break;
case 8:
uart_putc(UDR0); // Weitersenden der Daten zum Slave (Blau, rechts)
break;
}

Markus

unleashed
06.10.2008, 21:23
danke das war flott