mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 2 ATMega8 über SPI kommunizieren lassen


Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
also der erste µC soll periodisch dem zweiten eine 1 und eine 0 senden. 
Der zweite µC soll bei einer empfangenen 1 eine am PB0 angebrachte LED 
zum leuchten bringen und bei 0 diese wieder aus machen. Simpel, klappt 
aber dennoch nicht. Die Initialisierung und Sende/Empfangsmethoden hab 
ich direkt aus dem Datenblatt. SS ist bei Master als Output konfiguriert 
und beim Slave auf Masse gesetzt.

Code des Masters:
#include <avr/io.h>
#ifndef F_CPU
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert 
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb 
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
   "nachträgliche" Definition hinweist */
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
#define F_CPU 8000000UL     /* Quarz mit 3.6864 Mhz */
#endif
#include <util/delay.h>

void SPI_MasterInit(void)
{
  /* Set MOSI, SCK and SS output, all others input */
  DDRB = (1<<PB3)|(1<<PB5)|(1<<PB2);
  /* Enable SPI, Master, set clock rate fck/16 */
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}

void SPI_MasterTransmit(char cData)
{
  /* Start transmission */
  SPDR = cData;
  /* Wait for transmission complete */
  while(!(SPSR & (1<<SPIF)));
}
 
int main( void )
{
SPI_MasterInit();
while (1)
  {
  SPI_MasterTransmit(1);
  _delay_ms(700);
  SPI_MasterTransmit(0);
  _delay_ms(300);
  }  
  
    return 0;
}


Slave:
#include <avr/io.h>
#ifndef F_CPU
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert 
   (z.B. durch Übergabe als Parameter zum Compiler innerhalb 
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
   "nachträgliche" Definition hinweist */
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
#define F_CPU 8000000UL     /* Quarz mit 3.6864 Mhz */
#endif
#include <util/delay.h>

void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB4)|(1<<PB0);
/* Enable SPI */
SPCR = (1<<SPE);
}

char SPI_SlaveReceive(void)
{
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF)))
;
/* Return data register */
return SPDR;
}
 
int main( void )
{
  while(1)
  {
    if (SPI_SlaveReceive() == 1) PORTB |= (1 << PB0);
    if (SPI_SlaveReceive() == 0) PORTB |= (0 << PB0); 
  }
    
    return 0;
}


was ist da noch falsch?

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also als erstes initialisierst du nicht den SPI_SLAVE !
Zweitens dein delay_ms geht nicht.
Ausschnitt aus der delay.cpp :
The maximal possible delay is 262.14 ms / F_CPU in MHz.

Gruß

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ausserdem würde ich beim Slave lieber:

int main( void )
{
  SpiSlaveInit();
  unsigned char rec;
  while(1)
  {
    rec = SPI_SlaveReceive();
    if (rec == 0x01){ PORTB |= (1 << PB0);}
    else { PORTB |= (0 << PB0); }
  }

    return 0;
}


Ansonsten kanns passieren und er empfängt die 1 und vergöeicht aber mit 
0,......


Gruss

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt da hab ich vergessen die Init beim Slave aufzurufen, ändert aber 
nichts daran das nichts geht.
Also die Delay Funktion geht bei mir schon, auch eine ganze Sekunde 
funktioniert tadellos.

Ich hab mal beim Oszi SCK angeschaut, wenn ich flashe ist da deutlich 
was zu sehn, beim Senden vom Master aber nichts. Also müsste schon beim 
code vom Master was falsch sein. Reicht es das SS als Output 
konfiguriert ist oder muss der zusätzlich auch auf high gesetzt werden?

Autor: Marius Wensing (mw1987)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Ostner wrote:
> Zweitens dein delay_ms geht nicht.
> Ausschnitt aus der delay.cpp :
> The maximal possible delay is 262.14 ms / F_CPU in MHz.

Das war früher mal so. Inzwischen kann die avr-libc (seit Version 1.6) 
auch mit sehr langen delays umgehen. Die sind zwar nicht mehr so genau, 
aber mehr als ausreichend.

