Forum: Compiler & IDEs spi string empfangen


von max b. (maxod)


Lesenswert?

Hallo, ich versuche einen String den ich über einen Mega32 sende mit 
einem mega8 zu einem display zu senden. Leider hab ich absolut keine 
Ahnung was mein Denkfehler in der Empfangsroutine ist.
1
// sende routine atmega 32
2
void Master_Send (char* wert)
3
{
4
    PORTD|=(1<<PD7);
5
    while(*wert)
6
    {
7
    SPDR  = *wert;          // send Character
8
                while (!(SPSR & (1<<SPIF)));    // wait until Char is sent 
9
                wert++;                // Point to next char in String
10
                }     
11
    PORTD&=~(1<<PD7);
12
}
13
14
// empfangsroutine Atmega8
15
void Slave_Receive (void)
16
{
17
  char* text="";
18
  while(SPDR)
19
        {
20
                while (!(SPSR & (1<<SPIF)));    // Wait until Char is received
21
                                                // Check if Char (Byte) is received correctly 
22
                *text = SPDR ;
23
                text++;                  // Set Pointer on next Character
24
        }
25
        // output result transmission status on Port D 
26
        lcd_gotopos(2,1);
27
        lcd_writetext(text);
28
}

von Karl H. (kbuchegg)


Lesenswert?

