Forum: Mikrocontroller und Digitale Elektronik SPI-Datenübertragung Problem /SS-Leitung


von Alexander L. (lippi2000)


Angehängte Dateien:

Lesenswert?

Hallo,
habe eine SPI-Master-Slave Schnittstelle zwischen zwei AVR aufgebaut.

Die Daten für den Master (ATMega8) kommen von der RS232 und sollen an 
den Slave (ATMega32) versendet werden. Damit der Master weiß, wann die 
Ausführung am Slave abgeschlossen ist und ein datenbyte zurückgelesen 
werden kann, habe ich eine zusätzliche /ACK-Leitung eingebaut. Diese ist 
für 50us LOW und wechselt dann wieder auf HIGH. Anschließend schreibt 
der Master eine 0x00 an den Slave um die Antwortdaten über MISO zu 
empfangen.

Nun mein Problem: Der Master erkennt nicht wann er die 8Bit übertragen 
hat und nimmt dann zu früh das /SS zurück.
1
#define F_CPU 16000000L                    //CPU-Frequenz
2
#define BAUD 9600L                      //Baudrate
3
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)        //Runden für Prescaler
4
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))          //reale Baudrate
5
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)        //Fehler in Promille
6
//Compilerausgabe bei Fehler
7
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
8
#error Systematischer Fehler der Baudrate ist größer 1% und damit zu hoch!
9
#endif
10
11
12
13
#include<avr/io.h>
14
#include<avr/interrupt.h>
15
16
unsigned char temp=0;
17
18
19
int main(void)
20
{PORTB = (1<<PORTB2)|(1<<PORTB0);                //PB0,PB2 ist 1
21
 DDRB = 0x2C;                          //SCK,MOSI,/SS = Ausgang
22
  //UART Initialisierung
23
 UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);            //8 Bit + 2 Stoppbit
24
 UBRRL = UBRR_VAL;                        //Baudrate setzen
25
 UBRRH = (UBRR_VAL>>8);
26
 //SPI-Initialisierung
27
 SPSR = (0<<SPI2X);
28
 SPCR = (1<<SPE)|(1<<MSTR)|(2<<SPR0);              //SPI-Mode 0; 250kHz
29
  
30
31
 //Hauptprogramm
32
 UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);            //RX-IRQ enable;TX & RX enable
33
 sei();
34
 while(1);
35
   {};
36
37
 };
38
39
40
ISR(USART_RXC_vect)
41
{cli();
42
 PORTB &= ~(1<<PORTB2);                      //slave select = low
43
 SPDR=UDR;                            //daten von RS232 an SPI schreiben
44
                         
45
 while(PINB&(1<<PINB0))                      //warte auf ACK = low
46
      {};
47
 while(!(PINB&(1<<PINB0)))                    //warte auf ACK = high
48
      {};
49
 SPDR=0x00;
50
 while(!(SPSR & (1 << SPIF)));      //Warte bis daten gesendet 
51
 
52
 PORTB |=(1<<PORTB2);
53
 UDR = SPDR;                          //daten von SPI an RS232 schreiben
54
 while(!(UCSRA&(1<<UDRE)))                    //TxD complete
55
           {};
56
 sei();
57
}

Anbei noch eine Messung...siehe data2 da sollte /SS noch low sein.

von Deejay (Gast)


Lesenswert?

Hi,

versuch mal das Flag SPIF im Register SPSR zurückzusetzen, bevor Du mit 
der While-Schleife auf das Ende der Übertragung wartest. Was genau Du 
zum Zurücksetzen tun musst, findest im Datenblatt bei der Beschreibung 
des Flags.

Bye
  Deejay

von Alexander L. (lippi2000)


Lesenswert?

Danke, habs gerade gefunden.
Im Datenblatt ist nichts genaues geschrieben. In ner APP von Atmel steht 
drinne, dass man erst SPSR und dann SPDR auslesen muss um das Flag zu 
löschen.
1
ISR(USART_RXC_vect)
2
{cli();
3
 PORTB &= ~(1<<PORTB2);                      //slave select = low
4
 SPDR=UDR;                            //daten von RS232 an SPI schreiben
5
                         
6
 while(PINB&(1<<PINB0))                      //warte auf ACK = low
7
      {};
8
 while(!(PINB&(1<<PINB0)))                    //warte auf ACK = high
9
      {};
10
 temp=SPSR;
11
 temp=SPDR;
12
 SPDR=0x00;
13
 while(!(SPSR & (1 << SPIF)));
14
 
15
 PORTB |=(1<<PORTB2);
16
 UDR = SPDR;                          //daten von SPI an RS232 schreiben
17
 while(!(UCSRA&(1<<UDRE)))                    //TxD complete
18
           {};
19
 sei();
20
}

So geht's jetzt.

Trotzdem Danke.

von Daniel J. (deejay)


Lesenswert?

Hi,

also in dem Datenblatt, dass ich kenne, steht das genau so drin ;-)
Aber freut mich, dass es jetzt geht.

Bye
 Deejay

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.