MfG
Marius

Autor: nixversteh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Reicht es das SS als Output
> konfiguriert ist oder muss der zusätzlich auch auf high gesetzt werden?
Datenblatt, S.129
If SS is configured as an output, the pin is a general output pin which 
does not affect the
SPI system. Typically, the pin will be driving the SS pin of the SPI 
Slave.
If SS is configured as an input, it must be held high to ensure Master 
SPI operation. If
the SS pin is driven low by peripheral circuitry when the SPI is 
configured as a Master
with the SS pin defined as an input, the SPI system interprets this as 
another Master
selecting the SPI as a Slave and starting to send data to it.

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
also wenn dein _delay funzt ist das reines Glück, weil in der _delay 
wird mit einem uint16 gearbeitet, kann also wie schon oben gepostet nit 
gehen.
Schau selber in der _delay_ms nach, oder besser glaub mir einfach.

Das SS brauchste jetzt erstmal nit, erst bei mehreren Slaves oder wenn 
du später mal den Slave schlafen schickst.

Mach mal zum Test statt deiner _delay_ms(700):
int i;
for(i=0 ; i<=140; i++)
{
  _delay_ms(5);
}

und bei deiner _delay_ms(300):
for(i=0 ; i<=60; i++)
{
   _delay_ms(5);
}


Später nimmste besser Timer und Interrupts.

Gruß

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@MArius:
Hmm na gut will ich glauben, bei mir gehts nit. Aber auch keine Ahnung 
welche Version ich habe.

Gruß

Autor: Marcel K. (viewer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Erich,
vielleicht hilft dir das hier:
///////////////////////////////////
#define SS        PORTB_Bit4
#define DDR_SS    DDRB_Bit4
#define DDR_MOSI  DDRB_Bit5
#define DDR_MISO  DDRB_Bit6

#define ACTIVATE_SLAVE(){   SS        = LOW;}
#define DEACTIVATE_SLAVE(){ SS        = HIGH;}

#define PIN_INIT_MASTER(){  DDR_SS    = 1;\
                            DDR_MOSI  = 1;\
                            DDR_SCK   = 1;}


#define PIN_INIT_SLAVE(){   DDR_MISO  = 1;}



void init_spi_master_mode(void)
{
  PIN_INIT_MASTER();
  ACTIVATE_SLAVE();
}
void init_spi_slave_mode(void)
{
  PIN_INIT_SLAVE();
}
///////////////////////////////////

Ist ein Codeschnippsel aus meiner include. (Schreibe mit IAR)

Bitte vergewissere dich auch, dass der SS Pin den richtigen Wert hat. 
(input/output; high/low) Sonnst funzt das ganze nicht. es gibt auch ein 
Application Note bei Atmel. Dort findet man auch einiges.

Gruße, Marcel

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hoffe dein Progger hängt nicht am SPI ^^.

Gruß

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich hoffe dein Progger hängt nicht am SPI ^^.
hehe, nein, das nicht.

@Marcel
warum hast du im Init_Master_Mode ein Activate_Slave? SS soll doch beim 
Master auf high gehalten werden.

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also meinen Master hab ich zum laufen gebracht indem ich
tmp = SPSR;
tmp = SPDR;
hinzugefügt habe.

aber der Slave will noch nicht, obwohl ich hier selbiges hinzugefügt 
habe.
Hier nochmal der code:
uint8_t tmp;

void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB4)|(1<<PB0)|(1<<PB1);
/* Enable SPI */
SPCR = (1<<SPE);
}

char SPI_SlaveReceive(void)
{
tmp = SPSR;
tmp = SPDR;
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF)));
/* Return data register */
return SPDR;
}
 
int main( void )
{
  SPI_SlaveInit();
  while(1)
  {
    tmp = SPI_SlaveReceive();
    if (tmp == 0) PORTB |= (1 << PB0);
    else PORTB |= (0 << PB0); 
  }
    
    return 0;
}
Die Pin Vebindung hab ich jetzt so oft überprüft, die müsste stimmen. 
Aber was nun im code noch fehlt/falsch ist....keine Ahnung.
Ich hoffe mir kann da jemand weiter helfen.

Autor: Marcel K. (viewer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
€Erich:
Du hast Recht. SO NICHT!! :o) Ist wohl beim koieren etwas nicht so 
richtig gelaufen. Muss ich dann noch mal da Heim prüfen!!
Ich glaube Dir das Du die Pinverbindung geprüft hast. Hast Du aber auch 
mit einem Messgerät mal am /CS gemessen? Auch mal den Master am /CS des 
Slaves getrennt und den /CS des Slaves fest auf Masse gelegt? Da habe 
ich nämlich gemerkt dass bei mir etwas nicht gestimmt hat!!

Grüße, Marcel

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
der Master sollte auch gehen ohne dieses tmp = .... Zeugs.
Ansonsten häng doch einfach mal den SS Pin vom MAster an einen PortPin 
von deinem Slave. Frage diesen in der while Schleife ab und falls Low 
dann springe in den Receive Teil.

Gruß.

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du mit CS SlaveSelect meinst, dann ja, den habe ich die ganze Zeit 
auf GND gelegt gehabt.

Fabian, als ich das Auslesen von SPSR und SPDR hinzugefügt habe, habe 
ich ein Ausgangssignal bekommen, davor nicht.

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ja mein Fehler meinte den SS-Pin.
Hmm das mit den SPDR und SPSR auslesen sollte überflüssig sein, wenn du 
Lust hast, dann kompiliere doch mal deinen Code ohne die Register 
auszulesen und stell mal die LSS-Datei hier rein. Mal schauen, ob da was 
wegoptimiert wird oder so.
Gruß

Autor: Erich (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
so jetzt hab ich das mal gemacht. Allerdings hat das ja nichts mit 
meinem eigentlichen Problem zu tun, dem Empfangen von den SPI Signalen.

Hatte mir das einfacher vorgestellt eine 1 bzw. 0 über SPI zu versenden. 
Dass ich da schon 2 Wochen dran rum mach ist schon zum verzweifeln.

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab die Empfangsroutine des Slaves mal für den Interrupt-Betrieb 
umgeschrieben. Und hier empfange ich tatsächlich etwas. Die ISR wird zu 
den richtigen Zeitpunkten aufgerufen:
#include <avr/io.h>
#ifndef F_CPU
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
#define F_CPU 8000000UL     /* Quarz mit 8 Mhz */
#endif
#include <util/delay.h>
#include <avr/interrupt.h>

char tmp;

void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB4)|(1<<PB0)|(1<<PB1);
/* Enable SPI und SPI-Interrupt*/
SPCR = (1<<SPE)|(1<<SPIE);
}

ISR(SPI_STC_vect)
{
PORTB ^= ( 1 << PB0 );  // Toggle PB0 z.B. angeschlossene LED
}
 
int main( void )
{
  SPI_SlaveInit();
  sei();
  while(1)
  {
  }
    
    return 0;
}
Ersetze ich aber innerhalb der ISR die Zeile
PORTB ^= ( 1 << PB0 );
durch
tmp = SPDR;
if (tmp == 0) PORTB &= ~(1<<PB0); //LED aus
if (tmp == 1) PORTB |= (1<<PB0); //LED an
dann bleibt die LED aus (PB0 auf low). Sprich es wird etwas übertragen, 
aber es kommt etwas falsches an. Bei einem Leitungsweg von 10cm dürfte 
das doch aber nicht der Fall sein.
Kann doch nicht sein dass das so schwierig ist.

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe keine Ahnung warum es auf einmal funktioniert, aber es 
funktioniert. Zig mal mit den Geschwindigkeiten rum gespielt, dutzende 
male geflasht und auf einmal gehts mit dem Code wie er ein Posting 
drüber da steht. Fragt mich nicht warum.

Btw. Fabian Ostner...
>Ich hoffe dein Progger hängt nicht am SPI ^^.
geht trotzdem

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.