Forum: Mikrocontroller und Digitale Elektronik SPI Komunikation


von Dieter_T (Gast)


Lesenswert?

Hi an all die Profis,
Ich habe Probleme mit meinen Code und komme einfach nicht weiter.
Ich nutze ein Mega als Master und ein Nano als Slave. Der Master sendet 
Text zum Slave, dieser kommt auch an und der Slave soll ein Text 
zurücksenden doch beim Master kommt nur genau das an was der Master 
sendet.Das der Slave was sendet muss ok sein, da der Master beim nicht 
senden kein Text zusammensetzten kann. Sendedaten und Empfangsdaten 
haben aber keinen Bezug. Weswegen der Master dann aber das zusammensetzt 
was er sendet ist für mich nicht nachvollziehbar. Hier der Code:

//Master
#include <SPI.h>
volatile boolean senden;
volatile char Paket_vom_Slave;
volatile char Paket_zum_Slave;
char buf [100];
volatile byte pos;
String Paket = "";

void setup (void)

{
  Serial.begin(9600);
//  pinMode(53, OUTPUT);
  pinMode(SS, OUTPUT);
 // digitalWrite(SS, HIGH);  //SS Pin auf HIGH setzten
  SPI.begin ();  //Verbindung starten
  SPI.setClockDivider(SPI_CLOCK_DIV8);  //Geschwindigkeit verlangsamen
}

void loop (void)
{
  //Text_erstellen();

  digitalWrite(SS, LOW);    //starten der Kommunikation mit Slave

  for (const char * p = "TxT v Master\n" ; Paket_zum_Slave = *p; p++)
  {
    //Text_erstellen();
    Paket_vom_Slave = SPI.transfer(Paket_zum_Slave); //senden von Text
    Text_erstellen();
    delayMicroseconds (500);

    Serial.print("sent: ");
    Serial.print(Paket_zum_Slave);
    Serial.print("\t empfangen: ");
    //Serial.println(Paket_vom_Slave);
    Serial.println(Paket);
    delay(200);
  }
  digitalWrite(SS, HIGH);  //beenden der Kommunikation
  delay (1000);  //kurze pause

}

void Text_erstellen()
{
  if (pos < sizeof buf)
  {
    char c = Paket_vom_Slave;  //kopieren der Daten von SPI Buffer
    buf [pos++] = c;  //hinzufuegen des naechsten Zeichens
    if (c == '\n')
      senden = true;
  }
  if (senden)
  {
    buf[pos] = 0;
    Paket = (buf);
    Paket.trim();
    Serial.println (("empfangen :--->") + (Paket));
    Serial.println (("empfangen :--->") + (Paket));
    Serial.println (("empfangen :--->") + (Paket));
    pos = 0;
    senden = false;
  }
}


//Slave
#include <SPI.h>
volatile boolean senden;
volatile boolean versandbereit;
//volatile byte Paket_Master,Sendung_Slave;
volatile char Paket_Master;
volatile char Sendung_Slave;
String Paket = "";
String Sendung = "";
int i = -1;
char buf [20];
char buf1 [20];
volatile byte pos;
volatile byte pos1;


void setup(void)
{
  Serial.begin(9600);
 // pinMode(12, OUTPUT);
  pinMode(MISO, OUTPUT);
 SPCR |= _BV(SPE);         // turn on SPI in slave mode


  //SPCR |= bit (SPE);
  senden = false;
  SPCR |= _BV(SPIE);   // turn on interrupts
  SPI.attachInterrupt();
}

void loop(void)
{
  if ((versandbereit) == false);
  {
    Paket_Text();
  }

  if (senden)
  {
    i = i + 1;
    buf[pos] = 0;
    Paket = (buf);
    buf1[pos] = 0;
    Sendung = (buf1);
    if (i == 12)
    {
      SPDR = "\n";
    }
    else
    {
      SPDR = (buf1[i]);
    }
    Paket.trim();
    Sendung.trim();
    Serial.println (("empfangen :--->") + (Paket));
    Serial.println (buf1[i]);
    Serial.println (i);
    Serial.println (("gesendet  :--->") + (Sendung));
    pos = 0;
    senden = false;
  }
  if (i == 12) i = -1;
}

