Forum: Mikrocontroller und Digitale Elektronik Habe ich einen Fehler gemacht?


von Dennis (Gast)


Lesenswert?

Hallo zusammen,

ich kenne mich mit Bitoperationen noch nicht so gut aus.
Folgendes Problem:

Über SPI sollen mit einem Atmega32 3 Integer-Variablen gesendet werden.
Damit die jeweils in das SPDR passen, habe ich folgende Operationen 
programmiert (SPI_send ist die Sendefunktion. Die funktioniert!):
1
for (i = 0; i < 4; i++)
2
{
3
 // Low-Byte senden
4
 send_SPI(((unsigned char) (control[i] & 0x00ff)));
5
 // High_Byte senden
6
 send_SPI(((unsigned char) (control[i] >> 8)));
7
}

Der Slave-Controller (ebenfalls Atmega32) geht mit dem empfangenen 
Ergebnis wie folgt um:
1
SIGNAL(SIG_SPI)
2
{
3
 // count zählt die empfangenen Bytes (0-5)
4
 letter[count] = SPDR;
5
 if (count == 5)
6
 {
7
  count = 0;
8
 }
9
}
10
11
int main()
12
{
13
 // Laufvariable auf null
14
 a = 0;
15
16
 // gesendete Abstände wieder zusammensetzen...
17
 for (i = 0; i < 6; i = i + 2)
18
 {
19
   // gesendet wurde erst Low-Byte dann High-Byte
20
   gap[a] = (((unsigned int) (letter[(i + 1)] << 8)) | ((unsigned int)  letter[i]));
21
   a++;
22
 }

Hab ich die Umwandlungen richtig gemacht?

Viele Grüße und Danke für jeden Hinweis!!!

Dennis

von Michael U. (amiga)


Lesenswert?

Hallo,

irgendwie verstehe ich Bahnhof...

SIGNAL(SIG_SPI)
{
 // count zählt die empfangenen Bytes (0-5)
 letter[count] = SPDR;
 if (count == 5)
 {
  count = 0;
 }
}

wer oder was ist count, wer ändert count und wo und warum?

Gruß aus Berlin
Michael

von Dennis (Gast)


Lesenswert?

count wird außerhalb von der Endlosschleife ein Mal auf Null gesetzt und 
ist dann dafür da, die Anzahl der empfangenen Bytes zu senden.

Da 3 Int-Werte geschickt werden, muss 6x gesendet werden, bis die SPI 
alles verschickt hat. Und count zählt durch und steuert das Schreiben 
der Werte in das Feld letter...

von Uwe .. (uwegw)


Lesenswert?

Und wann wird count hochgezählt?

von Dennis (Gast)


Lesenswert?

Ach mist,

ich habe Euch die falsche SPI-Interrupt-Service-Routine geschickt...
Der Rest ist korrekt!
1
SIGNAL(SIG_SPI)
2
{
3
 letter[count] = SPDR;
4
 SPDR = 0x44;
5
 if (count == 5)
6
 {
7
  TIMSK &= (~(1 << TOIE0));
8
 }
9
 else
10
 {
11
  count++;
12
 }
13
}

von Jean P. (fubu1000)


Lesenswert?

Dennis schrieb:
> Hallo zusammen,

Ja hallo.


> Über SPI sollen mit einem Atmega32 3 Integer-Variablen gesendet werden.
> Damit die jeweils in das SPDR passen, habe ich folgende Operationen
> programmiert (SPI_send ist die Sendefunktion. Die funktioniert!):
>
>
1
> for (i = 0; i < 4; i++)
2
> {
3
>  // Low-Byte senden
4
>  send_SPI(((unsigned char) (control[i] & 0x00ff)));
5
>  // High_Byte senden
6
>  send_SPI(((unsigned char) (control[i] >> 8)));
7
> }
8
>

Du sendest aber 4 Integer raus !


> Der Slave-Controller (ebenfalls Atmega32) geht mit dem empfangenen
> Ergebnis wie folgt um:
>
>
1
> SIGNAL(SIG_SPI)
2
> {
3
>  letter[count] = SPDR;
4
>  SPDR = 0x44;
5
>  if (count == 5)
6
>  {
7
>   TIMSK &= (~(1 << TOIE0));
8
>  }
9
>  else
10
>  {
11
>   count++;
12
>  }
13
> }
14
>

Ziemlich unklar, warum läuft da nen Timer und wofür ?


>
1
> int main()
2
> {
3
>  // Laufvariable auf null
4
>  a = 0;
5
> 
6
>  // gesendete Abstände wieder zusammensetzen...
7
>  for (i = 0; i < 6; i = i + 2)
8
>  {
9
>    // gesendet wurde erst Low-Byte dann High-Byte
10
>    gap[a] = (((unsigned int) (letter[(i + 1)] << 8)) | ((unsigned int)
11
> letter[i]));
12
>    a++;
13
>  }
14
>

Wasn dat. Das kann gar nit gehen du packst ständig irgend etwas in deine 
tolles Array gap. Zeige mal deinen ganzen aktuellen Code mit dem Mist 
kann keiner was anfangen !

Gruß

von Stefan (Gast)


Lesenswert?

> Ja hallo.


> Über SPI sollen mit einem Atmega32 3 Integer-Variablen gesendet werden.
> Damit die jeweils in das SPDR passen, habe ich folgende Operationen
> programmiert (SPI_send ist die Sendefunktion. Die funktioniert!):
>
>

> for (i = 0; i < 4; i++)
> {
>  // Low-Byte senden
>  send_SPI(((unsigned char) (control[i] & 0x00ff)));
>  // High_Byte senden
>  send_SPI(((unsigned char) (control[i] >> 8)));
> }
>

> Du sendest aber 4 Integer raus !

Is klar! Die Schleife läuft solange kleiner 4 und es werden pro 
Schleifendurchlauf 2 Bytes gesendet. Also werden drei Durchläufe gemacht 
mal zwei Bytes sind sechs Bytes, also drei Integer.


>

> int main()
> {
>  // Laufvariable auf null
>  a = 0;
>
>  // gesendete Abstände wieder zusammensetzen...
>  for (i = 0; i < 6; i = i + 2)
>  {
>    // gesendet wurde erst Low-Byte dann High-Byte
>    gap[a] = (((unsigned int) (letter[(i + 1)] << 8)) | ((unsigned int)
> letter[i]));
>    a++;
>  }
>

> Wasn dat. Das kann gar nit gehen du packst ständig irgend etwas in deine
> tolles Array gap. Zeige mal deinen ganzen aktuellen Code mit dem Mist
> kann keiner was anfangen !

Ah so. Nur weil etwas ständig gemacht wird, geht es also nicht.
Und überhaupt: Was gibst Du hier für nen Mist von Dir? Du musst ihm 
nicht helfen, und wenn Du es nicht kannst, dann brauchst Du hier auch 
nicht so nen Senf von Dir zu geben, OK?

von (prx) A. K. (prx)


Lesenswert?

Stefan schrieb:

>> for (i = 0; i < 4; i++)

> Is klar! Die Schleife läuft solange kleiner 4 und es werden pro
> Schleifendurchlauf 2 Bytes gesendet. Also werden drei Durchläufe gemacht

Au weh. Noch keinen Kaffee gehabt? Versuch's lieber nochmal.

von Dennis (Gast)


Lesenswert?

Schlechte Stimmung am Montagmorgen? :)

Vielen Dank, das mit der FOR-Schleife ist der Fehler.
Sollte i<3 heissen! Also wird auch immer einer zu viel gesendet, was 
begründet, warum die Karre nicht so tut wie sie soll!


Danke an ALLE Beteiligten ;) Und das nächste Mal poste ich besser den 
ganzen Code!


Viele Grüße!

D.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Und das nächste Mal poste ich besser den ganzen Code!
Ja, denn ein Fragezeichen bleibt bei mir noch:
1
gap[a] = (((unsigned int) (letter[(i + 1)] << 8)) | ((unsigned int) letter[i]));
Wenn ich mir das High-Byte so anschaue, dann sitzen da die Klammern 
falsch :-o

Angenommen letter wäre ein char-Array, dann ergibt
1
(letter[(i + 1)] << 8)
immer 0. Da hilft dann das anschliessende Casten nicht mehr viel:
1
(unsigned int) (letter[(i + 1)] << 8)
Kann sein, dass das geht, es muß aber nicht... :-/

Zuverlässiger (und beabsichtigt) ist das wohl eher so:
1
gap[a] = (((unsigned int) letter[i+1]) << 8) | ((unsigned int) letter[i]);

von (prx) A. K. (prx)


Lesenswert?

Lothar Miller schrieb:

> Angenommen letter wäre ein char-Array, dann ergibt
1
(letter[(i + 1)] << 8)
> immer 0.

Keineswegs. Nur wenn sich der Compiler nicht an den Standard hält. Der 
schreibt nämlich vor, dass alle ganzzahligen Rechnungen mindestens als 
"int" oder "unsigned" durchgeführt werden.

Folglich darf man das in korrektem C auch so schreiben:
1
gap[a] = (letter[i+1] << 8) | letter[i];

Es gibt allerdings ein paar Compiler für 8-Bitter, die in einer 
bestimmten Compilereinstellung diese Regel verletzen um besseren Code 
erzeugen zu können.

von Sven P. (Gast)


Lesenswert?

C99 -- Committee Draft -- May 6, 2005 ISO/IEC 9899:TC2

Seite 42f:
1
The following may be used in an expression wherever an int or unsigned int may
2
be used:
3
-- An object or expression with an integer type whose integer conversion rank is less
4
    than or equal to the rank of int and unsigned int.
5
-- A bit-field of type _Bool, int, signed int, or unsigned int.
6
If an int can represent all values of the original type, the value is converted to an int;
7
otherwise, it is converted to an unsigned int. These are called the integer
8
promotions.48) All other types are unchanged by the integer promotions.
9
The integer promotions preserve value including sign. As discussed earlier, whether a
10
``plain'' char is treated as signed is implementation-defined.

