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:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
4
(z.B. durch Übergabe als Parameter zum Compiler innerhalb
5
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
6
"nachträgliche" Definition hinweist */
7
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
8
#define F_CPU 8000000UL /* Quarz mit 3.6864 Mhz */
9
#endif
10
#include<util/delay.h>
11
12
voidSPI_MasterInit(void)
13
{
14
/* Set MOSI, SCK and SS output, all others input */
15
DDRB=(1<<PB3)|(1<<PB5)|(1<<PB2);
16
/* Enable SPI, Master, set clock rate fck/16 */
17
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR0);
18
}
19
20
voidSPI_MasterTransmit(charcData)
21
{
22
/* Start transmission */
23
SPDR=cData;
24
/* Wait for transmission complete */
25
while(!(SPSR&(1<<SPIF)));
26
}
27
28
intmain(void)
29
{
30
SPI_MasterInit();
31
while(1)
32
{
33
SPI_MasterTransmit(1);
34
_delay_ms(700);
35
SPI_MasterTransmit(0);
36
_delay_ms(300);
37
}
38
39
return0;
40
}
Slave:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
4
(z.B. durch Übergabe als Parameter zum Compiler innerhalb
5
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
6
"nachträgliche" Definition hinweist */
7
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
8
#define F_CPU 8000000UL /* Quarz mit 3.6864 Mhz */
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ß
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?
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
> 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.
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ß
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
>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.
also meinen Master hab ich zum laufen gebracht indem ich
1
tmp=SPSR;
2
tmp=SPDR;
hinzugefügt habe.
aber der Slave will noch nicht, obwohl ich hier selbiges hinzugefügt
habe.
Hier nochmal der code:
1
uint8_ttmp;
2
3
voidSPI_SlaveInit(void)
4
{
5
/* Set MISO output, all others input */
6
DDRB=(1<<PB4)|(1<<PB0)|(1<<PB1);
7
/* Enable SPI */
8
SPCR=(1<<SPE);
9
}
10
11
charSPI_SlaveReceive(void)
12
{
13
tmp=SPSR;
14
tmp=SPDR;
15
/* Wait for reception complete */
16
while(!(SPSR&(1<<SPIF)));
17
/* Return data register */
18
returnSPDR;
19
}
20
21
intmain(void)
22
{
23
SPI_SlaveInit();
24
while(1)
25
{
26
tmp=SPI_SlaveReceive();
27
if(tmp==0)PORTB|=(1<<PB0);
28
elsePORTB|=(0<<PB0);
29
}
30
31
return0;
32
}
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.
€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
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ß.
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.
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ß
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.
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:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
4
#define F_CPU 8000000UL /* Quarz mit 8 Mhz */
5
#endif
6
#include<util/delay.h>
7
#include<avr/interrupt.h>
8
9
chartmp;
10
11
voidSPI_SlaveInit(void)
12
{
13
/* Set MISO output, all others input */
14
DDRB=(1<<PB4)|(1<<PB0)|(1<<PB1);
15
/* Enable SPI und SPI-Interrupt*/
16
SPCR=(1<<SPE)|(1<<SPIE);
17
}
18
19
ISR(SPI_STC_vect)
20
{
21
PORTB^=(1<<PB0);// Toggle PB0 z.B. angeschlossene LED
22
}
23
24
intmain(void)
25
{
26
SPI_SlaveInit();
27
sei();
28
while(1)
29
{
30
}
31
32
return0;
33
}
Ersetze ich aber innerhalb der ISR die Zeile
1
PORTB^=(1<<PB0);
durch
1
tmp=SPDR;
2
if(tmp==0)PORTB&=~(1<<PB0);//LED aus
3
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.
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