SPI per Software

Gast #112308
Lesenswert?

Hallo zusammen,

leider hat die Suche im Forum nichts erbracht.
Folgendes Problem: Ich möchte auf einem AT89C52 ein SPI Interface
realisieren. Entsprechende und für meine Anwendung funktionierende
Assembler-Routinen habe ich schon geschrieben. Allerdings muss ich mich
mit C beschäftigen, und davon hab ich leider nicht viel Ahnung.

1. Wie kann ich das Einlesen und Ausgeben realisieren?
2. Gibt es irgendwo eine Sammlung solcher Code-Schnipsel, damit sich
Anfänger nicht so schwer tun?

Danke

Gruß Ralf
#112312
Lesenswert?

In C ist es egal, ob 8051, MSP, ARM oder AVR.

Allerdings hat der 8051 spezielle Erweiterungen, um auf Portpins
zugreifen zu können. Damit kann man den Code noch etwas optimieren.
Funktionieren tuts aber auch ohne.

Wenn Du kein C kannst, solltest Du es zuerst lernen, z.B. mit
Borland-C.

Ein Bespiel zu schreiben und dann kapierst Du es nicht, dazu hat keiner
Lust.

Für SPI mußt Du for, if, &, |, <<, >> kennen.


Peter
Gast #112313
Lesenswert?

doch, sicher.
Aber geh doch andersherum ran: wenn du verstanden hast, wie das
physikalisch funktioniert, klappt das auch mit der Programmierei. Wenn
du dich mit C beschäftigen willst, nutzt es dir doch nichts,
vorgekauten Kram zu bekommen. Nichts ist dafür besser als eigene
Erfolgserlebnisse.
Gast #112314
Lesenswert?

@Peter:

Mach mir ein Beispiel, und ich sag dir, ob ich es verstanden habe ;-)
Nein, im Ernst, ich verstehe dich. FOR, IF, &, |(oder), sowie << und >>
(shiften bzw. rolieren), ist alles klar. Mein Problem war eher, dass ich
den Lösungsansatz suche, inzwischen habe ich eine der Routinen zum
laufen bekommen, aber auf diese Lösungsart bin ich nicht gekommen, weil
ich sie so nicht ERWARTET habe. Da hilft denke ich nur Input von denen,
die es können.

@Crazy Horse:

Wie ich Peter bereits sagte, auf den Lösungsansatz muss man gefasst
sein. Aber das mit den Erfolgserlebnissen, da hast du freilich recht.

Gruß Ralf
#112316
Lesenswert?

Welche Lösung hast Du denn gefunden ?
Es gibt ja so viele.
Hier z.B. eine, die die Bits nicht nur in auf- oder absteigender
Reihenfolge, sondern x-beliebig senden kann:

http://www.mikrocontroller.net/forum/read-4-22246.html

Das Beispiel von crazy horse ist auch eine, wenn auch nicht sehr
effektiv. Ehe man eine extra Maskenbyte schiebt, ist es schneller und
kürzer, wenn man das Datenbyte selbst schiebt. In der Regel braucht man
nämlich das Datenbyte danach nicht mehr bzw. kann damit gleichzeitig die
empfangenen Bits reinschieben.


Peter
Gast #112317
Lesenswert?

Hi Crazy Horse,

also... Ist die Routine zum SPI-Schreiben nicht ein bisschen dick?
Meine sieht so aus:

SPI_OUT(unsigned char output) {
  unsigned char i;

  for (i = 8; i; i--) {
  SCK = 0;
  MOSI = output & 0x01;
  output = output >> 1;
  SCK = 1;
  }
}

Oder übersehe ich irgendwo etwas in deiner Routine? Ich nehme an, du
machst weiche Ware für einen AVR oder so, vielleicht macht die Routine
da so mehr Sinn.

Gruß Ralf
Gast #112318
Lesenswert?

"Das Beispiel von crazy horse ist auch eine, wenn auch nicht sehr
effektiv" - ich wusste, dass das von dir kommt :-)

weiss ich selbst, aber man versteht es eigentlich recht gut, wie es
funktioniert. Man braucht auch keinen extra loop-Zähler.
Gast #112319
Lesenswert?

@Ralf: nicht immer ist ein einfacher aussehendes C-Programm auch die
optimale Lösung im Endergebnis, kommt natürlich auch auf den Compiler
an.
Konkret, (rein Interese halber habe mal beides compiliert) und siehe
da:
dein C-Code erzeugt 4 words mehr Maschinencode (absolut 19 zu 23) und
benötigt 271 Takte statt 193 bei meinem.
Gast #112320
Lesenswert?

@crazy horse:

