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
Hallo Karl Heinz, da warst Du schneller als ich schreiben konnte, danke für deine sehr ausführliche Erklärung! 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.
Nur der Vollständigkeit halber... Hast Du wohl recht und ich bin der Blödmann.
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 (int i=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
Hmmm, so'n Mist. Ich habe nun folgendes: // Definition der Led und Byte Anzahl #define ANZAHL_LEDS 48 #define ANZAHL_BYTES ( ANZAHL_LEDS / 8 ) ... void Read_SPI_EEProm (void){ BYTE HighAdress = 0; BYTE LowAdress = 0; BYTE Daten[ANZAHL_BYTES] = 0; BYTE i = 0; //LED Rot an sbi(PORTD, 7); while(RxBufferStatus()==0); myReceivedByte = RxBufferLesen(); if(myReceivedByte==':'){ while(RxBufferStatus()==0); HighAdress = RxBufferLesen(); while(RxBufferStatus()==0); LowAdress = RxBufferLesen(); cbi(PORTB,0); spiTransferByte(0b00000011); //read command spiTransferByte(HighAdress); //high adresse spiTransferByte(LowAdress); //low adresse for( i = 0; i < ANZAHL_BYTES; ++i ){ while(RxBufferStatus()==0); Daten[i] = RxBufferLesen(); } sbi(PORTB,0); while(RxBufferStatus()==0); myReceivedByte = RxBufferLesen(); if(myReceivedByte==';'){ //Daten mit "D" ankündigen, PC wartet, bis "D" kommt TxDatenSenden('D'); for( i = 0; i < ANZAHL_LEDS; ++i ) spiTransferByte( Daten[i] ); } } //LED Rot aus cbi(PORTD, 7); } Nun bekomme ich aber den Fehler: error: invalid initializerbei dieser Zeile: BYTE Daten[ANZAHL_BYTES] = 0; Dann passt doch was nicht mit dem Array. 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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.