von Dennis (Gast)


Lesenswert?

>Zuverlässiger (und beabsichtigt) ist das wohl eher so:

>gap[a] = (((unsigned int) letter[i+1]) << 8) | ((unsigned int) letter[i]);

Also die runden Klammern bei letter[i+1] weglassen?
Ich programmiere mit AVR Studio 4.0 ... falls die Info zur Lösung des 
Problems beiträgt!

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Btw: In Deiner Main bearbeitest Du bereits Eingaben, ohne zu prüfen, ob 
alle Daten angekommen sind. Du solltest erst dann loslegen, wenn count 
die 6 (!) erreicht hat - erst dann sind alle benötigten Daten da.

Was Du in SIGNAL(SIG_SPI) mit dem Timer-Interrupt machen willst, ist mir 
dabei immer noch unklar. Oder wolltest Du den SPI-Interrupt abschalten?

Wenn nein, könnte es sein, dass letter einen Speicherüberlauf ergibt, 
falls noch weitere Daten per SPI folgen.

Also zumindest SPI-Interrupt abschalten und nach der Datenverarbeitung 
count auf 0 sowie SPI-Interrupt wieder einschalten.

Beachte aber auch, dass SPI-Eingaben verschwinden können, wenn wärend 
der Datenverarbeitung mehrere Daten eingehen.