ISR(SPI_STC_vect)
{

  byte c = SPDR;  //kopieren der Daten von SPI Buffer
  if (pos < sizeof buf)
  {
    buf [pos++] = c;  //hinzufuegen des naechsten Zeichens
    if (c == '\n')
      senden = true;
  }
}

void Paket_Text()
{
  if (pos1 < sizeof buf1)
    for (const char * p = "Paket--Slave\n" ; char c = *p; p++)
    {
      buf1 [pos1++] = c;
                            Serial.println (buf1);
      if (c == '\n')
        versandbereit = true;
    }
}

von Alex D. (daum)


Lesenswert?

Bin zwar kein Arduino-Profi, arbeite meistens direkt auf Register level 
mit Microcontrollern aber versuche mal hier zu helfen.

Der erste Tipp den ich habe ist, dass du das nächste Datenbit beim Slave 
schon im Interrupt in das SPDR schreibts. Denn sonst kann es passieren, 
dass der Slave in der main loop den SPDR setz code nicht zwischen 2 SPI 
transfers erreicht.

Aber das kann ja nicht das eigentliche Problem sein. Schau nochmal ob du 
beim Slave MISO als output gesetzt hast. Dass der Master das gleiche 
empfängt kann nämlich auch an der verkabelung liegen. Wenn zwei 
Leitungen nebeneinander laufen (was bei dir der Fall sein wird) dann 
gibt es dazwischen Übersprechen, besonders wenn eine auf beiden Seiten 
Eingänge (hochohmig) hängen hat, und die andere halbwegs hohe Frequenzen 
(sieht ja nach 2MHz aus) hat. Sonst auch noch mal die Steckverbindung 
selbst überprüfen.

von Karl M. (Gast)


Lesenswert?

Hallo,

ich habe da so mein Problem mit der Schreibweise von sizeof(<type>) in 
deinem Code.

Ich kenne die Anwendung nur als Funktionsaufruf:

https://www.geeksforgeeks.org/sizeof-operator-c/

von Peter D. (peda)


Lesenswert?

So geht das nicht.

Beim Senden muß der Slave nach jedem Byte warten, bis der Master es 
abgeholt hat (Interrupt Flag).
Und der Master muß nach jedem Byte eine Wartezeit abwarten, damit der 
Slave das nächste Byte in SPDR schreiben kann. Die AVRs haben nämlich 
keinen Sendebuffer.

von Dieter_T (Gast)


Lesenswert?

Die Verkabelung und Slave MISO als output ist alles ok ein 
Beispielprogramm was eine Zahl hin und her sendet läuft ohne Probleme.

von Dieter_T (Gast)


Lesenswert?

Kannst du mir ein Tipp gegen wie ich das in meinen Code wo und wie 
einsetzen kann ich glaube auch das rs das ist. Leider bin ich hier sehr 
unerfahren hab versucht mich schlau zu lesen komme aber nicht weiter.

von Dieter T. (dieter_t)


Lesenswert?

Ich komme langsam voran :-)

Aber hab momentan ein Problem mit der Datenübergabe.
Ich übergebe beim Start: char Paket_zum_Master [50] = "Starten vom 
Slave.";
und ändere in der SPI interrupt routine den Inhalt in "neuer Text"
Gesendet wird aber "Starten vom Slave."
Wie muss ich das ändern.
1
// Slave
2
char Paket_zum_Master [50] = "Starten vom Slave.";
3
volatile int pos;
4
volatile bool active;
5
String Send_Paket;
6
7
8
ISR (SPI_STC_vect)    // SPI interrupt routine
9
{
10
Send_Paket = "neuer Text";
11
char Sendung = ((Send_Paket + "\n").c_str());
12
Paket_zum_Master [50] = Sendung;  
13
  byte c = SPDR;
14
  if (c == 1)  // starting new sequence?
15
    {
    active = true;
    pos = 0;
    SPDR = Paket_zum_Master [pos++];   // sendet erste byte
    return;
    }
  if (!active)
    {
    SPDR = 0;
    return;
    }
  SPDR = Paket_zum_Master [pos];
  if (Paket_zum_Master [pos] == 0 || ++pos >= sizeof (Paket_zum_Master))
    active = false;
}  // end of interrupt service routine (ISR) SPI_STC_vect

