Hallo,
ich habe ein Programm, das auf einer Hardware mit einer
unterschiedlichen
Anzahl von LEDs laufen soll.
Ich habe eine Hardware mit 16, 32, 48, 56 und 64 LEDs, seriell
angesteuert.
(tut ja nichts zur Sache!)
Nun möchte ich nicht 5 Programme schreiben, bzw. anpassen.
Wer kann mir das mit dem #Define mal erklären?
Ich würde gerne im Header des Programms vorgeben, wieviele LEDs ich
grade habe, und dementsprechend den dafür vorgesehenen Programmteil
nutzen.
z.B.
"wenn 16 LEDs, dann 2 Byte Lauflicht"
"wenn 32 LEDs, dann 4 Byte Lauflicht"
...
...
Danke im voraus....
Gruß Toby
Vieleicht so:
Im Header:
#define LED16
oder
#define LED32
oder
#define LED64
...
Im C-File:
#ifdef LED16
blalalalalla
#endif
#ifdef LED32
lululilale
#endif
...
Oder so:
Im Header:
#define LED 16 (oder 32, oder 64 ...)
Im C-File:
if (LED == 16)
{
dumdidum
}
if (LED == 32)
{
dadidum
}
...
Der Unterschied ist, dass im ersten Beispiel eine Konstante LED16
deklariert wird, ohne ihr einen Wert zuzuordnen. Das muss auch nicht. Im
Programm wird nun abgefragt, ob diese Konstante vorhanden ist, und
entsprechend verfahren.
Im zweiten Beispiel wird die Konstante LED deklariert und ihr der Wert
16 zugeordnet. Im Programm wird nun einfach abgefragt, welcher Wert
dieser Konstante zugeordnet ist, und entsprechend verfahren. Du kannst
mit dieser Konstanten auch rechnen:
VariableX = 3 * LED; // Dann ist VariableX 3 * 16 = 48
Konstanten werden in der Regel im Header definiert und mit
Großbuchstaben geschrieben. Dadurch lassen sie sich von normalen
Variablen unterscheiden.
Zunächst mal musst du dir im klaren sein, dass
#define
nichts magisches macht.
#define
maht einfach nur eine Textersetzung.
Wenn du also vereinbarst
#define ABC 123
dann wird der Präprozessor im Quelltext deines Programmes
alle Erwähnungen von ABC durch den Text 123 ersetzen.
Aus
int main()
{
ABC = 5;
}
wird daher
int main()
{
123 = 5;
}
und erst dieser Quelltext wird durch den eigentlichen Compiler
gejagt.
Nun gibt es auch Möglichkeiten mittels solcher Präprozessor-
Anweisungen einen Teil des Quelletxtes überhaupt ruaszuschmeissen
bzw. zu inkludieren, wenn ein bestimmte Bedingungen gelten.
Eine Bedingung könnte zb. sein, ob es ein bestimmes #define
überhaupt gibt:
#define KALLE 1
int main()
{
#ifdef KALLE
printf( "Dies ist ein Test\n" );
#else
printf( "Das erste Programm\n" );
#endif
}
Wieder: Alle Zeilen die mit # beginnen sind an den Präprozessor
addressiert, der sich den Quelltext vornimmt und eventuell ver-
ändert bevor ihn der eigentliche Compiler zu Gesicht kriegt.
(Der Präprozessor ist nichts anderes als ein Texteditor, der
genialerweise seine Anweisungen aus dem Text entnimmt, den
er bearbeitet)
Im gegenständlichen Fall geht der Präprozessor durch den
Text
#define KALLE 1
er merkt sich, dass er den Text KALLE durch den Text 1 ersetzen
muss. Er merkt sich aber auch, dass es ein Makro namens KALLE
gibt.
int main()
Da macht der Präprozessor gar nichts
#ifdef KALLE
Aha. Eine Anweisung an den Präprozessor. Welche? ifdef oder
ausgesprochen: "Wenn es ein #define gibt, welches KALLE hies"
Nun so ein #define gibt es. Es war ein paar Zeilen weiter oben
und der Präprozessor hat sich gemerkt das es das gab.
Also macht der Präprozessor weiter und inkludiert den
weiteren Quelltext in die Ausgabe:
printf( "Dies ist ein Test\n" );
Danach stösst der Präprozessor auf das
#else
Damit ist der #ifdef Teil erledigt und da der #ifdef genommen
wurde, wird der #else Teil nicht in die Ausgabe übernommen.
Der weitere Text bis zum
#endif
entfällt also.
Damit baut der Präprozessor für den Compiler folgenden
Quelltext zusammen:
int main()
{
printf( "Dies ist ein Test\n" );
}
und der übersetzt ihn dann.
Würde ich das
#ifdef KALLE 1
auskommentieren
/* #define KALLE 1 */
int main()
{
#ifdef KALLE
printf( "Dies ist ein Test\n" );
#else
printf( "Das erste Programm\n" );
#endif
}
dann würde der Präprozessor beim #ifdef KALLE kein Makro namens
KALLE gefunden haben und er würde den Text aus dem #else Teil
einbauen.
int main()
{
printf( "Das erste Programm\n" );
}
Das ganze geht aber auch noch weiter. #ifdef hat nur abgefragt
ob ein bestimmtes Makro existiert. Für #ifdef macht es keinen
Unterschied ob das nun so
#define KALLE 1
oder so
#define KALLE irgendwas
oder gar so
#define KALLE
definiert wurde. #ifdef kümmert sich nur darum, ob das Makro
existiert.
Mittels #if hingegen, kann man gezielt auch nach Werten abfragen
int main()
{
#if KALLE == 1
printf( "Das war eine 1\n" );
#elif KALLE == 2
printf( "Das war eine 2\n" );
#else
printf( "Keine Ahnung\n" );
#endif
}
stellt du dem ein
#define KALLE 1
voran, dann baut der Präprozessor diesen Code daraus
int main()
{
printf( "Das war eine 1\n" );
}
lautet das Makro aber
#define KALLE 2
so erzeugt der Präprozessor
int main()
{
printf( "Das war eine 2\n" );
}
und in allen anderen Fällen macht er
int main()
{
printf( "Keine Ahnung\n" );
}
daraus.
Hallo,
danke dafür.
Aber ehe ich es Falsch verstehe,
wenn ich jetzt z.B. 16 LEDs definiere,
#define LED16
dann wird nur für 16 LEDs Code erzeugt,
(also nur der Code genutzt, der in
#ifdef LED16
blalalalalla
#endif
steht)
nicht für die anderen, ja?
Gruß Toby
Tobias Tezlaff wrote:
> Hallo,>> danke dafür.>> Aber ehe ich es Falsch verstehe,> wenn ich jetzt z.B. 16 LEDs definiere,>> #define LED16>> dann wird nur für 16 LEDs Code erzeugt,> (also nur der Code genutzt, der in>> #ifdef LED16> blalalalalla> #endif>> steht)
ganz genau.
Der WItz in C ist es, dass du den Quelltext vor dem Compilieren
automatisch bearbeiten lassen kannst. Bearbeiten heist bei
#ifdef, dass Quelltextteile auch rausfliegen können bevor
sie der eigentliche Compiler sieht.
> nicht für die anderen, ja?>
Das hängt davon ob, wie deren Bedingungen lauten.
Im obigen wird der Quelltext
blablablabla
genau dann mitcompiliert, wenn LED16 definiert ist.
Über anderen Code sagt das nichts aus.
@GAst:
> ...dass im ersten Beispiel eine Konstante LED16 deklariert wird,...
#define deklariert keine Konstante und auch nichts anderes. Mit #define
erzeugt man ein Präprozessor-Makro, und das ist nichts anderes als ein
Platzhalter für das, was hinter dem Bezeichner steht. Es handelt sich um
eine reine Textersetzung, die lediglich dazu dient, den Schreibaufwand
zu reduzieren und die Übersichtlichkeit des Codes zu erhöhen. Der
Präprozessor ersetzt beim Durchlaufen alle definierten Makros mit dem
dazugehörigen Text. Wie in C Konstanten deklariert werden steht auf
einem anderen Blatt und hat mit der Fragestellung hier nichts zu tun.
Das nur der Vollständigkeit halber... Ansonsten hat Karl Heinz ja schon
alles gesagt.
Das ist zwar alles richtig, was bisher gesagt wurde, aber trotzdem
unklar.
#ifdef LED16
blalalalalla
#endif
#ifdef LED32
lululilale
#endif
führt schnell dazu, daß du fünf Programme in einem C-file schreibst,
dazu aber noch ineinander verschachtelt. Das gibt nur Durcheinander, und
führt zu Fehlern. Das must du am Ende fünfmal kompilieren, fünfmal
debuggen, und das ergibt garantiert fünf mal fünf Ärger.
Sinnvoll ist so etwas:
1
#define ANZAHL_LEDS 16 // hier trägst du die Anzhal der LEDs ein
2
3
#define LAUF_BITS ((ANZAHL_LEDS)/4)) // nur so als Beispiel
4
5
...
6
7
for(inti=0;i<ANZAHL_LEDS;i++)
8
...
EIN Programm, mit parametrierbaren Konstanten. Und davon möglichst
wenig.
Oliver
Oliver wrote:
> EIN Programm, mit parametrierbaren Konstanten. Und davon möglichst> wenig.
Da hast du grundsätzlich schon recht.
Nur so einfach geht das meist nicht.
Denn: Beim Übergang von bsp. 8 Led auf 16 Led muss
beispielsweise ein 2-ter Port initialisiert werden.
Das kriegst du anders als mit #ifdef nicht hin.
#define LEDS 16
int main()
{
// wenn nur 8 Leds benutzt werden, spielt sich alles am
// Port B ab, von 8 bis 16 Leds an den Ports B und D
// 24 Leds mach ich an den Ports B, D und C
DDRB =0xFF; // für 8 Led
#if LEDS > 8
DDRD = 0xFF;
#endif
#if LEDS > 16
DDRC = 0xFF;
#endif
....
Auch für die Aufteilung der Lauflichtbits wird man um ein
paar #if nicht herumkommen.
In der Praxis wird es wohl auf eine Kombination aus beiden
Techniken hinauslaufen:
Nach Möglichkeit alles in Formeln packen, die mittels ein
paar Makros parametriert werden. Wo das nicht geht, muss
man auf #if ausweichen.
> #define LEDS 16>> int main()> {> // wenn nur 8 Leds benutzt werden, spielt sich alles am> // Port B ab, von 8 bis 16 Leds an den Ports B und D> // 24 Leds mach ich an den Ports B, D und A>> DDRB =0xFF; // für 8 Led> #if LEDS > 8> DDRD = 0xFF;> #endif> #if LEDS > 16> DDRA = 0xFF;> #endif>> ....>> Auch für die Aufteilung der Lauflichtbits wird man um ein> paar #if nicht herumkommen.
Zur Verdeutlichung:
Warum nicht einfach so:
DDRB = 0xFF;
if( LEDS > 8 )
DDRD = 0xFF;
if( LEDS > 16 )
DDRA = 0xFF;
Auf einem Mega8 gibt es keinen PORT A. Damit ist aber
DDRA = 0xFF;
ein schöner Syntaxfehler :-)
Hallo,
ich habe nun meinen ersten Test hinter mir.
Im Main sende ich per UARt eine "Kennun" der Hardware.
// Definition der LED Anzahl
#define ANZAHL_LEDS 48
im Main:
#if ANZAHL_LEDS == 16
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('1');
TxDatenSenden('6');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#elif ANZAHL_LEDS == 32
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('3');
TxDatenSenden('2');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#elif ANZAHL_LEDS == 40
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('4');
TxDatenSenden('0');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#elif ANZAHL_LEDS == 48
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('4');
TxDatenSenden('8');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#elif ANZAHL_LEDS == 56
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('5');
TxDatenSenden('6');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#elif ANZAHL_LEDS == 64
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('6');
TxDatenSenden('4');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#else
TxDatenSenden('N');
TxDatenSenden('V');
TxDatenSenden('0');
TxDatenSenden('0');
TxDatenSenden('S');
TxDatenSenden('/');
TxDatenSenden('W');
TxDatenSenden(10); //Vorschub
TxDatenSenden(13); //Rücklauf
#endif
Geht so weit wirklich gut!
Nun habe ich allerdings 6 einzelne Programme in einem Großen.
Da gebe ich Oliver Recht, das es schnell unübersichtlich wird.
Vorallem, da es nicht nur ein Lauflicht ist.
Ich nutze einen externen EEProm, in dem Biler gespeichert werden.
Die LED Reihe dreht sich, wie ein Propeller Uhr.
Nun muß ich ja alle Routinen, wie z.B. das EEProm lesen/schreiben
sechs mal schreiben, und zwar für jede LED Anzahl eine eigene,
diese mit dem #elif von einander getrennt.
(Dumm Ausgedrückt ! Ich hoffe ihr versteht mich)
So eine EEProm Routine sieht so aus:
void Write_SPI_EEProm (void){
BYTE HighAdress = 0;
BYTE LowAdress = 0;
BYTE Daten1 = 0;
BYTE Daten2 = 0;
BYTE Daten3 = 0;
BYTE Daten4 = 0;
BYTE Daten5 = 0;
BYTE Daten6 = 0;
BYTE Daten7 = 0;
BYTE Daten8 = 0;
//BYTE status = 0;
//LED Rot an
sbi(PORTD, 7);
while(RxBufferStatus()==0);
myReceivedByte = RxBufferLesen();
if(myReceivedByte==':'){
while(RxBufferStatus()==0);
HighAdress = RxBufferLesen();
while(RxBufferStatus()==0);
LowAdress = RxBufferLesen();
while(RxBufferStatus()==0);
Daten1 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten2 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten3 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten4 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten5 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten6 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten7 = RxBufferLesen();
while(RxBufferStatus()==0);
Daten8 = RxBufferLesen();
//status = Read_EEProm_Status();
//if ( status == 0b00000000 ){
//while(Read_EEProm_Status()!=0);
cbi(PORTB,0);
spiTransferByte(0b00000110);//write enable WREN
sbi(PORTB,0);
cbi(PORTB,0);
spiTransferByte(0b00000010);//write command
spiTransferByte(HighAdress);//high adresse
spiTransferByte(LowAdress); //low adresse
spiTransferByte(Daten1); //data
spiTransferByte(Daten2); //data
spiTransferByte(Daten3); //data
spiTransferByte(Daten4); //data
spiTransferByte(Daten5); //data
spiTransferByte(Daten6); //data
spiTransferByte(Daten7); //data
spiTransferByte(Daten8); //data
sbi(PORTB,0);
while(RxBufferStatus()==0);
myReceivedByte = RxBufferLesen();
if(myReceivedByte==';'){
//Bestätigung schicken
TxDatenSenden('O');
}
}
//LED Rot aus
cbi(PORTD, 7);
}
Hier bschreibe ich den EEProm mit den per UART Empfangenen Bytes.
Wenn ich das alles 6 mal schreiben muß, wird es doch ganz schön
unübersichtlich, nicht?
Das sollte doch besser in eine Funktion gehen, in der Man die LED Azahl
durch 8 teilt.
ann habe ich zumindest schon mal die byte Anzahl, die ich im EEProm
speichern muß/will.
Gruß Toby
Tobias Tezlaff wrote:
> Hallo,>> ich habe nun meinen ersten Test hinter mir.> Im Main sende ich per UARt eine "Kennun" der Hardware.>> // Definition der LED Anzahl> #define ANZAHL_LEDS 48>> im Main:>> #if ANZAHL_LEDS == 16> TxDatenSenden('N');
[Snip]
> TxDatenSenden(10); //Vorschub> TxDatenSenden(13); //Rücklauf> #endif>> Geht so weit wirklich gut!>> Nun habe ich allerdings 6 einzelne Programme in einem Großen.> Da gebe ich Oliver Recht, das es schnell unübersichtlich wird.
Kein Wunder.
Mann. Du musst dir Hilfsfunktionen bauen:
void TxStringSenden( char * String )
{
while( *String )
TxDatenSenden( *String++ );
}
und in main() dann
#if ANZAHL_LEDS == 16
TxStringSenden( "NV16S/W\r\n" );
#elif ANZAHL_LEDS == 32
TxStringSenden( "NV32S/W\r\n" );
#elif ANZAHL_LEDS == 40
TxStringSenden( "NV40S/W\r\n" );
#elif ANZAHL_LEDS == 48
TxStringSenden( "NV48S/W\r\n" );
#elif ANZAHL_LEDS == 56
TxStringSenden( "NV56S/W\r\n" );
#elif ANZAHL_LEDS == 64
TxStringSenden( "NV64S/W\r\n" );
#else
TxStringSenden( "NV00S/W\r\n" );
#endif
Schon besser. Aber wenn ich mir die Strings so anschaue,
dann sind die alle nach dem gleichen Muster aufgebaut:
Zuerst kommt ein "NV", dann die Anzahl der Leds, gefolgt
von dem String "S/W\r\n"
D.h. wenn ich die Anzahl der LED als Zahl habe, dann mach
ich flugs daraus einen String, setzte "NV" davor und
"S/W\r\n" hinten dran und habe den String fertig zur Ausgabe:
* Wenn sprintf kein Problem ist, dann zb so:
sprintf( Buffer, "NV%02dS/W\r\n", ANZAHL_LEDS );
TxStringSenden( Buffer );
* Falls sprintf keine gute Idee ist:
TxStringSenden( "NV" );
itoa( Buffer, ANZAHL_LEDS,10 );
TxStringSenden( Buffer );
TxStringSenden( "S/W\r\n" );
* Falls es kein Problem ist dass der #else Fall nicht
richtig behandelt wird:
#define Stringize(x) #x
TxSTringSenden( "NV" Stringize(ANZAHL_LEDS) "S/W\r\n" );
Wodurch dein ganzer 50-Zeiler in nur einer Zeile unterkommt.
> Wenn ich das alles 6 mal schreiben muß, wird es doch ganz schön> unübersichtlich, nicht?
Du musst dir gemeinsame Teile suchen und in eigene Funktionen
auslagern. Oder gemeinsame Teile in Formeln beschreiben, in die
deine Kennzahlen eingehen.
Ohne Nachzudenken einfach ein paar #if und #define
einzubauen ist genau der Weg, den Oliver (zu Recht)
bekrittelt hat.
Karl heinz Buchegger wrote:
>> #define Stringize(x) #x>> TxSTringSenden( "NV" Stringize(ANZAHL_LEDS) "S/W\r\n" );>
Falls du dich frägst wie das funktioniert:
Das benutzt den sog. 'Stringize' Operator # in einem Makro.
Der Präprozessor bau beim Stringizen (also für das #x) einfach
nur Gänsefüschen rund um das Argument.
Aus
"NV" Stringize(ANZAHL_LEDS) "S/W\r\n"
wird durch die erste Makro Substitution
(ANZAHL_LEDS ersetzeN)
"NV" Stringize(32) "S/W\r\n"
Dann wird das Stringize Makro evaluiert, dass durch den #
erzwingt, dass das ganze umgeformt wird zu
"NV" "32" "S/W\r\n"
und zu guter letzt ist der Compiler noch verpflichtet, String
Konstanten die direkt aufeinanderfoglen zu einer einzigen
zusammenzufassen:
"NV32S/W\r\n"
e voila.
Du hättest das ganze auch so machen können:
TxStringSenden(
#if ANZAHL_LEDS == 16
"NV16S/W\r\n"
#elif ANZAHL_LEDS == 32
"NV32S/W\r\n"
#elif ANZAHL_LEDS == 40
"NV40S/W\r\n"
#elif ANZAHL_LEDS == 48
"NV48S/W\r\n"
#elif ANZAHL_LEDS == 56
"NV56S/W\r\n"
#elif ANZAHL_LEDS == 64
"NV64S/W\r\n"
#else
"NV00S/W\r\n"
#endif
);
Denk immer daran: Der Präprozesser ist eine reine Textverarbeitungs-
maschinerie. Den kümmern C Anweisungen oder deren Grenzen oder
Klammern oder ; herzlich wenig. Das Einzige ist: Aus Strings
hält er sich raus:
#define ABC 123
int main()
{
printf( "ABC" );
}
das druckt wirklich ABC, und nicht 123.
>>> Wenn ich das alles 6 mal schreiben muß, wird es doch ganz schön>> unübersichtlich, nicht?>> Du musst dir gemeinsame Teile suchen und in eigene Funktionen> auslagern. Ohne Nachzudenken einfach ein paar #if und #define> einzubauen ist genau der Weg, den Oliver (zu Recht) bekrittelt hat.
Du willst faul sein. Du willst nicht alles 6 mal schreiben
muessen. Also musst du nach Wegen suchen, wie du dieses Ziel
erreichen kannst. Die Lösung dafür heist aber so gut wie nie:
Cut&Paste
> Nun muß ich ja alle Routinen, wie z.B. das EEProm lesen/schreiben> sechs mal schreiben, und zwar für jede LED Anzahl eine eigene,> diese mit dem #elif von einander getrennt.> (Dumm Ausgedrückt ! Ich hoffe ihr versteht mich)
Warum musst du da 6 eigene Funktionen schreiben.
Der eigentliche Lesevorgang ist doch immer derselbe, nur
die Anzahl der zu lesenden Bytes verändert sich.
> void Write_SPI_EEProm (void){>> BYTE HighAdress = 0;> BYTE LowAdress = 0;> BYTE Daten1 = 0;> BYTE Daten2 = 0;> BYTE Daten3 = 0;> BYTE Daten4 = 0;> BYTE Daten5 = 0;> BYTE Daten6 = 0;> BYTE Daten7 = 0;> BYTE Daten8 = 0;
Aus diesen Datenx Variablen machst du gleich mal ein Array ...
BYTE Daten[ANZAHL_LEDS] = 0;
> //BYTE status = 0;>> //LED Rot an> sbi(PORTD, 7);>> while(RxBufferStatus()==0);
< myReceivedByte = RxBufferLesen();
> if(myReceivedByte==':'){>> while(RxBufferStatus()==0);> HighAdress = RxBufferLesen();> while(RxBufferStatus()==0);> LowAdress = RxBufferLesen();> while(RxBufferStatus()==0);> Daten1 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten2 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten3 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten4 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten5 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten6 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten7 = RxBufferLesen();> while(RxBufferStatus()==0);> Daten8 = RxBufferLesen();
... denn dann kannst du das Datenlesen sofort
in eine Schleife packen.
for( i = 0; i < ANZAHL_LEDS; ++i ) {
while(RxBufferStatus()==0);
Daten[i] = RxBufferLesen();
}
>> //status = Read_EEProm_Status();> //if ( status == 0b00000000 ){> //while(Read_EEProm_Status()!=0);> cbi(PORTB,0);> spiTransferByte(0b00000110);//write enable WREN> sbi(PORTB,0);> cbi(PORTB,0);> spiTransferByte(0b00000010);//write command> spiTransferByte(HighAdress);//high adresse> spiTransferByte(LowAdress); //low adresse
...
> spiTransferByte(Daten1); //data> spiTransferByte(Daten2); //data> spiTransferByte(Daten3); //data> spiTransferByte(Daten4); //data> spiTransferByte(Daten5); //data> spiTransferByte(Daten6); //data> spiTransferByte(Daten7); //data> spiTransferByte(Daten8); //data
... und auch hier wieder eine Schleife benutzen
for( i = 0; i < ANZAHL_LEDS; ++i )
spiTransferByte( Daten[i] );
> sbi(PORTB,0);>> while(RxBufferStatus()==0);> myReceivedByte = RxBufferLesen();> if(myReceivedByte==';'){>> //Bestätigung schicken> TxDatenSenden('O');>> }
...
und schon brauchst du wieder nur eine Funktion.
Diese Funktion wird über ANZAHL_LEDS parametrisiert.
Karl heinz Buchegger wrote:
>> #define Stringize(x) #x>>>> TxSTringSenden( "NV" Stringize(ANZAHL_LEDS) "S/W\r\n" );>>
Ah. reingefallen. (Passiert mir immer wieder :-)
Das geht so nicht.
Aber so
#define STR(x) #x
#define Stringize(x) STR(x)
TxSTringSenden( "NV" Stringize(ANZAHL_LEDS) "S/W\r\n" );
Man muss den Umweg über ein 'Zwischenmakro' gehen.
Die erste Lösung würde
NVANZAHL_LEDSS/w\r\n
erzeugen, also zuerst ANZAHL_LEDS in "" verpacken und erst
dann ANZAHL_LEDS durch die Zahl ersetzen (was aber nicht passiert,
da sich der Präprozessor aus Strings raushält).
Hallo Karl Heinz,
ich habe nun diese Hilfsfunktion eingebaut:
void TxStringSenden( char * String )
{
while( *String )
TxDatenSenden( *String++ );
}
und in main() dann
#if ANZAHL_LEDS == 16
TxStringSenden( "NV16S/W\r\n" );
#elif ANZAHL_LEDS == 32
TxStringSenden( "NV32S/W\r\n" );
#elif ANZAHL_LEDS == 40
TxStringSenden( "NV40S/W\r\n" );
#elif ANZAHL_LEDS == 48
TxStringSenden( "NV48S/W\r\n" );
#elif ANZAHL_LEDS == 56
TxStringSenden( "NV56S/W\r\n" );
#elif ANZAHL_LEDS == 64
TxStringSenden( "NV64S/W\r\n" );
#else
TxStringSenden( "NV00S/W\r\n" );
#endif
Sag mir bitte, warum soll sprintf ein Problem sein?
Verstehe es nicht so ganz, was Du damit meinst, oder was die Funktion
bewirken kann.
Werde nachher mal die Funktionen für das EEProm schreiben und lesen
verkürzen!
Gruß Toby
Hallo nochmal,
muß ich nicht hier:
Aus diesen Datenx Variablen machst du gleich mal ein Array ...
BYTE Daten[ANZAHL_LEDS] = 0;
die ANZAHL_LEDS durch 8 teilen, da die LEDs ja Bits sind, und die Daten
Bytes sind?
Bei z.B. 64 LEDs habe ich ja nur 8 Bytes, also nur 8 mal die i Schleife
durchgehen, und nicht 64!
Gruß Toby
> Sag mir bitte, warum soll sprintf ein Problem sein?
Weil es die eierlegende Wollmilchsau der Bibliotheksfunktionen
schlechthin ist. Entsprechend schleppt sie einiges an Code mit
sich herum. Wenn das für dich kein Problem ist, dann ist auch
sprintf() kein Problem. ;-)
Hallo,
danke für deine Antwort.
Leider ist mein Mega8 schon fast voll.
Es passt nichtmal mehr der Bootloader rein! ;-(
Nunja, dann werde ich die sprintf() Funktion wohl eher mal raus lassen.
Gruß Toby
Tobias Tezlaff wrote:
> Hallo nochmal,>> muß ich nicht hier:>> Aus diesen Datenx Variablen machst du gleich mal ein Array ...>> BYTE Daten[ANZAHL_LEDS] = 0;>> die ANZAHL_LEDS durch 8 teilen, da die LEDs ja Bits sind, und die Daten> Bytes sind?
Wenn das bei dir so ist, dann musst du das wohl durch 8
teilen :-)
>> Bei z.B. 64 LEDs habe ich ja nur 8 Bytes, also nur 8 mal die i Schleife> durchgehen, und nicht 64!
Klingt gut.
Mach das aber nicht so direkt im Code, sondern definiere
dir wieder ein Makro
#define ANZAHL_LEDS 16
#define ANZAHL_BYTES ( ANZAHL_LEDS / 8 )
und das benutzt du dann:
BYTE Daten[ANZAHL_BYTES] = 0;
...
for( i = 0; i < ANZAHL_BYTES; ++i )
...
Tobias Tezlaff wrote:
> Hallo,>> danke für deine Antwort.> Leider ist mein Mega8 schon fast voll.
Für ein simples Lauflicht ?!
Hast du den Optimizer vom Compiler aktiviert?
Hallo Karl Heinz,
danke zuerst.
Natürlich ist es kein simples Lauflicht!
Es ist, wie oben kurz mal erwähnt, eine Art Propeller Uhr,
nur halt mit bis zu 2mal 64 LEDs.
2mal 64 LEDs, ja, das kommt daher, da ich das Ganze in einem
Modellhubschrauber unterbringen will.
Der hat 2 Rotorblätter, in diese kommen je bis zu 64 LEDs,
einmal nach oben abstrahlend, einmal nach unten.
Nun kommt der ganze Kram der Spaltenberechnung, der
Umdrehungsberechnung,
und die 16x12 Schrift im Programmspeicher hinzu.
Gruß Toby
Tobias Tezlaff wrote:
>> Es ist, wie oben kurz mal erwähnt, eine Art Propeller Uhr,
Hab ich irgendwie überlesen :-)
> nur halt mit bis zu 2mal 64 LEDs.> 2mal 64 LEDs, ja, das kommt daher, da ich das Ganze in einem> Modellhubschrauber unterbringen will.> Der hat 2 Rotorblätter, in diese kommen je bis zu 64 LEDs,> einmal nach oben abstrahlend, einmal nach unten.
Geil.
Da ich selbst Heli fliege, interessiert mich das brennend.
Wenn du fertig bist: Gib mir bitte Nachricht!
Tobias Tezlaff wrote:
> error: invalid initializerbei dieser Zeile:> BYTE Daten[ANZAHL_BYTES] = 0;>> Dann passt doch was nicht mit dem Array.
Der Compiler beschwert sich, dass die Initialisierung
nicht stimmt.
* lass das = 0 weg.
da die Werte sowieso ausgelesen werden, wäre eine Initialisierung
auf 0 nur Zeitverschwendung.
* Da das ein Array ist, muss die Initialisierung so lauten
BYTE Daten[ANZAHL_BYTES] = { 0 };
Wie ist es denn mechanisch geplant? Also daß die LEDs nicht die
Luftströmung auf dem Blatt stören, daß die Blätter stabil bleiben und
daß sie sauber ausgetrimmt sind? Wie wird das Signal an den Rotor
übergeben?
Hallo Rolf,
ich habe LED Module mit je 8 LEDs, die weren von einer "zentralen
Steuerplatine" angesteuert.
Leider sind die Platinen etwas teuer, und aus kronischem Geldmangel
gehts nur langsam voran.
Außerdem würde ich gerne jedem Blatt einen eigenen Prozessor mit LP
spendieren.
Gruß Toby
Hier noch ein Bild der Steuerplatine.
Aus Kostengründen habe ich 240 LED Module fertigen lassen, und erstmal
25 Steerplatinen.
Im Nutzen waren die im Endeffekt günstiger, als Prototypen.
Die LED Module werden ins Blatt mit einlaminiert, die Steuerplatine soll
eine Art Rotorbremse werden.
Zum Signa habe ich 2 Möglichkeiten.
1. Ein Hallsensor im Bereich der Taumelscheibe.
2. Ein Hallsensor am Hauptzahnrad, welcher einem weiterem AVR im festen
Teil des Helis einen INT auslöst.
Dieser sendet dann ein 36KHz Signal zum IR Empfangsmodul der drehenden
Steuerplatine.
Bei der 2. Version kann ich durch auswertung eines Empfängersignals und
dadurch veränderlichen Pulslängen des IR Signals sogar noch zwischen 3
Bildern mit einem 3 Stufenschalter am FS-Sender umschalten.
Leider macht das IR Empfangsmodul noch ein paar Probleme, da anscheinend
mehr 36KHz Signale rummschwirren, wie ich mir nie hätte träumem lassen.
So bekomme ich ständig unerwartete Interups, die mich wirklich stören.
Gruß Toby
Ach, noch was,
ich habe 2 Versionen geplant.
Eine 16 LED Text Version
eine 32 bis 64 LED Grafik Version.
Beide sind auf den Bildern zu sehen.
Die Holzblätter dienen nur zum Vergleich, es sind 600er Raptor 50
Blätter.
Zur Stromversorgung kann ich nur noch sagen, es gibt ein Schaltnetzteil
auf der Steuerplatine.
Versorgt wird die Hardware aus 2x 2 350er Lipos.
Alles zum Projekt ist hier :
http://www.rc-heli.de/board/index.php?topic=57220.0
Gruß Toby
>Leider macht das IR Empfangsmodul noch ein paar Probleme, da anscheinend>mehr 36KHz Signale rummschwirren, wie ich mir nie hätte träumem lassen.>So bekomme ich ständig unerwartete Interups, die mich wirklich stören.
Genau deshalb macht man die Auswertung ja auch nicht per Interrupt, Und
36kHz-IR-Signale kommen eigentlich nur von Fernbedienungen. Solange da
keine anderen in der Nähe betätigt werden, gibt es auch keine Signale.
guggst du hier:
Beitrag "Fernbedien RC5 Empfänger"
Deine Rotor-LED-Bilder sind allerdings wirklich Klasse.
Oliver
Hallo Oliver,
ich war bei meinem Vater, der auch mit AVRs etwas macht.
Er hat mal dasEmpfangsodul an seinen Oszi gehängt.
Das Signal, die Masse und VCC waren absolut sauber.
Trotzdem gab es dort ständig Interrupts.
Bis wir die Neonröhre mal ausgeschaltet haben, (so eine Lampe, mit 2
Röhren, etwas verspiegelt).
Dann gab es keinen Interupt mehr.
Also liegt es nicht nur an IR Fernbedienungen, sondern auch an allen
anderen Lichtquellen, die sich grade so spiegeln und reflektieren,
daszufällig 36 KHz dabei raus kommen.
Des weiteren geht es bei meiner Anwendung nicht mit einem
Übertragungsprotokoll wie z.B. RC5 Code.
Habe ich schon ausprobiert, nur dauert die Empfangsroutine immer eine
gewisse Zeit.
Wenn sich mein Rotor aber schneller dreht, verschiebt sich das Bild,
wenn die Übertragung immer gleich lange dauert,
da ich mit der IR Übertragung auch den überaus wichtigen Referenzpunkt
(Nullpunkt) bei jeder Umdrehung nutze.
Gruß Toby
Hallo nochmal,
evtl. habe ich mich etwas schlecht ausgedrückt!
Ich habe mal den IR Empfänger an di UART angeschlossen, und versucht,
per IR Signal ein Byte 1,2 oder 3 damit zu übertragen.
Hat ja soweit gut geklappt.
Nur dauert bei 2400 Baud die Übertragung eines Bytes etwa 4ms.
Nun habe ich im Rotor gewartet, bis per UART eine 1,2 oder 3 angekommen
ist.
Das war dann das Zeichen dafür, das der Rotor nun bei Spalte 0 ist, also
der Referenzpunkt.
Bei einer Drehzahl von 1500 U/min waren die 4 ms etwa (ich weiß es nicht
mehr genau) 10 Grad versetzt zur eigentlichen Referenz.
Nun kann derRotor aber auch mit 2000 U/min drehen, und dann würde sich
das Bild ja wieder um einige Grad verdrehen.
Daher habe ich auf diese Weise nicht weiter gemacht.
Ich hoffe, ihr könnt meinen Gedankengängen folgen! ;-)
Gruß Toby