Forum: Mikrocontroller und Digitale Elektronik SPI per Software


von Ralf (Gast)


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

von Alex (Gast)


Lesenswert?

avrfreaks.net
--> Anmeldung erforderlich, aber viel Beispielsource zu verschiedenen
Themen
--> Englischkenntnisse erforderlich

Gruß, Alex

von Auf Merk Sam (Gast)


Lesenswert?

AT89C52 !

von Ralf (Gast)


Lesenswert?

Hallo,

hat noch niemand sowas gemacht?

Gruß Ralf

von Peter D. (peda)


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

von crazy horse (Gast)


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.

von Ralf (Gast)


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

von crazy horse (Gast)


Angehängte Dateien:

Lesenswert?

hier mal ein Beispiel für das SPI-Schreiben, die Grundroutine write_spi
und ein Funktion, die diese benutzt.

von Peter D. (peda)


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

von Ralf (Gast)


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

von crazy horse (Gast)


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.

von crazy horse (Gast)


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.

von Ralf (Gast)


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

von crazy horse (Gast)


Lesenswert?

Ach was :-)
Ja, war für nen AVR (2313) mit CodeVision.

von crazy horse (Gast)


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.

von Ralf (Gast)


Lesenswert?

Auch knuffig. Ich muss jetzt mal anfangen, die Sache real (sprich nicht
Simulator) auszutesten, und mal sehen was dabei rauskommt.
Hoffentlich tuts auch...

Gruß Ralf

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei mal der Code mit dem WINAVR (20 Byte) und mit dem Keil (17 Byte).


Der WINAVR gestattet leider keine Portpindefinitionen, daher die etwas
umständlichere Schreibweise mit Maskierung.
Ist aber alles nur ne Gewöhnungsfrage.


Peter

von crazy horse (Gast)


Lesenswert?

Kannst du mal das Listing anhängen?
Deine Lösung erzeugt bei mir das schlechteste Ergebnis (29 words, 439
Takte). Da besteht offensichtlich deutlicher Optimierungsbedarf am
Compiler.

von Peter D. (peda)


Angehängte Dateien:

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

von Paul K. (fluctuation)


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

von spi (Gast)


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.

von S. G. (goeck)


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

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.