Forum: Mikrocontroller und Digitale Elektronik ATmega128 und Atmega32 mit SPI verbinden und String senden


von CG (Gast)


Lesenswert?

Hallo Zusammen,
hoffe mir kann jemand helfen.

Ich habe zwei ATmegas (32 und 128) mittels SPI verbunden. Beide Laufen 
mit 16MHz.
Der ATMEGA32 ist als Master konfiguriert und der 128 als Slave.
Ich bin mitlerweile so weit gekommen, dass der Master ein Byte (in 
meinem Fall zum Testen ein 'A') sendet und der Slave schaut ob ein 'A' 
angekommen ist und dann einfach eine LED schaltet.
Dies Funktioniert soweit ziemlich gut :-)

Nun zu meinem Problem.
Ich würde gerne ein String senden, z.B. "Time\n" und wenn der Slave das 
richtige bekommt, dann soll diesr erstmals auch einfach eine LED 
einschalten. (Arbeite mich langsam Schritt für Schritt vor)

Quellcode beim Master sieht wie folgt aus :
1
char spi_send_string(char string[], int cs)
2
{
3
  uint8_t length;
4
  uint8_t i;
5
 
6
  length = strlen(string);
7
  
8
  for(i=0; i < length; i++)
9
  {
10
     spi_send(string[i], cs);
11
  }
12
}
13
14
char spi_send (unsigned char data, int cs)
15
{
16
  PORT_SPI &= ~(1<<cs);        // SS am Slave Low --> Beginn der Übertragung
17
    SPDR = data;            // Daten ins Buffer-Register laden und senden mittels Interrupt
18
  _delay_us(10);
19
  while (!(SPSR & (1<<SPIF)));
20
  //_delay_ms(1);
21
  _delay_us(10);
22
  PORT_SPI |= (1<<cs);        // SS High --> Ende der Übertragung
23
  return (SPDR);            // Return received data  
24
}

zum senden benutze ich einfach
1
 spi_send("TIME\n", PIN_SPI_CS3);

beim Slave habe ich nun folgendes gemacht. Ich habe im Interrupt 
folgenden Quellcode:
1
volatile unsigned char data;
2
// SPI Transmission/reception complete ISR
3
ISR(SPI_STC_vect)
4
{
5
  SWITCH_LED3;
6
  data = SPDR;
7
    // add to buffer if room
8
  if (spi_data_pos < sizeof(spi_data_buf) )
9
    {
10
    spi_data_buf[spi_data_pos++] = data;  
11
    if (data == '\n')
12
    {
13
      spi_data_pos = 0;
14
    }
15
    } 
16
}
17
18
spi_master_slave.h
19
20
#ifndef SPI_MASTER_SLAVE_H_
21
#define SPI_MASTER_SLAVE_H_
22
23
#include <avr/io.h>
24
#include <stdlib.h>
25
#include <util/delay.h>
26
#include <avr/interrupt.h>
27
28
#include "../global.h"
29
extern volatile char spi_data_buf[50];
30
extern volatile int spi_data_pos;
31
32
void spi_init_slave (void);
33
void spi_init_master (void);
34
char spi_send (char data, unsigned char cs);
35
36
#endif /* SPI_MASTER_SLAVE_H_ */

global.h
1
#define F_CPU 16000000UL
2
3
4
// SPI DatenVariable
5
volatile char spi_data_buf[50];
6
volatile int spi_data_pos;
7
8
.....

und in der Main eine whileschleife
1
  cli();            // Disable all interrupts
2
  initPort();          // Inizalisierung der Ports
3
//  spi_init_master();      // SPI Inizalisierung
4
  spi_init_slave ();      // SPI Inizalisierung als Slave        
5
  sei();            // enable all interrupts
6
while(1)
7
{
8
        SWITCH_LED1;
9
  _delay_ms(500);
10
  if (spi_data_buf == "TIME\n")
11
    SWITCH_LED2;
12
}

Kann mir vielleicht jemand verraten warum die Überprufung im 
spi_data_buf nicht Funkioniert bzw. nicht das richtige drin steht? Habe 
ich da einen Denkfehler in meinem Programm?
Oder etwas mit den Variablen (Buffern für den String) falsch gemacht?

Falls ich zu wenig Informationen gegeben habe einfach bescheid sagen was 
fehlt und ich poste es sofort nach!

Dankeschön im Vorfeld für eure Hilfe.

von Spiffman G. (spiffman)


Lesenswert?

Hallo,

soweit ich das verstanden habe vergleichst du den Zeiger auf deinen 
Buffer mit dem Text (vermtl. temporäre Variable). Daher sollte der 
vergleich nie wahr werden.

Versuch doch mal die Funktion strcmp:
http://www.gnu.org/software/libc/manual/html_node/String_002fArray-Comparison.html

von CG (Gast)


Lesenswert?

