SPI Bus Kommunikation in C: Funktionen und Anwendungsbeispiele

Gesendet von Javi und eingeordnet in Informatik

Geschrieben am in Deutsch mit einer Größe von 6,96 KB

Einführung in den SPI-Bus

Der SPI-Bus (Serial Peripheral Interface) ist ein weit verbreiteter Kommunikationsstandard, der hauptsächlich für den Datentransfer zwischen integrierten Schaltkreisen in elektronischen Geräten eingesetzt wird. Es ist ein serieller, synchroner Bus, der im Vollduplex-Modus arbeitet. Er verfügt über eine Taktleitung (SCK), eine Leitung für eingehende Daten (MISO), eine für ausgehende Daten (MOSI) und einen Chip-Select-Pin (SS), der den Betrieb des Geräts, mit dem kommuniziert werden soll, aktiviert oder deaktiviert.

SPI-Bus-Verwaltung in C

Es gibt vier C-Funktionen, die mit dem SPI-Modul zusammenhängen. Diese sind jedoch nur nutzbar, wenn das Mikrocontroller-Hardware-Modul (SSP) ausgewählt ist. Es gibt auch Software-Implementierungen des SPI-Moduls. Die genannten Funktionen sind:

setup_spi()

void setup_spi(const mode);

Diese Funktion wird verwendet, um die serielle Schnittstelle (SPI) zu initialisieren und zu konfigurieren sowie den Betriebsmodus dieser Kommunikation zu definieren.

In der Header-Datei des Mikrocontrollers (.h) sind eine Reihe von Tags definiert, die mit Modi verbunden sind und in drei Gruppen unterteilt werden:

a) Modus

  • SPI_MASTER: Konfiguriert das Gerät als Master.
  • SPI_SLAVE: Konfiguriert das Gerät als Slave.
  • SPI_SS_DISABLED: Deaktiviert den SS-Pin (Chip Select).

b) Taktflanken

Konfiguriert die SPI-Übertragungsmodi in Abhängigkeit von den folgenden Kombinationen:

  • SPI_L_TO_H: Taktflanke von niedrig nach hoch (steigende Flanke).
  • SPI_H_TO_L: Taktflanke von hoch nach niedrig (fallende Flanke).
// MOTOROLA | MICROCHIP | CCS
//---------------------------------------------------------------------------------------------------
// SPI Mode 0,0 | CKP = 0, CKE = 1 | SPI_L_TO_H | SPI_XMIT_L_TO_H
// SPI Mode 0,1 | CKP = 0, CKE = 0 | SPI_L_TO_H
// SPI Mode 1,0 | CKP = 1, CKE = 1 | SPI_H_TO_L
// SPI Mode 1,1 | CKP = 1, CKE = 0 | SPI_H_TO_L | SPI_XMIT_L_TO_H

CKP = Clock Polarity Select bit
CKE = Clock Edge Select bit

c) Frequenz

Bestimmt die Frequenz, mit der der Takt schwingt. Dies wird nur verwendet, wenn das Gerät als Master konfiguriert ist, da dieser das Taktsignal generiert.

SPI_CLK_DIV_4
SPI_CLK_DIV_16
SPI_CLK_DIV_64
SPI_CLK_T2

Die oben genannten Tags werden mit dem Bit-Operator OR (|) verknüpft. Einige Beispiele:

  • Konfiguration des Geräts als Master, mit Modus B (0,1) und einer bestimmten Taktfrequenz:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
  • Konfiguration des Geräts als Slave, mit Modus C (1,0) und deaktiviertem Chip-Select-Pin:
setup_spi(SPI_SLAVE | SPI_H_TO_L | SPI_SS_DISABLED);

spi_write()

void spi_write(char c);

Diese Funktion schreibt das nächste Zeichen an den SPI-Port. Wenn das Gerät als Master konfiguriert ist, generiert es ein Taktsignal und sendet den Wert sofort. Ist das Gerät ein Slave, wird der Wert erst gesendet, wenn der Master ein Taktsignal sendet.