Ich wollte dir auch nicht auf die Hufe... äh... Füsse treten. Du hast
den Code jetzt für einen AVR generiert, oder? Ich werd bei Gelegenheit
mal deinen für den 8051 generieren, mal sehen, ob meiner da auch so
groß ist im Gegensatz zu deinem. In dem Fall würde ich deinen nehmen,
wenn da kein Copyright drauf ist :-)

Gruß Ralf
Gast #112322
Lesenswert?

Noch ein Test, ohne extra loop-counter

void write_spi (unsigned char data_out){       //msb first
unsigned char mask;
for (mask=0x80; mask; mask=mask>>1)
    {sclk=0;
    if (data_out & mask) mosi=1;
    else mosi=0;
    sclk=1;
    }
}
schlägt mit 16 words und 159 Takten (mit Aufruf und return) zu Buche.
#112326
Lesenswert?

Anbei das Listing für den WINAVR.

Er erkennt, wenn nur ein Portpin gesetzt oder gelöscht werden soll und
nimmt dann SBI/CBI.


Der Keil vertraut darauf, daß man Pins, die man einzeln benutzen will
auch als einzelne Bits definiert.
Warscheinlich der CodeVision auch.



Peter
Angehängte Dateien:
#631992
Lesenswert?

>>1. Wie kann ich das Einlesen und Ausgeben realisieren?
Das Ausgeben habt Ihr hier super beschrieben, doch wie sieht es mit 
Einlesen aus?
Brauche ich für meinen ATTiny13 Project, der ja kein SPI kann (nur ISP 
über SPI seltsamerweise...steht auch im Datenblatt nix dazu...)

Ein Mega8 wird bei mir Soft- oder Hardware SPI benutzen (werde sehen, 
was besser ist), um dem Tiny13 Befehle zur Steuerung einer RGB-LED zu 
geben.
Der Tiny13 muss diese Befehle auslesen und interpretieren.

Danke in Voraus

Grüße, paul
Gast #2024746
Lesenswert?

Ist schon etwas älter aber hatte ähnliches problem und fand diese seite 
bei google.

meine lösung für CPHA=1 und CPOL=1 
(http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus)
1
void SOFT_SPI_init(void){
2
  // MOSI und CLK auf Ausgang setzen
3
  SOFT_SPI_MOSI_DDR |=(1<<SOFT_SPI_MOSI_BIT);
4
  SOFT_SPI_CLK_DDR  |=(1<<SOFT_SPI_CLK_BIT);
5

6
  // MOSI und CLK auf HIGH setzen
7
  SOFT_SPI_MOSI_PORT|=(1<<SOFT_SPI_MOSI_BIT);
8
  SOFT_SPI_CLK_PORT |=(1<<SOFT_SPI_CLK_BIT);
9

10
  // MISO auf Eingang setzen
11
  SOFT_SPI_MISO_DDR &=~(1<<SOFT_SPI_MISO_BIT);
12
}
13

14
unsigned char SOFT_SPI_WriteRead(unsigned char dataout)
15
{
16
  uint8_t datain=0;
17
  //das Byte wird Bitweise nacheinander Gesendet MSB zuerst
18
  for (uint8_t a=8; a>0; a--){                
19
      datain<<=1;                      //Schieben um das Richtige Bit zusetzen
20
      SOFT_SPI_CLK_PORT &=~(1<<SOFT_SPI_CLK_BIT);     // Clock auf LOW
21
                                
22
      if (dataout & 0x80){                //Ist Bit a in Byte gesetzt
23
        SOFT_SPI_MOSI_PORT |=(1<<SOFT_SPI_MOSI_BIT);   //Set Output High
24
      }
25
      else{
26
        SOFT_SPI_MOSI_PORT &=~(1<<SOFT_SPI_MOSI_BIT);   //Set Output Low
27
      }
28
      _delay_us(1);
29
      if (SOFT_SPI_MISO_PIN & (1<<SOFT_SPI_MISO_BIT))   //Lesen des Pegels 
30
        {
31
        datain |= 1;
32
        }
33

34
      _delay_us(1);
35
      SOFT_SPI_CLK_PORT |=(1<<SOFT_SPI_CLK_BIT);       // Clock auf High
36
      _delay_us(2);
37
      dataout<<=1;                     //Schiebe um nächstes Bit zusenden
38
    }
39

40
  return datain;
41
}

mit den Delay zeiten kann man noch etwas spielen.
#2247691
Lesenswert?

Hallo,

habe für einen ATTiny2313 auch eine Software SPI Lösung gesucht und hier 
gefunden. Danke vor allem an meinen Vorposter, der Code funktioniert 
eiwandfrei. Habe ihn etwas angepasst, da ich CPHA=1 und CPOL=1 nicht 
nutze.
Benötigte den Code für die Kommunikation mit einem SCA3000. Werde die 
Bibliothek(en) in einem neuen Thread posten.

Grüße
Göck

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren