Forum: Mikrocontroller und Digitale Elektronik Arduino SPI Daten senden


von Mgns (Gast)


Lesenswert?

Moin,

ich bin leider noch ein ziemlicher Anfänger in der Programmierung der 
SPI eines Arduinos. Deswegen möchte ich im ersten Schritt lediglich 
erstmal sehen, dass ich einzelne Befehle aussenden kann. Das Ganze gucke 
ich mir dann über ein digitales Oszilloskop an.
(Der Arduino empfängt Befehle per Bluetooth über MATLAB.)

Ich habe dazu folgenden Code geschrieben:
1
#include <SoftwareSerial.h>
2
#include <SPI.h>
3
4
int TxD;
5
int RxD;
6
int data;
7
const byte WAKEUP  = 0b00000010;
8
unsigned long nextMillis = 0;
9
SoftwareSerial bluetooth(TxD, RxD);
10
11
/* SPI pin numbers:
12
  SCK   13  // Serial Clock.
13
  MISO  12  // Master In Slave Out.
14
  MOSI  11  // Master Out Slave In.
15
  SS    10  // Slave Select*/
16
17
void setup() {
18
  Serial.begin(9600);
19
  nextMillis = millis();
20
  bluetooth.begin(9600);                                                                                    
21
  SPI.begin();
22
  SPI.setClockDivider(SPI_CLOCK_DIV128);
23
}
24
25
void loop()
26
{
27
  if (bluetooth.available() > 0)
28
  {
29
    data = bluetooth.read();
30
    Serial.print(data);
31
    Serial.print("\n");
32
33
    if (data == 'H')
34
    {
35
      digitalWrite(SS, LOW);                      /* Turn SlaveSelect Level to low*/
36
      delay(5);                                   /* all delays for stability*/
37
    }
38
    else if (data == 'U')
39
    {
40
      SPI.transfer(WAKEUP);                       /* Turn off standby mod*/
41
      Serial.println("Turn off standby Sent.");
42
      delay(5);
43
    }
44
  else if (data == 'Z')
45
    {
46
      digitalWrite(SS, HIGH);                   /* Turn SlaveSelect Level to high*/
47
    }
48
  }
49
}

Der Teil, bei dem ich das Level vom SlaveSelect verändere funktioniert.
Aber ich kann mittels des Oszilloskops nicht sehen, dass Daten 
ausgesendet werden. Kann mir jemand sagen, was ich dafür ändern muss?
Nach meinem Verständnis müsste bei jedem Takt ja ein Bit gesendet 
werden.

Vielen Dank im voraus!
M

von Einer K. (Gast)


Lesenswert?

Mgns schrieb:
> Der Teil, bei dem ich das Level vom SlaveSelect verändere funktioniert.
Genau da liegt der Irrtum!
Es sieht auf dem Oszi so aus, als wenn es funktioniert.
Macht aber was anderes, als du glaubst.


> digitalWrite(SS, LOW);
Wenn du deinen SS nicht vorher zum Output machst, dann schaltet der SPI 
"Baustein" bei Low an SS in den Slavemode.
Dann kommt kein Takt und auch keine Daten.

Steht auch so im Datenblatt deines Prozessors.
Auch in der Arduino SPI Doku wird es erwähnt.



Also in setup():
> digitalWrite(SS, HIGH);
> pinMode(SS,Output);
(ja, in dieser Reihenfolge)
Dann tuts das auch.

von Mgns (Gast)


Lesenswert?

Vielen Danke! Habe ich hinzugefügt!

Ich kann eine Veränderung des Levels des SS weiterhin sehen, allerdings 
nicht, dass irgendwelche Bits übertragen werden.
Ich habe mit "SPI.setClockDivider(SPI_CLOCK_DIV128);" meine CLK auf 
125kHz gesetzt oder? Das müssten doch ca. 8µs für jeden Takt sein. 
Deswegen habe ich mein Oszilloskop auf 1µs/div gestellt. (Bin auch 
andere Auflösungen durchgegangen, nur immer sicher zugehen).
Habt ihr 'ne Idee, was ich anders einstellen müsste?
Benutze ein "AnalogDiscovery 2" von Digilent.

von Einer K. (Gast)


Lesenswert?

