Forum: Mikrocontroller und Digitale Elektronik ATTiny2313 mit ATMega32 über SPI


von Jens K. (mister232)


Lesenswert?

Hallo Leute,
habe folgendes Problem:
Ich versuche gerade zwei Mikrocontroller miteinander über SPI 
kommunizieren zu lassen. Ein Kommunikation zwischen zwei ATMega32 ist 
mir bereits gelungen. Leider Möchte der ATTiny2313 aber irgendwie nicht 
mit dem ATMega32 sprechen :-(
Nach langem Suchen in unzälligen Foren und stundenlanges Wälzen des 
Datenblattes habe ich ein Programm geschrieben, welches eigentlich 
funktionieren sollte. Vielleicht könnt ihr mir ja mal wieder auf die 
Sprünge helfen :-)

Hier der Code des Master (ATMega32):
1
/*
2
 * SPI_Master.c
3
 *
4
 * Created: 06.07.2013 21:05:31
5
 *  Author: Jens
6
 */ 
7
8
// This program is for the SPI-Master on an ATMega device
9
10
#include <avr/io.h>
11
#include <util/delay.h>
12
13
// Initialize the SPI-Interface
14
void init_spi()
15
{
16
  //Set MOSI, clock pin and SS pin as output.  Not using
17
  //  the SS pin at this point.
18
  DDRB = (1<<DDB4) | (1<<DDB5) | (1<<DDB7);
19
  
20
  //Enable SPI mode, master and F_CPU/16.  Slowed it down so
21
  //  could see what is going on with scope.
22
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
23
}
24
25
// Send data via SPI
26
void send_spi(int data)
27
{
28
  // Load the data into the data register
29
  SPDR = data;
30
  
31
  // Wait until data is transmitted
32
  while(!(SPSR & (1<<SPIF)));
33
  
34
  // Wait 500ms before sending the next Byte
35
  _delay_ms(500);
36
}
37
38
int main(void)
39
{
40
  int data;
41
  
42
  // Set LED-Port PB2 and PB3 as output
43
  DDRB = (1<<DDB3) | (1<<DDB2);
44
  
45
  init_spi();
46
  
47
  data = '5';
48
  
49
  // Send 5, 6, 5, 6, 5, ...
50
    while(1)
51
    {
52
         if(data == '5')
53
     {
54
      // Send '5' and turn on LED1 and off LED2
55
      send_spi(data);
56
      data = '6'; 
57
      PORTB = (1<<PB3);
58
      PORTB &= ~(1<<PB2);
59
     }
60
     else
61
     {
62
      // Send '6' and turn on LED2 and off LED1
63
      send_spi(data);
64
      data = '5'; 
65
      PORTB = (1<<PB2);
66
      PORTB &= ~(1<<PB3);
67
     }
68
    }
69
  
70
  return 0;
71
}

und hier der des Slave (ATTiny2313):
1
/*
2
 * SPI_Slave.c
3
 *
4
 * Created: 07.07.2013 10:59:29
5
 *  Author: Jens
6
 */ 
7
8
// This program is for an SPI-Slave Tiny device
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/delay.h>
13
14
int data;
15
16
// Initialize SPI-Interface
17
void init_spi()
18
{
19
  // Set DO as output and DI, USCK as input
20
  DDRB = (1<<DDB6);
21
  DDRB &= ~(1<<DDB5) | ~(DDB7);
22
  
23
  // Set 3-wire-mode and external positive clock
24
  USICR = (1<<USIWM0) | (1<<USICS1);
25
  
26
  // Set the counter-overflow flag
27
  USISR = (1<<USIOIF);
28
  
29
  // Enable interrupt for counter-overflow when data is received
30
  USISR = (1<<USISIF);
31
  
32
}
33
34
ISR(USI_OVERFLOW_vect) 
35
{
36
  // Wait for reception complete 
37
  while(!(USISR & (1<<USIOIF)));
38
  
39
  // Return data register
40
  data = USIDR;
41
  
42
}
43
44
int main(void)
45
{
46
  // Set LED-Ports PB2 (LED1) and PB3 (LED2) as output
47
  DDRB = (1<<DDB2) | (1<<DDB3);
48
  
49
  init_spi();
50
  
51
  // If data is received via SPI, check if it is an '5' or an '6'. 
52
  // Then turn on the corresponding LED
53
    while(1)
54
  {  
55
    // Check if "data" includes an '5' -> Turn on LED1 PB2
56
    if(data == '5')
57
    {
58
        PORTB = (1<<PB2);
59
        PORTB &= ~(1<<PB3);
60
    }
61
    // Check if "data" includes an '6' -> Turn on LED2 PB3
62
    else if(data == '6')
63
    {
64
        PORTB = (1<<PB3);
65
        PORTB &= ~(1<<PB2);
66
    }
67
    }
68
  
69
  return 0;
70
}

von Jens K. (mister232)


Lesenswert?

Niemand da der mir weiterhelfen kann?

von Jens K. (mister232)


Lesenswert?

Muss für die Kommunikation evtl. ein externer Quarz angeschlossen sein 
oder geht es auch ohne?

von Martin (Gast)


Lesenswert?

Keine ISR Funktion eingeschaltet oder wo ist das sei() ?
Return wert ist auch eher fraglich, variablen den wenigsten als
volatile gesetzt ?

von Jens K. (mister232)


Lesenswert?

Hab das sei() jetzt vor das init_spi() in der main-Funktion gepackt und 
data als volatile int deklariert. Leider funktioniert es immernoch nicht 
:-(

von Jens K. (mister232)


Lesenswert?

Es funktioniert nun.. hatte die falsche Datei geflashed... :-)
Danke!

von Jens K. (mister232)


Lesenswert?

Hier nochmal der neue Slave-Code für alle die wissen wollen wie es 
funktioniert (ich hab ja selber ewig gesucht):
1
/*
2
 * SPI_Slave.c
3
 *
4
 * Created: 07.07.2013 10:59:29
5
 *  Author: Jens
6
 */ 
7
8
// This program is for an SPI-Slave Tiny device
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/delay.h>
13
14
volatile int data;
15
16
// Initialize SPI-Interface
17
void init_spi()
18
{
19
  // Set DO as output and DI, USCK as input
20
  DDRB = (1<<DDB6);
21
  DDRB &= ~(1<<DDB5) | ~(DDB7);
22
  
23
  //Enable USI overflow interrupt, set three wire mode and set
24
  //  clock to External, positive edge.
25
  USICR = (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1);
26
  
27
  //Clear overflow flag
28
  USISR = (1<<USIOIF);
29
  
30
  // Global enable interrupts
31
  sei();
32
}
33
34
ISR(USI_OVERFLOW_vect) 
35
{
36
  // Return data register
37
  data = USIDR;
38
  
39
    // Reset counter-overflow Flag   
40
   USISR = (1<<USIOIF);  
41
}
42
43
int main(void)
44
{
45
  // Set LED-Ports PB2 (LED1) and PB3 (LED2) as output
46
  DDRB = (1<<DDB2) | (1<<DDB3);
47
  
48
  init_spi();
49
  
50
  // If data is received via SPI, check if it is an '5' or an '6'. 
51
  // Then turn on the corresponding LED
52
    while(1)
53
  {  
54
    // Check if "data" includes an '5' -> Turn on LED1 PB2
55
    if(data == '5')
56
    {
57
        PORTB = (1<<PB2);
58
        PORTB &= ~(1<<PB3);
59
    }
60
    // Check if "data" includes an '6' -> Turn on LED2 PB3
61
    else if(data == '6')
62
    {
63
        PORTB = (1<<PB3);
64
        PORTB &= ~(1<<PB2);
65
    }
66
    }
67
  
68
  return 0;
69
}

von Peter D. (peda)


Lesenswert?

Jens K. schrieb:
> // Wait 500ms before sending the next Byte
>   _delay_ms(500);

So gehts natürlich.

Aber wenn der Master mehrere Bytes hintereinander senden/empfangen soll, 
kommt der Slave nicht mehr mit.

Wenns zuverlässig sein soll, brauchst Du einen Slave mit mindestens 1 
Byte HW-Puffer (Senden+Empfangen).
Z.B. AT89LP4052

von Jens K. (mister232)


Lesenswert?

Eine Sache wäre da auch noch: Wenn ich den SPI oder USI initialisiere 
und nutze leuchten die LEDs, im gegensatz zu einem vorherigem Programm 
wo ich sie nur toggle, sehr schwach. Woran liegt das und wie kann ich 
das ändern?

von spess53 (Gast)


Lesenswert?

Hi

>    // Reset counter-overflow Flag
>   USISR = (1<<USIOIF);

Ist unnötig. Das Macht der Interrupt schon.

>Eine Sache wäre da auch noch: Wenn ich den SPI oder USI initialisiere
>und nutze leuchten die LEDs, im gegensatz zu einem vorherigem Programm
>wo ich sie nur toggle, sehr schwach. Woran liegt das und wie kann ich
>das ändern?

>  // Set LED-Ports PB2 (LED1) and PB3 (LED2) as output
>  DDRB = (1<<DDB2) | (1<<DDB3);

>void init_spi()
>{
>  // Set DO as output and DI, USCK as input
>  DDRB = (1<<DDB6);
>  DDRB &= ~(1<<DDB5) | ~(DDB7);

Fällt dir etwas auf?

MfG Spess

von Jens K. (mister232)


Lesenswert?

Jo, das "1<<" fehlt, werde es nachher mal ausprobieren

von spess53 (Gast)


Lesenswert?

Hi

>Jo, das "1<<" fehlt, werde es nachher mal ausprobieren

Das ist nicht alles.

MfG Spess

von Jens K. (mister232)


Lesenswert?

Was fehlt den noch oder ist noch falsch, finde es nicht.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

>  DDRB &= ~(1<<DDB5) | ~(DDB7);
das macht nicht was du willst

>  DDRB &= ~(1<<DDB5) | ~(1<<DDB7);
das aber auch nicht ;-)

von spess53 (Gast)


Lesenswert?

Hi

>Was fehlt den noch oder ist noch falsch, finde es nicht.

In deiner Main kommt erst:

>  DDRB = (1<<DDB2) | (1<<DDB3);

Danach rufst du init_spi() auf, in der steht:

>  DDRB = (1<<DDB6);

Welchen Wert hat DDRB danach?

MfG Spess

von Jens K. (mister232)


Lesenswert?

Ah... Jetzt klappts, danke

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.