Guten Tag µC-Profis, folgendes Problem quält mich: Ich habe ein System aus zwei ATmega8515. Einer fungiert als SPI-Master, der andere als Slave. Der Master sendet ständig via SPI 8-Bit Helligkeitswerte an den Slave, welcher diese in Soft-PWM umwandeln sollte. Die Kommunikation über SPI funktioniert wunderbar. Als Soft-PWM Vorlage habe ich diesen Code benutzt (http://www.mikrocontroller.net/articles/Soft-PWM) welcher eigenständig auch super läuft. Habe den ein bisschen geändert. Wenn ich nun die beiden Controller verbinde sieht man (STK500), dass was passiert, jedoch nicht das, was ich erwarte. Die angesprochene LED blinkt/leuchtet nicht in der Helligkeit, welche übertragen wird. Ich selbst vermute, dass das ein Interrupt-Problem ist. Ich bin aber zu unerfahren, um das Problem sofort zu erkennen. Im Anhang findet Ihr den Code für den Slave. Vielleicht findet von Euch jemand den Fehler. Der Slave sollte lediglich den via SPI übertragenen Wert in ein PWM-Signal übersetzen. Vielen Dank Gruß Flo
@Flo K. (Gast) >Die angesprochene LED blinkt/leuchtet nicht in der Helligkeit, welche >übertragen wird. Kann sie auch schlecht, wen du die Daten nicht ins Array kopierst. Dein Array t1 wird bei jedem Schleifendurchlauf neu intitialisiert. Und gewöhn dir diesen Mist mit Variablendefinition mitten im Programm ab! Das ist schlicht unnötig. Variablendefinitionen gehören an den Funktionsanfang. Probier mal das.
1 | while(1) |
2 | {
|
3 | uint8_t port_tmp; |
4 | |
5 | SPI_SlaveReceive(); |
6 | |
7 | port_tmp = SPDR; |
8 | t1[0] = port_tmp; |
9 | |
10 | memcpy(pwm_setting, t1, 8); |
11 | pwm_update(); |
12 | }
|
MFG Falk
> Und gewöhn dir diesen Mist mit Variablendefinition mitten im Programm ab! > Das ist schlicht unnötig. Variablendefinitionen gehören an den Funktionsanfang. Das kann ich so nicht stehenlassen. Ich denke schon, dass es Sinn macht Variablen so "spät" als möglich zu deklarieren.
@ chester (Gast) >Das kann ich so nicht stehenlassen. Ich denke schon, dass es >Sinn macht Variablen so "spät" als möglich zu deklarieren. Sehe ich nicht so. Das bringt nur Kauderwelsch rein, z.B. die IMO unsägliche Definition der Laufvariable in for Schleifen. Igitt! Wenn man die Variablen kompakt am Funktionsanfang definiert hat man einen guten Überblick und es gibt keine Doppeldefinitionen, mit denen man sich in Blöcken etc. ins Knie schiessen kann. MFG Falk
Hallo Falk & Co., danke für die Antwort. War durchaus brauchbar. Ich habe nun den Code etwas geändert: while(1) { uint8_t port_tmp; uint8_t t1[8]; SPI_SlaveReceive(); port_tmp = SPDR; t1[0] = port_tmp; memcpy(pwm_setting, t1, 8); pwm_update(); } Noch einige Infos zu meinen Versuchen: Ich bin dran, einen DMX-Empfänger dazu zu bringen, einzelne Dantenbytes via SPI an Slaves zu senden. Der DMX-Empfang und die PWM arbeiten tadellos. Nur wenn ich einzelne Werte via SPI an den Slave sende, gibts Probleme. Wenn ich nämlich ständig den gleichen DMX-Wert empfange und diesen auch sende, ist das Ergebnis am PWM-Ausgang ein zyklisch zappelnder PWM-Pegel, der sich nicht nachvollziehen lässt. Ist das ein Timing-Problem?
> while(!(SPSR & (1<<SPIF)));
Das würde ich aus der Senderoutine rausnehmen und das Flag im
Hauptprogramm abfragen. Wenn die Hardware bereit ist und sich der
DMX-Wert geändert hat, würde ich den neuen Wert senden.
MW
Uiuiui Vielen Dank Michael. Bitte Entschuldige meine Unwissenheit, aber könntest Du mir das genauer erklären. So quasi Schritt für Schritt was da vor sich geht? Danke
In der Senderoutine wartest du, bis das Byte rausgeshiftet wurde. Während dieser Wartezeit können andere Aktionen, außer Interruptfunktionen, nicht ausgeführt werden. Also frag das SPIF im Hauptprogramm ab, ob das Byte schon geschrieben wurde. Weiterhin ist es nur µC Belastung, gleiche Werte wiederholt zu senden. Das ist nicht notwendig. Wenn du mal mehr Sklaven ansprechen willst, du einen Datenstrom von 512 Byte mit der Geschwindigkeit von 44 Wiederholungen in der Sekunde hast, wirst du froh sein um jede vermiedene Wartezeit. MW
Wenn ich Deinem Vorschlag nachgehe, sieht doch mein Programm folgendermaßen aus: ******************************************************************** int main(void) { cli(); DDRA = 0xff; //Ausgänge DMX_initialisieren(); SPI_MasterInit(); sei(); //Arbeitsschleife while(1) { DIPs_auslesen(); SPI_MasterTransmit(DMX_WERT[1]); while(!(SPSR & (1<<SPIF))); } } //Funktionen void SPI_MasterInit(void) { /* Set MOSI and SCK output, all others input */ DDRB = (1<<DDB5)|(1<<DDB4)|(1<<DDB7); /* Enable SPI, Master, set clock rate fck/16 */ SPCR = (1<<SPE)|(1<<MSTR)|(1<<DORD)|(1<<SPI2X)|(1<<SPR0); } void SPI_MasterTransmit(char cData) { /* Start transmission */ SPDR = cData; /* Wait for transmission complete */ } ******************************************************************** Das ist doch aber nichts anderes als vorher, oder? Liegt das Problem nicht vielmehr darin, dass das Hauptprogramm ständig von der Interruptroutine des DMX-Empfangs unterbrochen wird? Womöglich an ungünstigen Stellen und dadurch das Durcheinander entsteht? Oder verstehe ich das falsch. Ich müsste es irgendwie schaffen, dass ein DMX-Wert empfangen wird, dieser übergeben und gesendet und dann erst wieder ein Wert empfangen werden darf. Zeitlich sehe ich da nicht so sehr das Problem, weil der Slave nur maximalst 20 Kanäle über SPI empfangen soll. Vorschläge? Meinungen?
Was ich meinte, ist die Wartezeit ganz rauszunehmen. In etwa in main schreiben: if (SPSR & (1 << SPIF)) und dann erst senden, wenn der aktuelle DMX-Wert anders ist als der zuletzt gesendete. MW
OK! Das entspricht aber leider nicht meiner Anwendung. Im Idealfall sollten DMX-Werte empfangen werden und sofort über SPI an den Slave gesendet werden. Und das ganze ständig. D. h. ein Vektor von z. B. DMX-Kanal 1 bis 10 soll ständig empfangen und sofort gesendet werden. Egal, ob sich Werte ändern oder nicht. Dazu eine Idee?
Du sendest mit Clock/8. Das bedeutet, bei Quarz von 16 MHz sendet du mit 2 MBaud. Das ist wesentlich schneller als DMX. Dann fütter das SPDR direkt in der Empfangsroutine. Bis der nächste Uart-Int kommt, ist die Hardware mit dem Senden fertig. Finde ich aber unnötig, wiederholt die gleichen Daten zu senden. MW
@ Falk > Wenn man die Variablen kompakt am Funktionsanfang definiert hat man > einen guten Überblick und es gibt keine Doppeldefinitionen, mit denen > man sich in Blöcken etc. ins Knie schiessen kann. Der Nachteil liegt auf der Hand. Je länger die Lebensdauer einer Variable ist, umso mehr Speicher (Stack) wird statistisch benötigt. Es wird eigentlich in jedem guten Buch (zB: Scott Meyers) darauf hingewiesen, lokale Variablen so spät als möglich anzulegen. Nach deiner Argumentation wäre es dann eigentlich noch besser, ausschließlich globale Variablen zu verwenden. chester
Hallo Michael, hallo µC Gemeinde, ich habe nun den Master so weit, dass er das mach, was ich will. D. h. er empfängt acht DMX-Kanäle, sendet diese sofort via SPI zum Slave und dann wieder von Vorne. Nun stehe ich vor dem nächsten Problem: Wie bringe ich den Slave dazu, diese acht Werte zu isolieren und jeweiligen Variablen zuzuweisen, die dann die PWM-Werte darstellen oder anderweitig verwendet werden? Der verwendete Code ist dem ersten Artikel dieses Threads zu entnehmen. Es wird dabei wahrscheinlich so sein, dass es Konflikte zwischen der Empfangsroutine und dem Interrupt des Timers gibt. Kann mir jemand Tips geben, wie ich das Ganze umbauen muss? Vor allem die Arbeitsschleife? while(1) { uint8_t port_tmp; uint8_t t1[8]; SPI_SlaveReceive(); port_tmp = SPDR; t1[0] = port_tmp; memcpy(pwm_setting, t1, 8); pwm_update(); } Ich bin für jeden Tip sehr dankbar. Gruß Flo
@ chester (Gast) >Der Nachteil liegt auf der Hand. Je länger die Lebensdauer einer >Variable ist, umso mehr Speicher (Stack) wird statistisch benötigt. Ich behaupte mal ganz kess, dass ein gescheiter Compiler das allein richtig macht und optimiert, EGAL wo die Variablen in der Funktion definiert werden. >Nach deiner Argumentation wäre es dann eigentlich noch besser, >ausschließlich globale Variablen zu verwenden. Käse. Hat kein Mensch behauptet.
@ falk > Ich behaupte mal ganz kess, dass ein gescheiter Compiler das allein > richtig macht und optimiert, EGAL wo die Variablen in der Funktion > definiert werden. DAS kann ein Compiler nicht. Der Linker vergibt den Speicher... aber ich seh schon, das bringt nichts. nichts für ungut.
@ chester (Gast) >> Ich behaupte mal ganz kess, dass ein gescheiter Compiler das allein >> richtig macht und optimiert, EGAL wo die Variablen in der Funktion >> definiert werden. >DAS kann ein Compiler nicht. Der Linker vergibt den Speicher... Das meine ich nicht. Es geht NICHT um globale/lokale Variablen, sondern den Definitionspunkt INNERHALB einer Funktion, welche EINEN Scope darstellt. Also auch keine Blöcke innerhalb einer Funktion. >aber ich seh schon, das bringt nichts. nichts für ungut. Ahhhh, der Meister ist sich zu fein, um mit dem Fussvolk zu sprechen. Ich bin unwürdig . . . MFG Falk P S Wer sich selbst erhöht soll erniedrigt, und wer sich selbst erniedrigt soll erhöht werden.
@Falk Ich bin auf deiner Seite und damit auch unwürdig. Wenn ich im Code eine Variable sehe schaue ich nach oben, zum Kopf der Funktion, der Main oder des Programmes. Vorne (!) steht wie die Variable definiert ist. Keine Suche um zu wissen, ob z.B. v1&=0x1234 geht oder v1 ein char ist. Aber wer Zeit zum Suchen hat ! gruß hans
chester wrote: > @ Falk >> Wenn man die Variablen kompakt am Funktionsanfang definiert hat man >> einen guten Überblick und es gibt keine Doppeldefinitionen, mit denen >> man sich in Blöcken etc. ins Knie schiessen kann. > > Der Nachteil liegt auf der Hand. Je länger die Lebensdauer einer > Variable ist, umso mehr Speicher (Stack) wird statistisch benötigt. > Es wird eigentlich in jedem guten Buch (zB: Scott Meyers) darauf > hingewiesen, lokale Variablen so spät als möglich anzulegen. Willkommen in der Neuzeit, wo Compiler so gut optimieren, wie noch nie zu vor. Wie schon gesagt, wird der Compiler die Zeit, in der die Variable effektiv genutzt wird, erkennen und danach den Speicher einteilen. Übrigens werden (zumindest bei Architekturen mit so vielen Registern wie dem AVR) lokale Variablen kaum auf dem Stack angelegt (erst, wenn die Arbeitsregister ausgehen). Übrigens: Wenn du Recht haben würdest, warum empfiehlt man dann, möglichst eine lokale Variable für einen Zweck anzulegen und keine Sammelvariablen ala "temp" zu benutzen um da ganz verschiedene Typen von Ergebnissen drin zu speichern?
Es kann kein Compiler wissen, ob zur Laufzeit der
else-Zweig einer if-Anweisung genommen wird oder nicht.
Ist die Variable erst im else-Zweig deklariert, dann
ist sie eben nur dann existent, wenn reingehüpft wird.
Hast du viele solche Konstellationen, dann denk ich,
dass es Vorteile bringt, mehr nicht.
Ich habe mich nur gegen die generelle Aussage gewehrt:
> gewöhn dir diesen Mist mit Variablendefinition mitten im Programm ab!
Dass sich jemand dadurch emotional angegriffen fühlt,
oder sich gar unwürdig fühlt, war von mir nicht gewollt.
chester
chester wrote: > Es kann kein Compiler wissen, ob zur Laufzeit der > else-Zweig einer if-Anweisung genommen wird oder nicht. Hä? Was ist denn die Alternative zu
1 | void func(int Param1) |
2 | {
|
3 | int Bla; |
4 | |
5 | if(Param1) |
6 | Bla = 8; |
7 | else
|
8 | Bla = -4; |
9 | }
|
> Ist die Variable erst im else-Zweig deklariert, dann > ist sie eben nur dann existent, wenn reingehüpft wird. Wenn du die Variable erst im else-Zweig deklarierst, kann der if-Zweig nicht darauf zugreifen! Sprich: Du brauchst die Variable nur im else-Zweig, was den Compiler wieder die Speicheroptimierung erhöht. Du hast dir gerade selbst ins Bein geschossen. > Hast du viele solche Konstellationen, dann denk ich, > dass es Vorteile bringt, mehr nicht. Welche Konstellationen? Gib mal ein wenig Beispielcode. > Ich habe mich nur gegen die generelle Aussage gewehrt: > >> gewöhn dir diesen Mist mit Variablendefinition mitten im Programm ab! Schon klar. Trotzdem bin (auch) ich noch der Meinung, dass diese generelle Aussage Sinn macht.
z.B:
1 | if (alles_gut) |
2 | {
|
3 | led = gruen; |
4 | }
|
5 | else
|
6 | {
|
7 | failure_struct f1; |
8 | f1 . a = |
9 | f1 . b = |
10 | :
|
11 | .
|
12 | f1 . z = |
13 | print_failure(f1); |
14 | }
|
Guten Morgen zusammen, es fällt mir immer wieder auf, dass es in diesem Forum anscheinend gang und gäbe ist, dass so mancher seine Minderwertigkeitskomplexe auf der Tastatur ausleben muss. Ich habe nicht diesen Thread eröffnet, um zu erfahren wo und wann welche scheiß Variable wie definiert ist. Bitte kauft Euch Bücher in denen das Thema behandelt wird aber langweilt doch bitte nicht mit diesem Dünnschiss!!! Ich wollte mit diesem Thread von Profis Lösungen für mein Problem bekommen. Habt Ihr denn gar nichts anderes zu tun? Hier mein letzter Eintrag der eigentlich ein wenig zielführender sein sollte: ************************************************************************ ** Hallo Michael, hallo µC Gemeinde, ich habe nun den Master so weit, dass er das mach, was ich will. D. h. er empfängt acht DMX-Kanäle, sendet diese sofort via SPI zum Slave und dann wieder von Vorne. Nun stehe ich vor dem nächsten Problem: Wie bringe ich den Slave dazu, diese acht Werte zu isolieren und jeweiligen Variablen zuzuweisen, die dann die PWM-Werte darstellen oder anderweitig verwendet werden? Der verwendete Code ist dem ersten Artikel dieses Threads zu entnehmen. Es wird dabei wahrscheinlich so sein, dass es Konflikte zwischen der Empfangsroutine und dem Interrupt des Timers gibt. Kann mir jemand Tips geben, wie ich das Ganze umbauen muss? Vor allem die Arbeitsschleife? while(1) { uint8_t port_tmp; uint8_t t1[8]; SPI_SlaveReceive(); port_tmp = SPDR; t1[0] = port_tmp; memcpy(pwm_setting, t1, 8); pwm_update(); } Ich bin für jeden Tip sehr dankbar. Gruß Flo ************************************************************************ ** Und ich bitte inständig darum, dass Themenbezogene Artikel eingestellt werden. Vielen Dank Flo
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.