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.
> 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
voidfunc(intParam1)
2
{
3
intBla;
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.
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