von Dennis (Gast)


Lesenswert?

> Was Du in SIGNAL(SIG_SPI) mit dem Timer-Interrupt machen willst, ist mir
> dabei immer noch unklar. Oder wolltest Du den SPI-Interrupt abschalten?

Nein, da wird und soll tatsächlich der Timer abgeschaltet werden. Das 
Programm macht noch mehr, als ich hier geschrieben habe. Das nächste Mal 
lege ich einfach alles ab.

> Wenn nein, könnte es sein, dass letter einen Speicherüberlauf ergibt,
> falls noch weitere Daten per SPI folgen.

Ich frage ab, ob sechs Bytes angekommen sind:
1
SIGNAL(SIG_SPI)
2
{
3
 letter[count] = SPDR;
4
 SPDR = 0x44;
5
 if (count == 5)
6
 {
7
  TIMSK &= (~(1 << TOIE0));
8
 }
9
 else
10
 {
11
  count++;
12
 }
13
}


> Also zumindest SPI-Interrupt abschalten und nach der Datenverarbeitung
> count auf 0 sowie SPI-Interrupt wieder einschalten.

Wenn ich den SPI-Interrupt abschalte, sendet der Master ja trotzdem 
weiter, oder? Also könnten doch Daten verloren gehen, bzw in der 
falschen Reihenfolge eintreffen, korrekt?

> Beachte aber auch, dass SPI-Eingaben verschwinden können, wenn wärend
> der Datenverarbeitung mehrere Daten eingehen.

Das musst Du mir bitte erklären!

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
Noch kein Account? Hier anmelden.