Oh super für die schnelle Antwort.
werde es mal morgen früh ausprobieren und dann bescheid geben. Bin 
leider nicht daheim.
Mis morgen

von CG (Gast)


Lesenswert?

Okay super es funktioniert!

Darf ich jetzt noch fragen wenn ich vom Slave eine Antwort zurücksenden 
möchte (eigentlich ein String aber erstmal ein 'B' zum Testen)
kann man das dann so machen wie ich es gemacht habe?

Slave ISR
1
ISR(SPI_STC_vect)
2
{  
3
  int i;
4
  
5
  SWITCH_LED3;
6
  data = SPDR;  // Ankommende Daten über SPI in Buffer Schreiben
7
    
8
  if (spi_data_pos < sizeof(spi_data_buf) )
9
    {
10
    spi_data_buf[spi_data_pos++] = data;  
11
    if (data == '\n')
12
    {
13
      spi_data_pos = 0;
14
      if (strcmp(spi_data_buf,"TIME\n") == 0)
15
      {
16
        SWITCH_LED2;
17
        SPDR = 'B';
18
      }
19
    }
20
    }
21
22
}

und beim Master
1
// Senden von Daten über SPI
2
// Beispiel: spi_data = spi_send ('T', PIN_SPI_CS3); // senden von einem Byte auf der SPI-Schnittstelle
3
char spi_send (unsigned char data, int cs)
4
{
5
  PORT_SPI &= ~(1<<cs);        // SS am Slave Low --> Beginn der Übertragung
6
    SPDR = data;            // Daten ins Buffer-Register laden und senden mittels Interrupt
7
  _delay_us(10);
8
  while (!(SPSR & (1<<SPIF)));
9
  //_delay_ms(1);
10
  _delay_us(10);
11
  PORT_SPI |= (1<<cs);        // SS High --> Ende der Übertragung
12
  return (SPDR);            // Return received data  
13
}
14
15
// Senden von Daten über SPI
16
// Beispiel: spi_data = spi_send ("TEST\n", PIN_SPI_CS3); // senden von einem String auf der SPI-Schnittstelle
17
char spi_send_string(char string[], int cs)
18
{
19
  uint8_t length;
20
  uint8_t i;
21
  char tmp;
22
 
23
  length = strlen(string);
24
  
25
  for(i=0; i < length; i++)
26
  {
27
     tmp = spi_send(string[i], cs);
28
  }
29
  return (tmp);
30
}

und dann die nächste Frage wie sende ich denn ein String zurück?
Wie sieht denn die CS-Leitung dann aus?

von CG (Gast)


Lesenswert?

Okay leider Funkioniert dies bei mir nicht!  :-(
Glaube ich habe ein verständnisproblem. Hat jemand vielleicht einen 
Nützlichen Tip für mich? Komm leider nicht weiter

von Sebastian W. (wangnick)


Lesenswert?

1. Der String "TIME\n" besteht aus sechs Zeichen: 'T', 'I', 'M', 'E', 
'\n', '\0'. strcmp bricht bei der ersten Ungleichheit ab, oder wenn zwei 
'\0'-Zeichen gefunden wurden.

2. Die Abwicklung eines Protokolls (und das Senden einer Antwort auf 
eine Anfrage gehört schon dazu) sollte dann nicht mehr in einer ISR 
stattfinden, sondern in einem Zustandsautomaten im Hauptprogramm.

3. Checksum! Immer Checksum!

So weit erst einmal.

LG, Sebastian

von Jim M. (turboj)


Lesenswert?

CG schrieb:
> Okay leider Funkioniert dies bei mir nicht!

Kann nicht funktionieren. Das 'B' kommt erst beim nächsten vom Master 
gesendeten Zeichen als Antwort. Und auch das nur wenn die Slave ISR 
schnell genug ausgeführt wurde, sonst noch später. SPI Slave 
Programmierung ist nicht trivial.

von CG (Gast)


Lesenswert?

Das heißt ich kann den Slave nicht im Interrupt betreiben?
Ich habe nun dieses Beispiel gefundne und dort schreibt er ja vor dem 
empfangen über SPI schon seine Antwort ins datenregister. Wenn ich da 
srichtig verstanden habe wird ja das senden und lesen gleichzeigig 
ausgeführt. Jedoch müssen doch der Master und der Slave gleichzeitig die 
Funkion aufrufen oder? Das war mein Gedanke warum ich den Slave 
Interruptgesteuert gemacht habe.

von Sebastian W. (wangnick)


Lesenswert?

CG schrieb:
> Jedoch müssen doch der Master und der Slave gleichzeitig die
> Funkion aufrufen oder?

Dort wo der Master empfangen soll kann er ja Nullen senden die der Slave 
dann ignoriert.

Strings variabler Länge sind für ein SPI-Protokoll sowieso eher 
schwierig. Versuch doch erst einmal, Daten mit fixer Grösse 
auszutauschen.

LG, Sebastian

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.