> void Slave_Receive (void)
> {
>   char* text="";

No.

Du hast keinen Speicher, in den du die empfangenen Character ablegen 
könntest, brauchst aber einen.

Ein Pointer ist einfach nur ein Zeiger, ein Verweis auf den echten 
Speicher. Er ist aber NICHT der Speicher selber


   char text[80];    // Platz für 80 Charcater


Jetzt hast du tatsächlich ein Speicherfeld, in dem du Daten ablegen 
kannst. In deinem Fall eben einen String.

von Uwe (de0508)


Lesenswert?

Hallo,

du willst ins nichts den String zwischen speichern:
1
  char* text="";

Ich würde mir dazu ein Feld definieren:
1
 char cBuffer[20+1]; char* text = cBuffer;

Ich habe das so hingeschrieben um dir den Unterschied klar zu machen..

Edit: Karl Heinz war schneller.

von Karl H. (kbuchegg)


Lesenswert?

und das
1
  while(SPDR)
2
        {
3
                while (!(SPSR & (1<<SPIF)));    // Wait until Char is received
4
                                                // Check if Char (Byte) is received correctly 
5
                *text = SPDR ;
6
                text++;                  // Set Pointer on next Character
7
        }
geht so auch nicht.

Aus mehreren Gründen.

ZUm einen ist es deine Verwendung von text, die es dir unmöglich macht 
im Nachhinein text zu benutzen um den Anfang des Textes wiederzufinden.

Zum anderen kannst du die while Schleife so nicht machen. Wenn du einen 
String empfängst, dann muss dir der Sender in irgendeiner Form 
signalisieren, wann der String zu Ende ist. Das kann es zb machen, indem 
er vorab bekannt gibt, wieviele Zeichen er zu senden gedenkt. Oder aber 
er kann es zb machen, in dem vereinbart wird, mit welchem Zeichen ein 
String beendet wird. C benutzt üblicherweise die letzte Vereinbarung, in 
dem dem \0 Characer diese spezielle Bedeutung zu kommt. Das muss nicht 
so sein, man könnte auch jedes andere Zeichen nehmen, welches im 
eigentlichen Text niemals vorkommen wird. Du zb benuzt ein spezielles 
Zeichen, wenn du deinen Computer über die Command Line benutzt. Die 
Return Taste erfüllt diese Aufgabe, in dem sie das Zeichen \n generiert, 
welches dem mithörenden Programm anzeigt: Jetzt ist eine Eingabezeile zu 
Ende und es wird erwartet, dass sie vom Programm bearbeitet wird.

von maxod (Gast)


Lesenswert?

1
void Slave_Receive (void)
2
{
3
    char buffer[8];
4
    char* text=buffer;
5
    while(*text != '\0')
6
        {
7
                while (!(SPSR & (1<<SPIF)));    // Wait until Char is received
8
                                                // Check if Char (Byte) is received correctly 
9
                *text = SPDR ;
10
                text++;                  // Set Pointer on next Character
11
        }
12
        // output result transmission status on Port D 
13
        lcd_gotopos(2,1);
14
    lcd_writetext(text);
15
}

Erst mal vielen Dank für eure umfangreichen Antworten. Hab ich das nun 
korrekt? bin mir nicht so ganz sicher mit der 1. while schleife...

von Karl H. (kbuchegg)


Lesenswert?

maxod schrieb:
>
> Erst mal vielen Dank für eure umfangreichen Antworten. Hab ich das nun
> korrekt?


nein

> void Slave_Receive (void)
> {
>     char buffer[8];
>     char* text=buffer;
>     while(*text != '\0')


wie kannst du an dieser Stelle *text schon abfragen, wenn du *text noch 
gar nicht empfangen hast?

>         {
>                 while (!(SPSR & (1<<SPIF)));    // Wait until Char is
> received
>                                                 // Check if Char (Byte)
> is received correctly
>                 *text = SPDR ;
>                 text++;                  // Set Pointer on next
> Character
>         }
>         // output result transmission status on Port D
>         lcd_gotopos(2,1);
>     lcd_writetext(text);

an dieser Stelle: wo zeigt text hin und was müsstest du eigentlich an 
lcd_writetext übergeben.



Es gibt nicht nur

    while( ... ) {
      ...
    }

Schleifen. Es gibt auch

    do {
      ...
    } while( ... )

Schleifen.

Zu Pointer

Das ist dein Array. Mal es dir mit Bleistift auf Papier auf

  buffer
  +---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+

Jetzt nimmst du dir einen Kugelschreiber und legst ihn aufs Papier, so 
dass die Spitze auf das erste Kästchen zeigt. Das ist dein Pointer 
'text' und er zeigt deswegen auf das erste Kästchen, weil du genau das 
mittels
    char* text=buffer;
erzwungen hast. Wenn du text++ machst, schiebst du den Kugelschreiber um 
ein Kästchen nach rechts. Wenn in deinem Programmtext *text steht, dann 
bedeutet das, das der Inhalt des Kästchens gemeint ist, auf das gerade 
der Kugelschreiber zeigt.
Würde in deinem Programm also

   *text = 'g';
stehen, dann schreibst du mit dem Bleistift in das Kästchen auf das der 
Kugelschreiber verweist, ein 'g' hinein. Wenn in deinem Programmtext 
steht

   if( *text == 'r' )

dann liest du das Kästchen aus, auf das der Kugelschreiber zeigt. Und 
immer dran denken: lokale Variablen haben keinen definierten 
Defaultwert. Ein leeres Kästchen steht hier nicht für ein Leerzeichen 
oder ein \0 Zeichen, sondern dafür dass du gerade auf Speicher 
zugreifst, dessen Inhalt zufällig ist.
Wenn du je in die Situation kommst, dass dein Kugelschreiber nach ein 
paar ++ Operationen auf kein Kästchen mehr zeigt und du trotzdem einen * 
ausführen musst, dann hast du soeben einen weiteren schweren Fehler 
entdeckt. Das darf dir nie passieren (genausowenig, wie der Zugriff auf 
uninitialisierten Speicher).

So weit so gut. Und jetzt geh deine Funktion durch und simuliere auf dem 
Papier dessen Funktion. Als Zeichen, die aus der SPI herauskommen, 
kannst du erst mal welche erfinden, die deiner Meinung nach da 
rauskommen müssten.
(Dadurch dass du die Senderoutine schreibst, kannst du dann ja auch 
sicher stellen, dass genau das dann auch tatsächlich übertragen wird)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

max b. schrieb:
> while(SPDR)
>   {
>     while (!(SPSR & (1<<SPIF)));    // Wait until Char is received

Und wovon, glaubst du, würde der SPI-Block überhaupt anfangen, hier
etwas zu empfangen?  Intuition?  Blitzschlag?

Eine SPI-Schnittstelle ist inhärent eine Zweirichtungs-Schnittstelle.
Damit man Daten empfangen kann, muss der Master Taktimpulse senden.
Wenn der Master Daten empfangen will, muss man folglich das Aussenden
von Taktimpulsen dadurch triggern, dass man irgendwelche Daten
rausschreibt.  Ob diese geschriebenen Daten nun für den Slave bereits
ein neues Kommando darstellt (das er nach der aktuellen Datenlieferung
bearbeitet) oder ob man einfach nur Dummydaten sendet (in der Regel
einfach ein Nullbyte), das ist abhängig von der Implementierung deines
Slaves.

von maxod (Gast)


Lesenswert?

1
void Slave_Receive (void)
2
{
3
    char buffer[10]="1234";
4
    char* text=0;
5
    int i=0;
6
7
       do
8
    {
9
                while (!(SPSR & (1<<SPIF)));    // Wait until Char is received
10
                
11
          buffer[i] = SPDR;
12
        *text=buffer[i];
13
        i++;
14
            
15
      }while(*text != 'z');
16
    i--;
17
    buffer[i]='\0';
18
}
habs jetz so gelöst, da ich mir nicht besser zu helfen wusste.

das der string mit '\0' abgeschlossen werden soll, hab ich nicht 
hinbekommen, liegt wohl an meinen 4 jahren pause von der schule ^^

aber herzlichen dank :)

von Karl H. (kbuchegg)


Lesenswert?

Mal eine kurze Zwischenfrage

Wozu brauchst du in
1
      do
2
    {
3
                while (!(SPSR & (1<<SPIF)));    // Wait until Char is received
4
                
5
          buffer[i] = SPDR;
6
        *text=buffer[i];
7
        i++;
8
            
9
      }while(*text != 'z');
überhaupt noch den Pointer?

Abgesehen davon, dass das so schon wieder nicht geht, weil der Pointer 
wieder auf keinen gültigen Speicher zeigt, in dem man ein Zeichen 
ablegen könnte. Auf diesen Punkt MUSST du achten! Du kannst nicht 
einfach einen Pointer anlegen und den dann dereferenzieren. Wann immer 
du einen * auf einen Pointer machst, musst du dich fragen: "Wo zeigt 
mein Pointer hin? Gibt es dort überhaupt den Speicher um dort etwas zu 
speichern?". Dein 'Kugelschreiber' Pointer MUSS auf ein Kästchen 
zeigen. Alles andere ist ein schwerer Fehler.

Du willst einen Character zwischenspeichern, damit du ihn nachher beim 
Vergleich benutzen kannst. Na dann mach das doch! Definiere dir eine 
char Variable und dort schreibst du das Zeichen hinein. Kein Mensch 
braucht dazu einen Pointer.

Du könntest natürlich auch hergehen und sagen: Ok ich weiss, dass wenn 
ich das zuletzt empfangene Zeichen in buffer[3] (weil i gerade den Wert 
3 hatte) gespeichert habe, und ich danach i um 1 erhöhe (i hat dann den 
Wert 4), dann kann ich immer noch beim testen der while Bedingung ganz 
einfach auf das Zeichen zugreifen, weil es ja in buffer[i-1] stehen 
muss. Also brauch ich gar keine Hilfsvariable um dort das Zeichen 
zwischenzuspeichern. Solange ich das Array buffer und i habe, weiß ich 
immer welches Zeichen zuletzt wo gespeichert wurde.

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.