Forum: Mikrocontroller und Digitale Elektronik seriell out mit SPI am AT89s8252


von Stefan (Gast)


Lesenswert?

Guten abend zusammen,

ich verwende einen AT898252 Controller und will per SPI am
MOSI pin (P1.5) seriell daten ausgeben.
zu testzwecken soll fortlaufend 10101101 seriall ausgeben werden.
leider funktioniert das bei mir nicht
was mache ich falsch?
ist das unterprogramm senden richtig?


danke für eure hilfe
Stefan


hier mein assemblerprogramm:



$nomod51

#include <AT898252.H>



org 0000h

setb es ; für spi interrupt


;*****************************SPI am ATMEL
initialisieren**************************************
mov SPCR,#11001010b  ;Initialisierung des SPI Port zur seriellen
Übertragung







;**********************  Senden
******************************************
loop: mov a,#10101101b  ;diese 8 bit sollen fortlaufend an mosi
ausgegeben werden
       lcall senden
      lcall loop




;********************** Unterprogramm Senden
******************************************
senden:  mov   spdr,a      ;Akkuinhalt senden
warteS:   jnb   0x80 ,warteS
    clr   0x80        ;Sende-Flag löschen
    ret


;writing to the spi data register of the master cpu starts the spi
clock generator,
;and the data written shifts out of the mosi pin
;0x80= spi interrupt flag

;spdr=spi data register



end

von Ralf (Gast)


Lesenswert?

Hi,

1. Das ORG 0000h... du weisst schon, dass bei Verwendung des seriellen
Interrupts der Controller immer, wenn solch ein Interrupt auftritt, an
eine bestimmte Adresse springt, an der er die Interrupt-Routine
erwartet, oder? Das heisst, deine Software liegt höchstwahrscheinlich
genau an dieser Adresse (ich glaube der serielle IR liegt an 000Bh,
musst du nachschauen). Die erste Interrupt-Adresse (glaube Timer0)
liegt an 0003h. Das bedeutet, wenn du mit Interrupts arbeiten willst,
MUSS dein erster Befehl (0000h) ein JMP sein, der dafür sorgt, dass das
eigentliche Programm angesprungen wird.

2. SETB ES bringt dir gar nix, wenn du nicht auch das globale
Interrupt-Freigabe-Bit EA setzt. Falls du (wie ich vermute) das ganze
NICHT interruptgesteuert machen willst, sondern per Polling, kannst du
dir auch das SETB ES sparen.

3. Guckst du hier:
http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3419

Da ist ein PDF sowohl mit C- als auch mit Assembler-Beispielen.

Hoffe, ich konnte helfen.

Gruß Ralf

von Peter D. (peda)


Lesenswert?

;**********************  Senden
******************************************
loop: mov a,#10101101b  ;diese 8 bit sollen fortlaufend an mosi
ausgegeben werden
       lcall senden
      lcall loop



Rekursive Funktionen sind zwar nicht schön, aber erlaubt.
Bloß du must dann auch eine Abbruchbedingung definieren, sonst ist
irgendwann Dein SRAM dicht.


Peter

von Ralf (Gast)


Lesenswert?

Ich glaube, er ist noch am Üben, was µC und Assembler angeht. Die Sache
mit dem lcall loop würde ich definitiv als FEHLER einstufen (war mein
erster Fehler in der Lehre, als es an µC ging), das muss "jmp loop"
heissen, sonst zerbröselt es ihm den Stack (so wie ich es sehe, zwar
nicht in diesem Programm, aber wenn er sich erstmal dran gewöhnt hat,
Schleifen so aufzurufen, wirds kritisch).

Gruß Ralf

von Stefan (Gast)


Lesenswert?

Hallo,

erstmal vieln danbk für eure Hilfe,
Ralf hat Recht, ich fange erst mit Controller an.

Der Link auf die Atmelsite ist sehr interessant,
Würde das ganze jedoch gerne ohne Interrupts machen,
also per polling.

Weiß jemand wo ein Programm zu finden ist,
wo das ganze per polling funktioniert?

gruß
Stefan

von Ralf (Gast)


Lesenswert?

Hi Stefan,

Polling ist doch ganz einfach:

1. Interrupts deaktivieren, also ES = 0
2. Eine Polling-Routine könnte für den Empfang z.B. so aussehen:

send_SPI:jnb Interrupt-Flag,$
clr Interrupt-Flag
mov spi,a
ret

In Zeile 1 wird über das Interrupt-Flag abgefragt, ob das letzte Senden
abgeschlossen wurde. Das Interrupt-Flag wird auch gesetzt, wenn der
Interrupt selbst deaktiviert ist!
JNB bedeutet, springe, wenn ein Bit nicht gesetzt ist, an eine
bestimmte Stelle im Programm. Das $-Zeichen sagt dem Controller in
diesem Fall, dass er wieder zum JNB-Befehl springen soll (für diesen
Fall könntest du statt $ auch send_SPI eintragen).

In Zeile 2 wird das Interrupt-Flag wieder gelöscht, damit das nächste
Senden wieder in Angriff genommen werden (Der Controller setzt das
IR-Flag nachdem er das letzte Bit rausgehauen hat).

Zeile 3 und 4 brauch ich wohl nicht erklären, oder?

Freilich musst du darauf achten, dass du die SPI-Schnittstelle vor der
ersten Verwendung richtig initialisierst.

Falls noch Fragen offen sind, einfach weiterfragen ;-)

Gruß Ralf

von Stefan (Gast)


Lesenswert?

nabend zusammen,

versuche gerade das ganze mit data_polling zum laufen zu bringen.
anbei mein assemblerprogramm.
wenn ich das ganze im debugmodus laufen lasse, dann wird nie das spdr
datenregister beschrieben, obwohl das spif flag gesetzt wird.
was amche ich falsch?



$nomod51          ;vorgegebene Includedatei wird abgeschaltet

#include <AT898252.H>  ;Includedatei fuer ATMEL 89S8252 aktiviert sie
muss



transmit_completed BIT SPIF_  /* SPI Interrupt Flag 0x80 */
data_to_send DATA 10111101b



org 0000h


clr transmit_completed
clr WCOL_                                 /* SPI Write Collision Flag:
1=Collision 0x40  */
mov p1,00h
;*****************************SPI am ATMEL initialisieren******
mov SPCR,#01011011b  ;Initialisierung des SPI Port zur seriellen
Übertragung



loop: mov spdr,data_to_send
      jnb transmit_completed,$
      clr transmit_completed
      call loop

ret

end

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.