von Auh Weia (Gast)


Lesenswert?

Dieter T. schrieb:
> Wie muss ich das ändern.

Wie musst du was ändern um was zu erreichen?

Das schaut so schrecklich und chaotisch aus dass man wirklich
keine Lust hat darauf einzusteigen.

Bring erst mal Ordnung und Übersicht in dein Leben und deine
Programmier-Planung sowie die Code-Darstellung.

von Stefan F. (Gast)


Lesenswert?

Ich denke, du solltest dringend zuerst auf einem PC die Sprache C 
lernen, dann C++, dann die Besonderheiten von Arduino.

Das hier macht nie und nimmer das, was du erwartest:
1
char Paket_zum_Master [50] = "...;
2
String Send_Paket;
3
4
Send_Paket = "neuer Text";
5
char Sendung = ((Send_Paket + "\n").c_str());
6
Paket_zum_Master [50] = Sendung;

von Dieter T. (dieter_t)


Lesenswert?

he: Auh Weia "Bring erst mal Ordnung und Übersicht in dein Leben " ist 
ja wohl eine sehr persönliche Aussage, die muss ich mir von sone Wurst 
bestimmt nicht sagen lassen.

Bin 60 Jahre alt und denke, dass ich mein Leben sehr gut im Griff habe.
Zudem hab ich vor 30 Jahren schon einiges programmiert, das war da 
leider noch nicht so objekt gebunden, wie es heute ist.
Ich bin vor 1 Monat wieder angefangen mich mit Programmieren zu 
beschäftigen und momentan erschlagen mir förmlich die Mengen an 
Funktionen.
Aber ganz abgesehen davon:
Es gibt im Netz kein vernünftiges Beispiel einer SPI Übertragung, wo der 
Master ein String überträgt und gleichzeitig ein String empfängt.
Es bietet sich hier ja an, gemeinsam was vernümftiges zusammenzustricken 
und sei es nur dafür, das ein anderer es nutzen kann.

Und Stefanus F. mein Code ist außer die Variabel Namen ein Code von Nick 
Gammon und er funktioniert auch. Ich glaube so unübersichtlich 
programmiert  Nick Gammon auch nicht.
Was ich momentan ändern will, ist das der String der oben deklariert ist 
variabel änderbar ist.

von Stefan F. (Gast)


Lesenswert?

Du willst nicht einsehen, dass dein grob grob fehlerhaft ist.
Dann kann man Dir nicht helfen. Punkt.

von Auh Weia (Gast)


Lesenswert?

Stefanus F. schrieb:
> Du willst nicht einsehen, dass dein grob grob fehlerhaft ist.
> Dann kann man Dir nicht helfen. Punkt.

Yes.

Und danke sehr.

von Dieter_T (Gast)


Lesenswert?

Bin ich irgendwo von der Welt Stefanus, ich weiss das irgendwo ein 
Fehler ist deswegen bin ich ja hier. In der Regel erwartet man ja 
Unterstützung  und nicht eine Aussage wie oben das man erst mal sein 
Leben in Ordnung bringen soll. Und auch keine Aussage das da ein Fehler 
drin ist. Sondern wo der Fehler sein könnte und wie man ihn beseitigt. 
Ich glaub Stefanus auf deine Hilfe kann ich auch gut verzichten.

von c-hater (Gast)


Lesenswert?

Dieter T. schrieb:

> Es gibt im Netz kein vernünftiges Beispiel einer SPI Übertragung, wo der
> Master ein String überträgt und gleichzeitig ein String empfängt.

Ohhh, es gibt keine fertige Wichsvorlage... Das ist ja richtig 
schlimm... Da muss man doch tatsächlich wirklich selber programmieren... 
Das Leben kann ja so hart sein...

De facto ist es allerdings so: es gibt Unmassen solcher Beispiele. Man 
muss nur wenigstens soviel von der Sache verstehen, dass man sie auch 
finden kann. D.h.: man muss ubedingt das Grundkonzept der 
SPI-Kommunikation verstanden haben...

> Bin 60 Jahre alt

