- LiFePO4 Speicher Test         
Ergebnis 1 bis 10 von 10

Thema: Ambilight für den PC

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Benutzer Stammmitglied
    Registriert seit
    16.08.2006
    Beiträge
    34

    Ambilight für den PC

    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 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 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:

    Bild hier  
    Bild hier  

    Als RGB Leisten habe ich welche von Ebay 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.

    Bild hier  
    Bild hier  

    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:

    Bild hier  
    Bild hier  

    Bild hier  
    Bild hier  

    Bild hier  
    Bild hier  

    Bild hier  
    Bild hier  

    Bild hier  
    Bild hier  

    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:
    Code:
    #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:
    Code:
    #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
    Angehängte Dateien Angehängte Dateien

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen