Page 1 of 1

RGB-LED-Steuerung, für die, die es haben wollen...

Posted: Sun 26 Feb, 2006 6:33 pm
by random
Tach,

wer's haben will hier der Quellcode zur Ansteuerung einer RGB-LED.
Wer schimpfen will, solls tun, und es besser machen!
Dies ist für die Einsteiger gedacht, die Input zum uC-Lernen suchen ;-)


Code: Select all

#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdlib.h>


/****************************
 RGB-LED-Steuerung
 26.02.06 Th. de Buhr
 
 Ansteuerung einer RGB-LED
 Port B: 0=R, 1=G, 2=B
****************************/ 


#define CLK 8000000

#define delay_ms(ms) _delay_loop_2(ms * (CLK/4000))
#define delay_us(us) _delay_loop_2(us * (CLK/4000000))

#define bit_on(BYTE, BIT)  BYTE |= 1 << BIT;
#define bit_off(BYTE, BIT) BYTE &= ~(1 << BIT);


volatile char colour=1, led_out=0;
volatile int time=0, pwm=0;
volatile char palette[12]={0,1,2,4,1,2,3,4,5,6,7};


SIGNAL(SIG_OVERFLOW0)
{	
	TCNT0 = 0x80;
	time++; 
	
	if(time>=100) time=0;
	
	if(time>pwm)
	{
		led_out=0;			
	}
	
	else
	{
		led_out=palette[colour];	
	}
	
	PORTB = led_out;		
}



int main()
{
	char i=0;
	//pwm = 0...100%, colour = 0...10
		
	DDRB=0xFF;
	PORTB=0x00;
	
	DDRD=0xFF;
	PORTD=0x00;
		
	//Timer 8Bit setup
	bit_off(TCCR0, CS00);		//Int. CLK/8
	bit_on(TCCR0, CS01);
	bit_off(TCCR0, CS02);
	 
	TCNT0 = 0x00;				//Timer-Reg. löschen
	 
	bit_on(TIMSK, TOIE0);		//Overflow-Int. enable


	sei();

	delay_ms(20);				//Pause, falls Programmierfehler den Programmierport überschreibt
	
	
	while(1)
	{	
		for(i=0; i<=100; i++)
		{
			pwm=i;					
			delay_ms(20);				
		}
		
		if((++colour) > 10) colour=1;
 	} 	
}


edit:
-----

Das ganze läuft auf einem Atmel AVR (AT Mega 8) und ist unter WinAVR geschrieben (d.h. main.c - file & Makefile)

PWM ist bei Mikrocontrollern die gängige Variante, wenn es darum geht, Lampen (oder Motoren :lol: ) zu dimmen.
Man legt nicht einen analogen Pegel auf die LED (Scheinwerfer, Gleichstrommotor), sondern schaltet den maximalpegel ständig an/aus.

Durch den Tastgrad (=An-Zeit / Aus-Zeit oder andersherum ;-) ) wird die Leistung im "Verbraucher" bestimmt und dadurch z.B. die Leuchtkraft einer LED, eines Scheinwerfers etc...

Das Programm verwendet zum Erzeugen des PWM (=Pulsweitenmodulation) einen 8Bit-Timer. In der ISR (Interrupt - Service-Routine) Wird der PWM generiert. Mit 2 Variablen lassen sich Farbe und Tastgrad (in %) bestimmen, die gesamte Impulslänge wird durch den Timer festgelegt.
Je höher die Periodendauer des PWM-Signals, desto "ruckelfreier" läuft das Dimmen bzw.der Motor.
Aber auch hier sind Grenzen gesetzt (z.B. die Induktivität eines Motors, die mag ja bekanntlich schnelle Spannungsänderungen gar nicht gerne und geht die Änderung ganz gemächlich an (anderes Thema!).


btw: Wens interessiert: "Architektur" des Programms ist Round Robin mit Interrupt. Wohl für solche Anwendungen das Gängigste...

edit: Bug korrigiert, s. unten.



Greetz
medra

Posted: Sun 26 Feb, 2006 7:50 pm
by schobi
Hallo,

finde ich gut dass du deinen Quellcode veröffentlichst. Vielleicht wäre es noch interessant gewesen etwas näher zu erläutern auf welcher Plattform das läuft und wie es funktioniert. Sieht nach Atmel AVR aus. Nicht jedem Anfänger dürfte klar sein dass die Dimmung per PWM erfolgt (und was PWM überhaupt ist -> Pulsweitenmodulation).

Ich habe auf einem AVR einen 24kanal-Dimmer laufen (für 8 RGB Scheinwerfer), allerdings dürfte der spärlich kommentierte Assemblercode wenig hilfreich sein.

Was steuerst du damit an? Eine einzelne RGB-LED oder einen grossen Scheinwerfer mit vielen LEDs?

Gruß Tobias

Posted: Sun 26 Feb, 2006 8:21 pm
by random
Hi,

ich steuer damit eine RGB-LED. Hab mir bei ebay 5 stück kommen lassen, um mal damit zu spielen. Das ist herausgekommen. Der ganze Aufbau ist auf einem Steckbrett (Mega8, ULN2803, 8MHz, 22pF, 7805 mit drumherum, RGB-LED mit Anode an +12V und Kathoden über 680Ohm an den ULN. Dazu ein Steckbrett-tauglicher Adapter für mein Programmierkabel :lol: )
Also wirklich denkbar einfacher Aufbau.

Bei uCs steckt die meiste Denkarbeit eh im Code.

Wenn einer den Schaltplan zum Nachbauen haben will, dann pinsel ich das gerne eben auf (Target 3001 bzw. als tif) :lol:


Ich schreibe meinen Code idR in C. Bin etwas zu faul für assembler (geht auch, C ist aber einfacher und lesbarer), dafür aber sehr für kryptische C-Fragmente zu haben :twisted:

Posted: Mon 27 Feb, 2006 8:57 pm
by random
Haha ... nen Bock geschossen ;-)
Keiner gefunden ?

Hier:

if((++colour) > 10) colour=1;

der muss latürnich erst erhöhen und dann testen, ob > 10 :lol:


Greetz,
medra

Posted: Mon 27 Feb, 2006 9:12 pm
by lightfreak
if((++colour) > 10) colour=1;

der muss latürnich erst erhöhen und dann testen, ob > 10
Tut er doch, ist doch nen preinkrement und kein postinkrement.

Gruß

Simon

Posted: Wed 01 Mar, 2006 10:19 pm
by random
Lightfreak wrote:
if((++colour) > 10) colour=1;

der muss latürnich erst erhöhen und dann testen, ob > 10
Tut er doch, ist doch nen preinkrement und kein postinkrement.

Gruß

Simon
richtig, aber das Feld war da schon zuende, so zählt der nämlich bis 11.
Hab mich gewundert, dass eine "AUS"-Phase mit drin war ;-) Glücklicherweise stand da NULL im Speicher ;-) (zumindest auf den unteren 3 Bits, die ich nutze)

Hab das schon im Code oben bereits geändert ("edit: Bug korrigiert, s. unten."), anfangs stand da colour++

Greetz,
Medra


PS: Jetzt wäre zu überlegen, wie man einen 3-Kanal PWM (also alle 3 Kanäle unterschiedlich) in eine Timer-ISR bekommt ... :twisted: