Forum: Mikrocontroller und Digitale Elektronik ATmega8 über SPI mit ATtiny85 verbinden


von Konstantin L. (konze)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich versuche derzeit einen ATmega8 mit einen ATtiny85 über SPI zu 
verbinden (später soll der ATtiny85 die Werte an seinem ADC an den 
ATmega8 weitergeben).

Hierzu läuft auf dem ATmega8 ein SPI Master. Gesteuert wird der ATmega8 
über UART mit dem Computer. Wenn vom Computer aus das Signal 'send\n' 
geschickt wird dann übertragt der ATmega8 ein Byte (hier 97 == 'a') über 
den SPI Bus. Anschließend soll der ATtiny85 das gesendete Byte um 1 
erhöhen und zurück an den ATmega8 übertragen. Leider scheint mir der 
ATtiny immer nur 255 zurück zusenden anstatt 98 == 'b'.

Die beiden Controller sind wie folgt miteinander verbunden:

   ATmega8 -- ATtiny85

       GND -- GND
  PB2 (SS) -- PB4 (soll später als Slave Select verwendet werden)
PB3 (MOSI) -- PB1 (MISO)
PB4 (MISO) -- PB0 (MOSI)
 PB5 (SCK) -- PB2 (SCK)

Hier ist der Code für den ATmega8 (Master)
(In uart.h befindet sich der Code für die Kommunikation mit dem 
Computer)
1
#define F_CPU 8000000UL
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/wdt.h>
6
#include <util/delay.h>
7
#include <stdlib.h>
8
9
#include "uart.h"
10
11
uint8_t spi_tranceiver (uint8_t data);
12
13
void process_command(uint8_t * command) {
14
  
15
    uint8_t success = 0;
16
17
    
18
    if(strcmp(command, "send") == 0) {
19
        uint8_t send_byte = 97;
20
21
22
        int i;
23
24
        uart_puts("send: ",6);
25
26
        for(i = 7; i >= 0; i--) {
27
            if((send_byte & (1 << i)) == (1 << i)) {
28
                uart_putc('1');
29
            } else {
30
                uart_putc('0');
31
            }
32
        }
33
34
        uart_putc('\n');
35
        uart_putc('\r');
36
37
38
        uint8_t received_byte = spi_tranceiver(send_byte);
39
40
        uart_puts("recv: ",6);
41
42
        for(i = 7; i >= 0; i--) {
43
            if((received_byte & (1 << i)) == (1 << i)) {
44
                uart_putc('1');
45
            } else {
46
                uart_putc('0');
47
            }
48
        }
49
50
        uart_putc('\n');
51
        uart_putc('\r');
52
    }
53
54
    if(success == 1) {
55
        uart_puts("ack\n",4);
56
    }
57
}
58
59
void spi_init_master (void) {
60
    DDRB = (1<<5)|(1<<3);              //Set MOSI, SCK as Output
61
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); //Enable SPI, Set as Master
62
                                       //Prescaler: Fosc/16, Enable Interrupts
63
}
64
65
//Function to send and receive data
66
uint8_t spi_tranceiver (uint8_t data) {
67
    SPDR = data;                       //Load data into the buffer
68
    while(!(SPSR & (1<<SPIF) ));       //Wait until transmission complete
69
    return(SPDR);                      //Return received data
70
}
71
72
uint8_t main (void) {
73
74
    // enable interrupts
75
    sei();
76
77
    // enable uart
78
    uart_init(); 
79
    spi_init_master();
80
81
    sei();
82
83
    // send ready
84
    uart_puts("ready\n\r", 7);
85
86
    uint8_t * command;
87
    uint8_t command_in_queue;
88
89
    while(1) {
90
        command_in_queue = command_queue_pop(&command);
91
        
92
        if(command_in_queue == 0) {
93
            process_command(command);
94
            free(command);
95
        }
96
    }
97
98
    return 0; 
99
}

Auf dem ATtiny85 läuft der folgende Code
1
#define F_CPU 8000000UL
2
3
#include <avr/io.h>
4
5
6
// Set USI to slave mode - do this at startup
7
void spi_init_slave() {
8
    USICR = (1<<USIWM0)|(1<<USICS1);
9
}
10
11
// Receive a byte from the master
12
uint8_t spi_tranceiver() {
13
14
    // Clear counter overflow flag
15
    USISR = (1<<USIOIF);
16
17
    // Wait for complete byte to arrive
18
    while ((USISR & (1<<USIOIF))==0) {}
19
20
    // Return received byte
21
    uint8_t byte = USIDR;
22
    USIDR = byte+1;
23
}
24
25
26
uint8_t main(void) {
27
28
    spi_init_slave();
29
30
    while(1) {
31
        spi_tranceiver();
32
    }
33
    
34
    return 0;
35
36
}

Im angehängten Bild ist die Kommunikation zwischen dem Computer und dem 
ATmega8 aufgezeichnet. Hier Protokolliert der ATmega8 die SPI 
Kommunikation mit dem ATtiny85. Könnt ihr mir einen Tipp geben?

Vielen Dank und viele Grüße

Konze

von Thomas E. (thomase)


Lesenswert?

Konstantin L. schrieb:
> DDRB = (1<<5)|(1<<3);              //Set MOSI, SCK as Output

SS muss als Ausgang konfiguriert sein. Sonst ist der Pin die externe 
M/S-Umschaltung.

mfg.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Konstantin L. schrieb:
> Anschließend soll der ATtiny85 das gesendete Byte um 1 erhöhen und
> zurück an den ATmega8 übertragen.
Dir ist klar, wie SPI funktioniert? Nein?
SPI sind einfach gekoppelte Schieberegister. Siehe dort in der Mitte:
http://www.lothar-miller.de/s9y/categories/17-SPI

Nachdem der SlaveSelect-Fehler behoben ist:
Um von einem SPI-Slave etwas zu "empfangen" musst du vom Master 
irgendetwas  "senden". Denn für jedes Bit, das du vom Master sendest 
kommt exakt gleichzeitig ein Bit vom Slave zurück. Du bekämst mit 
diesem Programm also immer deine Daten um einen Zyklus "versetzt" 
zurück.

Siehe den Beitrag "Erstes Byte über SPI immer falsch"

Und da war doch vor kurzem so ein unerfreulicher Thread zum selben Thema 
"Verbinden von 2 uC mit SPI", der es aber trotzdem wert ist, gelesen zu 
werden:
Beitrag "Re: SPI 16-Bit Problem"

: Bearbeitet durch Moderator
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.