spi_read()

char spi_read([char c]);

Diese Funktion hat eine unterschiedliche Wirkung, je nachdem, ob das Gerät als Master oder Slave konfiguriert ist. Die Funktion liest Daten über den SPI-Bus und kann optional einen Parameter übergeben bekommen.

Als Master-Gerät:

Wenn das SPI-Gerät als Master konfiguriert ist, sendet die Funktion den Wert c, während gleichzeitig ein neuer Wert empfangen wird (z.B. d = spi_read(c)). Wenn keine Daten gesendet werden sollen, aber ein Lesevorgang erforderlich ist, wird 0 an die Funktion übergeben (z.B. d = spi_read(0)). Wenn Sie zuvor die Funktion spi_write() verwendet haben und Daten während des Schreibvorgangs lesen möchten, können Sie diese Funktion ohne Parameter aufrufen (z.B. d = spi_read()).

Als Slave-Gerät:

Wenn das Gerät als Slave konfiguriert ist, wartet die Funktion spi_read() darauf, dass das Master-Gerät das Taktsignal und die Daten an den SPI-Port sendet. Während die neuen Daten empfangen werden, sendet der Slave die Daten c an das Master-Gerät. Um zu überprüfen, ob Daten über die SPI-Schnittstelle empfangen wurden, kann die Funktion spi_data_is_in() verwendet werden.

spi_data_is_in()

char spi_data_is_in();

Diese Funktion liefert TRUE, wenn Daten über die SPI-Schnittstelle empfangen wurden.

Anwendungsbeispiel: Master-Slave-Kommunikation

Hier ist ein Beispiel für die Verwendung der erklärten Funktionen. Das Beispiel zeigt die Kommunikation zwischen einem Master- und einem Slave-Gerät. Um den Master-Code zu kompilieren, entfernen Sie die Kommentarzeichen vor #define MASTER_DEVICE.

#include <16f877.h>
#fuses HS, NOWDT // Für einen Microchip PIC16F877
#use delay(clock=10000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)
#use standard_IO(D)

//#define MASTER_DEVICE

#ifdef MASTER_DEVICE
// Master-Gerät
void main() {
    int8 c, d;
    setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
    printf("Press any key to begin\r\n"); // Added \r\n for better console output

    while (1) {
        c = getchar();
        output_D(0xFF ^ c); // Schaltet die entsprechenden LEDs an PORTD um

        // Methode 1: Senden und Empfangen in zwei Schritten
        spi_write(c);      // Sendet Daten
        d = spi_read();    // Empfängt Daten

        // Alternative Methode: Senden und Empfangen in einem Schritt
        // d = spi_read(c); // Schreibt Daten und liest gleichzeitig neue Daten

        putchar(c);
    }
}
#else
// Slave-Gerät
void main() {
    int8 c;
    setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_16);

    while (1) {
        // PIN_C2 blinkt, um Aktivität anzuzeigen
        output_low(PIN_C2);
        delay_ms(100); // 100 ms Verzögerung
        output_high(PIN_C2);
        delay_ms(100);

        // Methode 1: Prüfen, ob Daten bereit sind, bevor gelesen wird
        if (spi_data_is_in()) {
            c = spi_read();      // Liest Daten
            output_D(0xFF ^ c);  // Schaltet die entsprechenden LEDs an PORTD um
            spi_write(c);        // Sendet Daten zurück an den Master
        }

        // Alternative Methode:
        // c = spi_read(c);     // Schreibt alte Daten und liest neue
        // output_D(0xFF ^ c);  // Schaltet die LEDs an PORTD um
    }
}
#endif

Es gibt viele weitere komplexe Bibliotheken, die den Einsatz spezifischer Funktionen zur Verwaltung des SPI-Busses ermöglichen.

Verwandte Einträge: