Hallo liebe Gemeinde,
Ich möchte gerne mehrere RGB Leds ansteuern über den WS2803. Die
Ansteuerung funktioniert schon leider ist das ansteuern der einzelnen
Leds sehr umständlich. wie könnte ich das besser machen?
Habe ein Atmega32 und programiere in C.
Die Ansteuerung ist über SPI.
Jede LED hat drei werte also 3Byte pro Led.
1
uint8_twert[17];
2
3
//3 Werte pro LED
4
wert[0]=100;
5
wert[1]=200;
6
wert[3]=50;
7
8
//Senden der Daten
9
Spi_Master_Send(wert[0]);
10
Spi_Master_Send(wert[1]);
11
Spi_Master_Send(wert[2]);
Das ganze kann man doch in einer Funktion zusammenfasen.
Mein erster ansatz war sowas...
1
structLED
2
{
3
uint_8t=Rot;
4
uint_8t=Gruen;
5
uint_8t=Blau;
6
};
7
8
voidLED_einzeln(structLED)
9
{
10
//senden der Daten
11
}
das geht natürlich nicht schade aber gibt es einen besseren Asatz?
Vielen dank
Mathias
Mathias G. schrieb:> Mein erster ansatz war sowas...struct LED
Ein paar syntaktische Probleme, sieht aber sonst doch ganz gut aus...
> das geht natürlich nicht
Warum nicht? Abgesehen davon, dass es noch nicht fertig ist, passt das
doch: die Werte für 1 LED in einem Struct zusammenfassen. Dann so viele
Structs instantieren, wie LEDs da sind. Dann 1 Funktion zum Senden an 1
LED schreiben. Die dann so parametrieren, dass beliebige LEDs
angesprochen werden können...
Wenn ich mich richtig erinnere, definierst du quasi einen neuen
Variablentyp. Die "=" müssen also weg. Dann instantiierst du das wie
eine Variable:
LED meine_leds[6];
meine_leds[0].Rot= 0x00;
meine_leds[0].Gruen= 0x80;
meine_leds[0].Blau= 0xff;
...
meine_leds[5].ROT= blablabla;
LED_einzeln (meine_leds[0]);
...
void LED_einzeln (LED hier_meine_leds) {
SPI_send(hier_meine_leds.Rot);
SPI_send(hier_meine_leds.Gruen);
SPI_send(hier_meine_leds.Blau);
}
Such doch noch mal das C-Handbuch raus und lies die korrekte Nomenklatur
nach.
Du baust dir ein Struct und dekalrierst das als Datentype.
Dann kannst du so viele Variablen davon intialiesren wie du brauchst und
dein RAM hergibt.
Den Datentyp kannst du behandlen wie jeden anderen auch zB. int, char,
...
Vielleicht noch
[c]
SendLED(tLED *data){
SPIsend(data->wert1);
SPIsend(data->wert2);
SPIsend(data->wert3);
}
aufrufen kannst du dann die Funktion mit
SendLED(&led1);
Florian K. schrieb:> typedef struct{> unsigned char wert1;> unsigned char wert2;> unsigned char wert3;> }tLED;
Wobei "uint8_t" bzw. "uint8_fast_t" die Intentionen ersichtlicher
machen. "char" ist weder in der Bitbreite noch im Vorzeichen genau
festgelegt.
Mit freundlichen Grüßen,
Karol Babioch
So habe das mal so gemacht wie ihr es mir empfohlen habt.
Also das mit den Zeigern muss ich mir noch einhämmern.
Jetzt ist volgendes Problem.
Ich muss immer alles 6 Leds hintereinander über spi rausschicken.
Also wenn ich ein Wert ändern will muss ich trotzdem alle Leds
ansprechen.
Das gleiche Prinzip wie im Schieberegister.
Am ende soll es so sein das ich über ein befehl von meinen PC(RS232) an
den mikrocontroller schicke und er dann die Leds ändert.
Also ich fasse zusammen
Ich habe auf mein PC eine Bedienoberfläche mit der kann ich mir eine
Ablauffolge zusammenstellen für die LEDs.
Die Ablauffolge schicke ich dann per RS232 zum Atmega.
Der soll die Ablauffolge speichern und schon leuchten die LEDs. Wie
würdet ihr dort rangehen?
Mein Quelltext bis jetzt liegt bei(nur für mikrocontroller)
durch den Compiler gebracht?
Das kann der niemals akzeptiert haben.
Led_Senden will die Adresse eines kompletten led_nr Objektes haben.
led_1 wäre so ein Objekt. Aber led_1.Rot ist kein derartiges Objekt.
led1_.Rot ist ein einzelner uint8_t, aber kein komplettes led_nr Objekt
(BTW: wofür steht das nr in led_nr? Wenn es das steht, wofür ich es
halte, dann ist das ein ziemlich schlecht gewählter Strukturname. Du
solltest dir wirklich mehr Gedanken über die Benamung von Dingen machen.
Wofür steht denn deine Struktur, was fasst sie zusammen, was könnte man
als Überbegriff für diese Zusammenfassung nehmen?
wenn du eine Struktur hast
1
struct.....
2
{
3
uint8_tTag;
4
uint8_tMonat;
5
uint16_tJahr;
6
};
was ist dann ein vernünftiger Überbegriff für diese Zusammenfassung von
3 Werten. Nun, die 3 Werte sind Tag, Monat, Jahr und der landläufige
Überbegriff dafür ist ein 'Datum'. So wie in 'Geburtsdatum'. Der Begriff
'Datum' steht automatisch für die Zusammenfassung der 3 Werte. Ein
Geburtsdatum besteht aus einem Tag, einem Monat und einem Jahr.
Was wäre ein sinnvoller Überbegriff für eine Zusammenfassung der Werte
für Rot, Grün und Blau. Was beschreibt denn die Gesamtheit dieser Werte?
Nun, das was damit beschrieben wird, ist ja wohl eine Farbe (die
nebenbei bemerkt noch nicht einmal von einer LED abhängt. Auf einem
Monitor könnte man die Farbe eines Pixels mit genau den gleichen Werten
Rot, Grün und Blau beschreiben.)
In deinem jetzigen Programm ist eine Fehlbenamung noch nicht so
tragisch, weil das Programm noch klein ist. Aber wenn es mal größer
wird, dann rächen sich solche Dinge, weil der Code dann plötzlich
anfängt unlogisch zu wirken bzw. man dauernd um die Ecke denken muss, um
die Fehlbenamung im Kopf auszugleichen. Klar, man kann auf einem
Bauernhof auch zu einer Kuh Pferd sagen und zum Schwein Gans, während
man ein Huhn als Ziege und zur Ziege Kuh sagt. Mit genügend Achtsamkeit
und durch mitdenken kann man das alles gedanklich auseinander halten.
Aber einfacher ist es, wenn man einfach die korrekten üblichen
Bezeichnungen benutzt.
Einschub Ende)
> Also wenn ich ein Wert ändern will muss ich trotzdem alle Leds ansprechen.
Gut. Du brauchst also etwas, wo du nicht nur die Farbe einer Led
speichern kannst, sondern die Farbe von zb 6 Led.
Ein Array kann das ganz leicht.
1
#define RGB_Leds 6
2
3
structled_nrmeineLeds[RGB_Leds];
und schon hast du 6 Farb-Objekte, von denen jedes einen
Beschreibungssatz einer Farbe (bestehend aus Rot, Grün, Blau) speichern
kann.
1
meineLeds sind alle 6 FarbObjekte
2
meineLeds[2] wäre ein einzelnes komplettes Farbobjekt und zwar das 3.te
3
&meineLeds[2] ist die Adresse dieses einzelnen Objektes
4
meineLeds[2].Rot ist der Rot Anteil, des 3.ten Farbobjektes im Array
5
....
Man kann aus allem Arrays bilden. Aus int, aus long, aus char, aus
uint8_t. Und selbstverständlich auch aus Strukturen.
Und dann wird es natürlich vernünftig sein, sich eine Funktion zu
machen, die alle 6 Farben an die Led ausgibt. Denn wie du korrekt
festgestellt hast, musst du immer alle 6 neu beschicken, selbst wenn
sich nur 1 Farbwert verändert.
So eine Funktion ist aber nicht weitere schwer. Du hast ja schon eine
Funktion, die eine Farbe ausgeben kann.
1
voidSendAllLed()
2
{
3
uint8_ti;
4
5
for(i=0;i<RGB_Leds;i++)
6
Led_Senden(&meineLeds[i]);
7
}
fertig. Alle definierten Farbwerte werden ausgegeben.
Ändert sich irgendwo eine oder mehrere Farben, dann rufst du SendAllLed
auf und alle LED werden auf den neuesten Stand gebracht.
vielen dank erstmal für eure Unterstützung.
Habe den Quellcode jetzt abgeändert aber leider kommt immer nur Mist
Raus.
Im Anhang ist jetzt der Quellcode den ich aktuell auf den Atmega habe.
Der hat mir das Ergebnis gebracht was auf dem Bild vom Oszi zu sehen
ist.
Das war mein zweiter versuch.
1
voidSend_All_LED()
2
{
3
for(uint8_ti=0;i<Anzahl_Leds;i++)
4
{
5
Spi_Master_Send(&RGB_LED[i].Rot);
6
Spi_Master_Send(&RGB_LED[i].Gruen);
7
Spi_Master_Send(&RGB_LED[i].Blau);
8
}
9
10
_delay_us(600);
11
}
Aber auf dem Oszi keine veränderung.
Ich habe sicherheitshalber alle werte der LEDs auf 0 gesetzt. Da müsste
das Bild auf dem Oszi doch anders aussehen.
D1 vom Oszi Bild müsste doch eine gerade Linie sein.
Gruss Mathias
Mir ist noch was aufgefallen die 600µS pause werden leider nicht
eingehalten es sind nur 80µS habe die FUSE bits ausgelesen und die
stehen auf Intern 8MHZ.
Die CPU Frequenz habe ich auch mit 8MHz angegeben.
Vielen dank
Mathias
> Mir ist noch was aufgefallen die 600µS pause werden leider> nicht eingehalten es sind nur 80µS habe die FUSE bits ausgelesen> und die stehen auf Intern 8MHZ.> Die CPU Frequenz habe ich auch mit 8MHz angegeben.
So, so. Wo genau in LED.c hast du das denn gemacht? Wo steht da (oder in
einem h-File welches vo LED.c includiert wird), dass die Taktfrequenz 8
Mhz ist? Genau, es steht nirgends!
Dass es in Goldenes_Roessel.c drinnen steht ist schön. Interessiert aber
nicht, wenn LED.c compililert wird. Jedes C-File wird für sich selbst
und unabhängig von allen anderen compiliert!
Ein schönes Chaos hast du da mit deinen Includes veranstaltet. Kein
Wunder dass du den Überblick verlierst. Jedes File, egal ob C oder H
File includiert nur das, was es für sich selbst benötigt!
Benötigt LED.h
1
/*
2
* LED.h
3
*
4
* Created: 26.05.2014 20:16:22
5
* Author: Mathias Gronert
6
*/
7
8
#include<avr/io.h>
9
#include<util/delay.h>
10
#include"SPI.h"
11
12
#ifndef LED_H_
13
#define LED_H_
14
15
//anzahl RGB_LEDs
16
#define Anzahl_Leds 5
17
18
typedefstruct
19
{
20
uint8_tRot;
21
uint8_tGruen;
22
uint8_tBlau;
23
}Farbe;
24
25
FarbeRGB_LED[Anzahl_Leds];
26
27
voidSend_All_LED();
28
29
#endif /* LED_H_ */
die spi.h? Sieh dir das File an. Kommt da drinnen irgendetwas vor, was
in spi.h steht? Nein. Also braucht auch led.h die spi.h nicht zu
inkludieren. Das led.c die spi.h braucht ist eine andere Geschichte.
Wenn led.c die spi.h braucht (um den Protoypen für die Send Funktion zu
kriegen), dann soll led.c gefälligst selbst den Include machen. Genauso
mit dem include für delay. Siehst du in led.h irgendwo einen delay?
Nein? Ich auch nicht. Also hat dieser include da nichts verloren.
wieder: wenn led.c einen delay aufrufen will, dann soll led.c gefälligst
selbst den entsprechenden Include machen.
Und wieder muss ich mich wundern, wie du das hier
1
Spi_Master_Send(&RGB_LED[i].Rot);
durch den Compiler gebracht hast. Das müsste eigentlich einen dicken,
fetten Error geben, weil eine Adresse nun mal kein char ist,
Spi_Master_Send aber laut
1
voidSpi_Master_Send(chardata);
einen haben will.
Wieso eigentlich char? Der korrekte Datentyp für ein Byte ist ein
'unsigned char' oder ein 'uint8_t', aber kein char. char hebst du dir
für alles was im Zusammenhang mit Textverarbeitung steht auf. Selbst
dann, wenn auf deinem System ein char automatisch unsigned ist. Es gibt
3(!) kleine Datentypen:
1
char für alles im Zusammenhang mit Text
2
signed char (int8_t) für kleine Zahlen mit Vorzeichen
3
unsigned char (uint8_t) für kleine Zahlenbereiche ohne Vorzeichen,
4
vulgo Byte genannt
halte dich an diese Unterscheidung und du hast weniger Probleme.
ersteinmal möchte ich mich bedanke für die viele Hilfe die ich hier
bekomme.
Ich lerne sehr viel gerade über Zeiger und überhaupt aufbau von c
Programmen vielen dank dafür.
Leider bin ich mit mein Problem immer noch nicht weiter.
Wenn ich das jetzt richtig verstanden habe mache ich folgendes gerade in
meiner Send_All_Led() Funktion.
1
voidSend_All_LED()
2
{
3
for(uint8_ti=0;i<Anzahl_Leds;i++)
4
{
5
//Ich deklariere einen Zeiger der auf ein uint8_t zeigt.
6
uint8_t*pdata;
7
//Hier weise ich den Zeiger die Adresse von RGB_LED Rot zu.
8
pdata=&RGB_LED[i].Rot;
9
//Hier übergebe ich den inhalt
10
//von der Adresse an Spi_Master
11
Spi_Master_Send(*pdata);
12
pdata=&RGB_LED[i].Gruen;
13
Spi_Master_Send(*pdata);
14
pdata=&RGB_LED[i].Blau;
15
Spi_Master_Send(*pdata);
16
}
17
18
_delay_us(600);
19
}
Ich hoffe das ich das so richtig verstanden habe.
Das Timming funktioniert auch noch nicht also die 600µS sind immer noch
keine 600µS.
Die Daten die SPI ausgiebt sind leider auch nicht die die ich erwarte.
Erwartet werden von mir alles auf 0.
Vielen dank
Mathias
Mathias G. schrieb:> ersteinmal möchte ich mich bedanke für die viele Hilfe die ich hier> bekomme.> Ich lerne sehr viel gerade über Zeiger
Ja.
Aber du machst dir selbst das Leben schwer, indem du unbedingt und um
jeden Preis einen Zeiger an Stellen einbauen willst, an denen du
überhaupt keinen brauchst!
>
1
>
2
>voidSend_All_LED()
3
>{
4
>for(uint8_ti=0;i<Anzahl_Leds;i++)
5
>{
6
>//Ich deklariere einen Zeiger der auf ein uint8_t zeigt.
7
>uint8_t*pdata;
8
>//Hier weise ich den Zeiger die Adresse von RGB_LED Rot zu.
9
>pdata=&RGB_LED[i].Rot;
10
>//Hier übergebe ich den inhalt
11
>//von der Adresse an Spi_Master
12
>Spi_Master_Send(*pdata);
13
>
Spi_Master_Send will ein Byte haben. Und zwar direkt. Als Zahlenwert!
Du könntest also aufrufen
1
Spi_Master_Send(97);
und die Funktion gibt eine 97 aus.
Du brauchst hier keine Adresse, kein gar nichts. Du übergibst einfach
nur den Zahlenwert, den du ausgegeben haben willst. Fertig.
Was ist bei dir der Zahlenwert?
Na zum beispiel der Rot-Wert der i-ten Led
1
...
2
for(uint8_ti=0;i<Anzahl_Leds;i++)
3
{
4
Spi_Master_Send(RGB_LED[i].Rot);
5
...
RGB_LED[i].Rot IST bereits der Zahlenwert, den du ausgeben willst.
Ich hab dir doch extra weiter oben eine Tabelle mit der Syntax
hingeschrieben, und wie sie jeweils zu lesen ist. Nicht gesehen?
Mathias G. schrieb:> Das Timming funktioniert auch noch nicht also die 600µS sind immer noch> keine 600µS.
Dann solltest du dich da mal als erstes darum kümmern
1
#define F_CPU 8000000UL
2
3
#include<avr/io.h>
4
#include<util/delay.h>
5
6
#define TEST_DDR DDRB
7
#define TEST_PORT PORTB
8
#define TEST_PIN PB2
9
10
intmain()
11
{
12
TEST_DDR|=(1<<TEST_PIN);
13
14
while(1){
15
TEST_PORT|=(1<<TEST_PIN);
16
_delay_ms(2000);
17
TEST_PORT&=~(1<<TEST_PIN);
18
_delay_ms(2000);
19
}
20
}
ist der Ausgang (bei den defines entsprechende Werte einsetzen, so dass
du dort mit einer LED oder mit einem Voltmeter messen kannst, LED ist
besser) 2 Sekunden auf High und 2 Sekunden auf Low oder ist er es nicht.
Wenn er es nicht ist, dann läuft dein µc nicht mit 8Mhz und du musst dir
nochmal die Fuses ansehen.
So habe dein Programm ausgeführt und getestet das ergebnis in den anhang
eingefügt. Also ich sage mal das der Takt stimmt.
Was könnte es sein das mein anderes Programm falsches Timming hat?
Habe den Quellcode jetzt so abgeändert.
1
voidSend_All_LED()
2
{
3
for(uint8_ti=0;i<Anzahl_Leds;i++)
4
{
5
Spi_Master_Send(RGB_LED[i].Rot);
6
Spi_Master_Send(RGB_LED[i].Gruen);
7
Spi_Master_Send(RGB_LED[i].Blau);
8
}
9
10
_delay_us(600);
11
}
Ich muss die Daten doch einzel an Spi_Master_Send Senden. Wenn ich das
so machen würde:
Spi_Master_Send(RGB_LED[i]);
Schickt er doch 3 mal uint8_t an Spi_Master_Send.
Spi_Master_Send erwartet aber nur 1 mal uint8_t.
Sehe ich das falsch?
Vielen dank
Mathias
Mathias G. schrieb:> So habe dein Programm ausgeführt und getestet das ergebnis in den anhang> eingefügt. Also ich sage mal das der Takt stimmt.
So recht und schlecht.
Das sind auch nicht ganz 2 Sekunden.
Aber das war zu erwarten. Der interne Takt ist eben nicht der genaueste.
Er ist ca. 8Mhz. Mit der Betonung auf zirka.
> Habe den Quellcode jetzt so abgeändert.
in led.c fehlt der include für spi.h
Hat dein dein Compiler nichts gesagt, dass die Funktion Spi_Master_Send
nicht bekannt ist, als er led.c compiliert hat? Du solltest solche
Warnungen ernst nehmen
> Ich muss die Daten doch einzel an Spi_Master_Send Senden.
Ja natürlich.
1 Aufruf von Spi_Master_Send sorgt für die Ausgabe 1-nes Wertes. Du
willst 3 Werte ausgeben: Rot, Grün, Blau. Also müssen es auch 3 Aufrufe
von SPI_Master_Send sein. Welchen Teil davon verstehst du nicht?
> Wenn ich das> so machen würde:>> Spi_Master_Send(RGB_LED[i]);
... und du spi.h includiert hättest, würde das eine schöne Fehlermeldung
ergeben
Spi_Master_Send hat in der Argumentliste stehen, dass es 1-nen uint8_t
als Argument übernimmt. RGB_LED[i] ist aber kein uint8_t. RGB_LED[i] ist
ein Element aus dem Array und als solches ein 'struct Farbe' Objekt.
Welchen Teil davon verstehst du nicht?
Datentypen sind doch nicht dazu da, dass der Platz irgendwie angefüllt
wird!
Vielen dank für eure hilfe.
Jetzt funktioniert alles. Stehe aber schon vor meiner nächsten aufgabe.
Jetzt möchte ich natürlich die LEDs gezielt dimmen.
Meine gedanke waren dazu.
Ich gebe einen Startwert, Endwert und die zeit die brauch von Start zum
Endwert vor.
Kleines Beispiel:
Led[2].Rot = 50 //Startwert
Led[2].Rot = 100 //Endwert
500ms //Zeit
von diesen dimmen Sollen die anderen LEDs unbeeinflust weiter leuchten.
Im besten fall sollen mehrere LEDs gleichzeitig gedimmt werden.
Alles was bei mir bis jetzt rauskommt ist eine ewig lange liste mit
übergaben.
z.B.:
das ist doch nicht das gelbe vom Ei oder?
Ich müsster der Funktion auch noch übergeben welche Farbe jetzt gedimmt
werden soll. Die Liste wird ja immer länger.
Wie würdet ihr das am besten machen?
Vielen dank.
Mathias
so habe ich mir das auch schon gedacht in etwa leider weiss die Funktion
dann noch nicht welche farbe ich gedimmt werden soll.
Es sollen ja auch mehrere Farben gleichzeitig gedimmt werden.
RGB_LED[2].Rot
RGB_LED[0].Blau
RGB_LED[0].Gruen
und die sollen alle gleichzeitig gedimmt werde.
Gruß
Mathias
Mathias G. schrieb:> so habe ich mir das auch schon gedacht in etwa leider weiss die Funktion> dann noch nicht welche farbe ich gedimmt werden soll.
Mit "start" wird festgelegt, bei welchem Farbwert es los geht und mit
"ende", bei welchem Farbwert der Farbübergang beendet wir.
Was ist da unklar?
Alle Farbkomponenten, in denen sie sich unterscheiden, werden je nach
Differenz mehr oder weniger stark gedimmt. Und alle, die vom Wert gleich
sind, werden nicht gedimmt.