So what? Gerade mal drei Jahre älter als ich. Nö: das kann ich definitiv 
nicht als Ausrede gelten lassen...

Ich bin nichtmal sicher, ob das überhaupt wahr ist. Die KI sagt: 
definitiv NEIN, geschätztes Alter 2x. Ich schwanke noch, aus meiner 
Sicht: könnte zumindest so sein. In etlichen Fällen musste ich aber 
lernen, dass die KI beim Schätzen des Alters deutlich bessere 
Trefferraten erzielt als ich selber...

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> man muss ubedingt das Grundkonzept der
> SPI-Kommunikation verstanden haben...

Dieter, du brauchst die Grundlagen, wie man Zeichenketten in C, C++ und 
Arduino verwendet. Mit dem Thema SPI lenkst du oder wirst du vom Kern 
des Problems abgelenkt.

Spiele erstmal mit einem ganz "normalen" Arduino Uno Board und der 
Serial Klasse herum. Dabei wirst du einiges lernen, was du dann auf die 
SPI Klasse übertragen kannst.

Ich habe weiter oben ein paar fragwürdige Zeilen von deinem Quelltext 
zitiert. Bringe die mal auf dem Arduino Uno mit der Serial Klasse ans 
Laufen. Dann sehen wir weiter.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Dieter T. schrieb:
> Gesendet wird aber "Starten vom Slave."
> Wie muss ich das ändern.

 Aufhören in der ISR irgendetwas zu ändern.
 In der ISR wird nur gesendet, bzw. empfangen, die Position wird
 geprüft und entsprechende Flags gesetzt.
 Alles andere führt meistens zu Fehlern.

von Dieter T. (dieter_t)


Lesenswert?

Also ihr beiden Profis,
anstatt sich mal mit der Sache zu beschäftigen und mal sich mit ein 
Problem überhaupt mal auseinander zu setzen, sucht ihr glaub ich nur 
nach irgendwelchen Ausreden, um euer beklopptes Verhalten zu 
rechtfertigen.
Nochmal ich suche hier eigentlich nur nach einen Tipp, aber anscheinend 
seit ihr selber zu dumm, den Code zu lese.

Ich habe diese beiden Zeilen ausgetauscht und auch wenn ihr beiden es 
nicht glauben wollt, es läuft so wie es soll.

Send_Paket = "neuer Text";
strcpy(Paket_zum_Master, Send_Paket.c_str());
Serial.print ("Text vom Slave :---->  ");

Ich werde den Code noch ein wenig ausarbeiten und hier als Beispiel 
einsetzen, für diejenigen die nach einen guten Beispiel suchen.

Auf weitere Fachmeinungen von euch beiden kann ich gut verzichten.
MfG
      Dieter

von my2ct (Gast)


Lesenswert?

Dieter_T schrieb:
> Der Master sendet Text zum Slave, dieser kommt auch an und der Slave
> soll ein Text zurücksenden doch beim Master kommt nur genau das an was
> der Master sendet.

Aus deiner Formulierung entspringt ein grundlegendes Verständnisproblem 
bzgl. SPI. Über das SPI wird auf Ansage des Masters (Clock vom Master) 
zwei Bytes zwischen Master und Slave ausgetauscht. Der Slave sendet 
nie selbständig, sondern der Master holt sich etwas vom Slave.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Dieter T. schrieb:
> Ich werde den Code noch ein wenig ausarbeiten und hier als Beispiel
> einsetzen, für diejenigen die nach einen guten Beispiel suchen.

 Ich bin sicher, die weltweite Gemeinde der C-Programmierer wird mit
 Begeisterung ihre nun alten und wertlosen Bibliotheken und Programme
 wegwerfen und von da an nur deinen ausgezeichneten Code benutzen...

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Ich glaube auch, daß hier ein grundlegende Verständnis-Problem vorliegt.
Ganz gut wird das in dieser Grafik erklärt.
Mit jedem Zyklus "tauschen" Master und Slave den Inhalt ihrer 
Datenregister.
Entnommen aus dem Ddatenblatt des ATMega328p

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Dieter T. schrieb:
> Also ihr beiden Profis,
> anstatt sich mal mit der Sache zu beschäftigen und mal sich mit ein
> Problem überhaupt mal auseinander zu setzen, sucht ihr glaub ich nur
> nach irgendwelchen Ausreden, um euer beklopptes Verhalten zu
> rechtfertigen.

Meinst du das wirklich ernst? Ich helfe Dir jetzt nicht mehr weiter.

Lerne mal, Dich zu benehmen! Demut und Dankbarkeit wären die ersten 
Themen für Dich. Als nächste käme Selbsterkenntnis, denn das ist der 
Erste Weg zur Besserung.

von Dieter T. (dieter_t)


Lesenswert?

Ja stimmt natürlich der Master sendet natürlich ein Byte, und empfängt 
im Gegenzug ein Byte.
Allgemein gesagt Daten ausgetauscht.

von Dieter T. (dieter_t)


Lesenswert?

Meinst du das wirklich ernst?

Stefanus für dich nehm es zurück, aber das läuft soo, nie!! stimmt ja 
auch nicht.
Beim durchlesen hätte ich von einen Profi erwartet, das er auf die 
Fehlerstelle hinweist und nicht "das wird nie laufen."
Mittlerweile läuft es super.
"Spiele erstmal mit einem ganz "normalen" Arduino Uno Board"
Also das Netz und die Gruppen bieten sich zusätzlich zum Lernen, an, 
auch Fragen zu stellen und so seine Kenntnisse zu erweitern.
Wer sagt denn, dass ich nicht zusätzlich mich auch mit C-Programmierung: 
Zeichenkettenfunktionen uvm. beschäftige.
Aber auf eine Frage die Antwort "Lern erst mal....." passt ja auch 
nicht.
Hilfreicher wäre einfach nur ein Hinweis in der Sache ein Tipp ...

von Manno Mann (Gast)


Lesenswert?

So ein leeres Geschwafel.

Troll, trolle dich dahin.

von Stefan F. (Gast)


Lesenswert?

Dieter T. schrieb:
> Hilfreicher wäre einfach nur ein Hinweis in der Sache ein Tipp ...

Da war so viel auf einmal nicht in Ordnung, dass ein "Hinweis" oder 
"Tipp" gar nicht möglich war. Zuerst muss man eine gemeinsame Sprache 
haben, bevor man miteinander reden kann.

von Peter D. (peda)


Lesenswert?

Dieter T. schrieb:
> Ich übergebe beim Start: char Paket_zum_Master [50] = "Starten vom
> Slave.";
> und ändere in der SPI interrupt routine den Inhalt in "neuer Text"

Nein, tust Du nicht.
Du initialisierst mit "Starten vom Slave.", was ein großer Unterschied 
ist.
Dann mit "Paket_zum_Master [50] = Sendung;" schreibst Du ein Zeichen 
hinter die Variable, d.h. in einen ungültigen Bereich.
Ich kenne mich mit C++ nicht aus, aber in C kopiert man Strings mit 
strcpy(). Und die Länge ermittelt man mit strlen(). Schau mal ins Manual 
zur <string.h>.

sizeof() gibt Dir nur Anzahl Bytes einer Variablen, in diesem Fall 
konstant 50.

Dieter T. schrieb:
> ISR (SPI_STC_vect)    // SPI interrupt routine
> {
> Send_Paket = "neuer Text";
> char Sendung = ((Send_Paket + "\n").c_str());

Ich hab absolut keine Ahnung, was das bezwecken soll.

von Dieter_T (Gast)


Lesenswert?

Send_Paket = "neuer Text";
strcpy(Paket_zum_Master, Send_Paket.c_str());

Macht mehr Sinn,
Hiermit läuft es auch die Nachricht "neuer Text" wird vom Master 
empfangen.

Ich habe beim Slave jetzt die Möglichkeit je nach Ereignis einen 
passenden Text vom Master abholen zu lassen.

von Manno Mann (Gast)


Lesenswert?

Peter D. schrieb:
> Ich hab absolut keine Ahnung, was das bezwecken soll.

Wann wirst auch du begreifen dass du einen Troll fütterst?

Oder ist das reine Absicht? Sorry, so blind kann keiner sein.
Aber vielleicht gehörst du zu der Seite die den Troll
initiiert hat.

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.