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
avrfreaks.net --> Anmeldung erforderlich, aber viel Beispielsource zu verschiedenen Themen --> Englischkenntnisse erforderlich Gruß, Alex
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
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.
@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
hier mal ein Beispiel für das SPI-Schreiben, die Grundroutine write_spi und ein Funktion, die diese benutzt.
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
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
"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.
@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.
@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
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.
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
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
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.
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
>>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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.