Siehst du denn den Takt?

von Mgns (Gast)


Lesenswert?

Ne, den sehe ich ebenfalls nicht.

von Einer K. (Gast)


Lesenswert?

Du verwendest einen Arduino Mega?

von Mgns (Gast)


Lesenswert?

Ah, das hätte ich dazuschreiben können natürlich... Ich verwende einen 
Arduino Uno, sorry!

von Einer K. (Gast)


Lesenswert?

Tja, dann weiß ich auch nicht....

Gerade mit dem UNO getestet:
1
#include <SPI.h>
2
3
const byte WAKEUP  = 0b00000010;
4
5
6
/* 
7
 *  
8
 *  SPI pin numbers:
9
 *  Arduino UNO/Nano/Pro Mini
10
  SCK   13  // Serial Clock.
11
  MISO  12  // Master In Slave Out.
12
  MOSI  11  // Master Out Slave In.
13
  SS    10  // Slave Select
14
 */
15
16
void setup() 
17
{
18
  digitalWrite(SS, HIGH);
19
  pinMode(SS,OUTPUT);
20
  SPI.begin();
21
  SPI.setClockDivider(SPI_CLOCK_DIV8);
22
}
23
24
void send()
25
{
26
  digitalWrite(SS, LOW);
27
  SPI.transfer(WAKEUP); 
28
  digitalWrite(SS, HIGH);
29
}
30
31
void loop()
32
{
33
  send();
34
  //delay(1000);
35
}
Zuckt wie verrückt.
Perfekt.
Auch mit deinen 125kHz

von Rath Schläger (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Zuckt wie verrückt.
> Perfekt.
> Auch mit deinen 125kHz

Wer Arduino kann muss (noch) nicht unbedingt Messen können.

von Mgns (Gast)


Lesenswert?

Okay, das ist interessant! Mit deinem Code klappt das bei mir ebenfalls!
Dann muss der Fehler ja bei mir im Code liegen. Aber vielen Dank schon 
mal.

von Mgns (Gast)


Angehängte Dateien:

Lesenswert?

So sieht es mit deinem Code aus, Arduino Fanboy D.
Bei meinem passiert da leider nichts, als würde die Clock durch 
irgendwas blockiert werden.

von S. Landolt (Gast)


Lesenswert?

Dann wäre doch ein möglicher Weg, hiervon ausgehend nach und nach 
diese Bluetooth-Zusätze einzubauen und zu schauen, ab wann es nicht mehr 
geht.

Beitrag #5825385 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

Das
> int TxD;
> int RxD;
kommt mir arg komisch vor.

Ansonsten... außer den schon genannten Dingen... sehe ich da nix 
falsches.

Beitrag #5825392 wurde von einem Moderator gelöscht.
Beitrag #5825411 wurde von einem Moderator gelöscht.
Beitrag #5825413 wurde von einem Moderator gelöscht.
Beitrag #5825428 wurde von einem Moderator gelöscht.
von Veit D. (devil-elec)


Lesenswert?

Hallo,

dein SlaveSelect Pin muss an der richtigen Stelle schalten.
Du weißt vorher nicht welche Daten empfangen wurden, dann verheddert 
sich der SS Pegel.

Wenn jetzt kein 'U' kommt, geht der SS nur kurz auf Low und wieder auf 
High.
Kommt ein 'U' rein wird dazwischen noch kurz etwas gesendet.
Es ist sichergestellt das der SS Pin immer auf dem richtigen Pegel 
steht.
Das delay kann auch raus. Meistens benötigen die ICs 50ns Verzögerung. 
Ein Takt dauert aber schon 62,5ns. Das DigitalWrite dauert ca. 4µs. 
Einheiten beachten. Da musst du dir keine Sorgen machen.
Das Serial bei 'U' würde ich rausnehmen. Fürs debuggen noch okay.
1
#include <SoftwareSerial.h>
2
#include <SPI.h>
3
4
int TxD;
5
int RxD;
6
int data;
7
const byte WAKEUP  = 0b00000010;
8
unsigned long nextMillis = 0;
9
SoftwareSerial bluetooth(TxD, RxD);
10
11
/* SPI pin numbers:
12
  SCK   13  // Serial Clock.
13
  MISO  12  // Master In Slave Out.
14
  MOSI  11  // Master Out Slave In.
15
  SS    10  // Slave Select*/
16
17
void setup() {
18
  Serial.begin(9600);
19
  nextMillis = millis();
20
  bluetooth.begin(9600);      
21
22
  digitalWrite(SS, HIGH);
23
  pinMode(SS,OUTPUT);  
24
  SPI.begin();
25
  SPI.setClockDivider(SPI_CLOCK_DIV128);
26
}
27
28
void loop()
29
{
30
  if (bluetooth.available() > 0)
31
  {
32
    data = bluetooth.read();
33
    Serial.print(data);
34
    Serial.print("\n");
35
    
36
  digitalWrite(SS, LOW); 
37
  
38
    if (data == 'H')
39
    {
40
      // hier sinnvolle Dinge tun
41
    }
42
    else if (data == 'U')
43
    {
44
      SPI.transfer(WAKEUP);                       
45
      Serial.println("Turn off standby Sent.");
46
    }
47
    else if (data == 'Z')
48
    {
49
      // hier sinnvolle Dinge tun
50
    }
51
  
52
  digitalWrite(SS, HIGH);                  
53
  }
54
}

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

haha :-) , na klar, hier fehlen noch die Pinangaben.
1
int TxD;
2
int RxD;
3
SoftwareSerial bluetooth(TxD, RxD);

also irgendwie sowas
1
const byte TxD = 8;
2
const byte RxD = 9;
3
SoftwareSerial bluetooth(8, 9); // oder Wert vertauschen

von Mgns (Gast)


Lesenswert?

Okay, es ist etwas merkwürdig. Aber mit meinem Code funktioniert das 
ganze ebenfalls, wenn ich den SS als Output vorher definiere.
Allerdings nur, wenn ich über MATLAB beispielsweise
1
 fprintf(bt, 'UU')
schicke. Sende ich hingegen
1
 fprintf(bt, 'U')
 geht es nicht.
Ich habe das mit jeder beliebigen Kombination und unterschiedlichen 
Befehlen ausprobiert. Immer, wenn ich ein "U" vor dem nächsten Buchstabe 
setze, sendet er den Befehl... Kann mir das jemand erklären? Ich bin 
ziemlich verwirrt.

von Einer K. (Gast)


Lesenswert?

Veit D. schrieb:
> na klar, hier fehlen noch die Pinangaben.

Scheinen irgendwie nicht wichtig genug zu sein.....

TxD und RxD von SoftwareSerial und RxD von HardwareSerial alle drei 
Funktionalitäten auf dem gleichen Pin.

Naja... wer es mag....
Der jeweiligen Funktion tut es sicherlich nicht gut.
Zumindest habe ich keinerlei Ahnung, wie das ordentlich funktionieren 
soll.

Denn die Serielle ist kein Bus.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

hmm, man sollte nichts in Eile schreiben, Sorry   :-)
eigentlich sollte das vorhin so aussehen ....
1
const byte TxD = 8;
2
const byte RxD = 9;
3
SoftwareSerial bluetooth(RxD, TxD); // oder vertauschen

Ist aber Schwachsinn, weil man kann gleich die Pinnummern der Instanz 
direkt übergeben, dann gibts auch keine Konflikte.
1
SoftwareSerial bluetooth(8, 9);  // Bsp.

Wenn jetzt immer noch nichts richtig funktioniert, dann bitte erneute 
Problembeschreibung mit aktuellen Sketch.

aktuell würde ich es erstmal so machen
1
#include <SoftwareSerial.h>
2
#include <SPI.h>
3
4
const byte WAKEUP  = 0b00000010;
5
SoftwareSerial bluetooth(8, 9);   // RX, TX
6
7
/* SPI pin numbers:
8
  SCK   13  // Serial Clock.
9
  MISO  12  // Master In Slave Out.
10
  MOSI  11  // Master Out Slave In.
11
  SS    10  // Slave Select*/
12
13
void setup() {
14
  Serial.begin(9600);
15
  bluetooth.begin(9600);
16
  
17
  digitalWrite(SS, HIGH);
18
  pinMode(SS, OUTPUT);
19
  
20
  SPI.begin();
21
  SPI.setClockDivider(SPI_CLOCK_DIV128);
22
}
23
24
void loop()
25
{
26
  if (bluetooth.available() > 0)
27
  {
28
    char data = bluetooth.read();
29
    Serial.println(data);
30
31
    if (data == 'H')
32
    {
33
      // hier sinnvolle Dinge tun
34
    }
35
    else if (data == 'U')
36
    {
37
      digitalWrite(SS, LOW);
38
      SPI.transfer(WAKEUP);
39
      digitalWrite(SS, HIGH);
40
      Serial.println("Turn off standby Sent.");
41
    }
42
    else if (data == 'Z')
43
    {
44
      // hier sinnvolle Dinge tun
45
    }
46
  }
47
  
48
}

von Mgns (Gast)


Lesenswert?

Moin,

aktuell geht es. Allerdings reagiert der Chip nicht auf die Befehle, mal 
schauen woran das nun wieder liegt... :D
Danke für eure Hilfe!

von Einer K. (Gast)


Lesenswert?

Mgns schrieb:
> Danke für eure Hilfe!

Bitte bitte, gerne doch!

Hast du denn mittlerweile das
> int TxD;
> int RxD;
> SoftwareSerial bluetooth(TxD, RxD);
Problem verstanden und behoben?

von Mgns (Gast)


Lesenswert?

Ja, ich denke schon, dass das jetzt klar geworden ist!
Kurze Frage noch, mit SPI.transfer() kann ich auch Daten empfangen oder?
Aktiviert sich die Clock nur, wenn man dem Arduino mitgibt, dass er 
jetzt Daten lesen muss? Ich benötige ja die Clocktakte am Chip ebenfalls 
zum Daten ausgeben.
Sorry für die vermutlich sehr dummen Fragen! :D

von jo mei (Gast)


Lesenswert?

Mgns schrieb:
> die Clock

die Clock  --> die Uhr
der Clock  --> der Takt

von Einer K. (Gast)


Lesenswert?

Mgns schrieb:
> Sorry für die vermutlich sehr dummen Fragen! :D

Ob sie dumm sind, weiß ich nicht!
Aber, ich verstehe sie nicht.

Wikipedia: SPI
Schon gelesen?

Mgns schrieb:
> Kurze Frage noch, mit SPI.transfer() kann ich auch Daten empfangen oder?
Natürlich!
So sagt es die Spezifikation.
Die Arduino Doku betätigt es.
Und so wird es auch in der Praxis getan.

Mgns schrieb:
> Ja, ich denke schon, dass das jetzt klar geworden ist!
Und auch behoben?

von Mgns (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Und auch behoben?
Ja, so geändert wie ihr es geschrieben habt.

Habe Wikipedia und mehr dazu durchgestöbert, ich glaube grundsätzlich 
weiß ich was ich will, nur bin ich noch limitiert in meiner Denkweise, 
vielleicht macht es ja noch "klick".
Ich verstehe noch nicht ganz, wie das mit dem Datenaustausch 
funktiniert. Also folgendes, wenn ich mit Hilfe des Arduino den Befehl 
xxxx xxxx sende, dann sehe ich gleichzeitig, dass SCLK 8 Takte anliegt. 
Damit mein Chip aber jetzte korrekt darauf reagieren kann, so müsste ich 
diesem ja wieder die Takte meiner SCLK zur Verfügung stellen. Geht das 
darüber, dass ich ihm beispielsweise hiermit "receivedVal = 
SPI.transfer(val)" sage, "ließ mal aus, was so da sein könnte?"

von Einer K. (Gast)


Lesenswert?

Lesen und schreiben geschieht gleichzeitig.
Nicht nacheinander.

von Mgns (Gast)


Lesenswert?

Kann man denn nach einem einzelnen Bit quasi fragen?
Also wenn man beispielsweise "byte temp = SPI.transfer(0x00);" schreibt?

von Einer K. (Gast)


Lesenswert?

Acht Takte führen zu 8 Bit.
Also nein!
Einzelne Bits geht nicht.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

lese andere Quellen um den Ablauf von SPI zu verstehen. Die Auswahl ist 
riesig. Hier im Forum gibts auch ein Tutorial Fundus.

Ob ein SPI Device einen Wert gesendet bekommt oder ob ein Wert 
ausgelesen wird, darum kümmert sich die SPI.transfer Methode. Schau dir 
die Bsp. an. Du kannst das natürlich auch zu Fuss machen, lernste noch 
mehr.

Zu deiner letzte Frage. SPI arbeitet Byteweise. Du musst dann das 
empfangene Byte auf dein Bit abfragen. Alles nach der Übertragung.

: Bearbeitet durch User
von Mgns (Gast)


Lesenswert?

Danke, dass ihr so geduldig mit mir seid! :)
Ich wühle mich gerade durchs Forum und diversen anderen Seiten und habe 
auf jeden Fall schon einiges durch euch gelernt.
Eine kleine Verständnisfrage.
Wenn ich über die MOSI-Leitung meine Steuersignale ausgebe (bspw. 0000 
0010 oder so), dann wird über den Takt von SCLK meinem ADS1299 
mitgeteilt, jetzt kommt ein Befehl. Damit der IC nun darauf reagieren 
kann und die Möglichkeit zu antworten bekommt, muss ich nun über SCLK 
und MOSI (0000 0000 oder so) senden, damit dieser 8 Takte hat und die 
Bits seinerseits senden kann oder?

von jo mei (Gast)


Lesenswert?

Mgns schrieb:
> Danke, dass ihr so geduldig mit mir seid! :)

Danke auch.

Hauptsache du schreibst nicht "der Uhr" oder "die Takt".

Mgns schrieb:
> muss ich nun über SCLK
> und MOSI (0000 0000 oder so) senden, damit dieser 8 Takte hat und die
> Bits seinerseits senden kann oder?

Ja. dabei ist das Datum was du schickst nicht relevant,
Hauptsache du schickst was.

von Mgns (Gast)


Lesenswert?

Moin!

Ich habe eine weitere Frage, wer hätte das gedacht! :D
Momentan schicke ich ziemlich unelegant immer einen Byte über die 
Leitung warte kurz schicke den nächsten usw. ... Kann man auch 
Bytepakete schicken und genau definieren, wie viel Pause zwischen den 
einzelnen Paketen sein soll?
Mein Oszilloskop zeigt mir logischerweise immer nur einen Byte an und 
dann den nächsten. Gucke ich mir beispielsweise andere SPI-Protokolle 
an, bspw. das vom ADS1299 mit der ursprünglichen Software erzeugte 
Protokoll beim auslesen der Daten, dann wird mir mit denselben 
Einstellungen immer "mehr" angezeigt.

von S. Landolt (Gast)


Lesenswert?

Das kommt auf die Partner an: so kann z.B. ein ATmega mit der 
USART-Schnittstelle im SPI-Mode "am Stück", also ohne Unterbrechung, 
einen Datenblock (514 Bytes) an eine SDCard schicken - danach benötigt 
die SDC eine Pause.

von S. Landolt (Gast)


Lesenswert?

PS:
Diese ATmega-Schnittstelle ist gepuffert, man erreicht also eine 
SPI-Rate mit dem halben Systemtakt des ATmega, über beliebig viele Bytes 
hinweg.

von jo mei (Gast)


Lesenswert?

Mgns schrieb:
> Ich habe eine weitere Frage, wer hätte das gedacht!

Ich hätte da auch noch was ....

Mgns schrieb:
> einen Byte

--> ein Byte  (das Byte)

Mgns schrieb:
> den nächsten

--> das nächste

von Mgns (Gast)


Lesenswert?

Sorry Jo Mei!?
Du hast ja recht!

Wie programmiert man das korrekt? Die Dokumentation von SPI.transfer() 
ist ja mehr als überschaubar...
Also angenommen ich möchte 3 mal das Byte (0000 0001) hintereinander 
wegschicken, dann eine Pause von 3 Takten oder so haben und dann erneut 
das ganze, bis ich 216 Bits verschickt habe.
Also wenn ich den "Dreierblock" habe, würde ich den Rest vermutlich über 
die Delay-Funktion und eine for-Schleife oder while-Schleife regeln.?
Ach ja und noch eine Frage, wieso kann ich nicht 0000 0000 verschicken? 
Jedes andere Byte geht.

von Mgns (Gast)


Lesenswert?

Hat sich erledigt, sorry!

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.