Forum: Mikrocontroller und Digitale Elektronik Daten über die serielle Schnittstelle schicken (AT89C51ID2)


von Ampfing (Gast)


Lesenswert?

Hallo zusammen,

der Titel sagt eigentlich schon ziemlich viel.
Ich habe einen AT89C51ID2 und möchte ihn von einem Rechner aus per 
serieller Schnittstelle ansteuern - und natürlich soll er auch was 
zurücksenden.
Den Receive des Controllers habe ich soweit verstanden (glaube ich). 
Aber wie sage ich dem Controller, dass er Daten schicken soll? Es gibt 
ja (laut Datenblatt) nur ein UART-Buffer-Register namens SBUF. Dann habe 
ich noch ein Bit, mit dem ich den Empfang aktivieren und deaktivieren 
kann.
Muss ich jetzt also, um Daten vom Controller zum PC zu übertragen, den 
Empfang deaktivieren, meinen Buffer mit dem zu schreibenden Wert füllen 
und dann auf den Transmit-Interrupt warten? Oder bin ich da total auf 
dem Holzweg?

Danke schonmal im voraus für Eure Antworten und viele Grüße

P.S.: Ach ja, Pegelwandlung usw. ist klar, da nehm ich nen ADM232AAN 
(hab ich Muster von bekommen und sollte funktionieren).

von Joe (Gast)


Lesenswert?

Also, mov a,sbuf ließt dein Zeichen, mov sbuf,a sendet es.

RI zeigt einen Receive an, TI einen Transmit.

So, was willst du machen ??

Beispiel: Daten senden:

send_byte:   jnb ti,send_byte
             mov sbuf,a
             clr ti

Nun sende was du willst, oder wie ist die Frage zu verstehen ?

von Ampfing (Gast)


Lesenswert?

Hallo Joe,

ja, hast die Frage schon richtig verstanden.
Auch wenn ich in C programmiere, so viel Assembler versteh ich sogar 
noch :-)
Das heißt also, ich muss REN nicht rücksetzen, oder? Was macht er denn, 
wenn er gleichzeitig Daten empfängt, während er sendet? Okay, sollte 
normalerweise (bei mir) nicht passieren, aber wenns doch so ist?

Viele Grüße und danke für die schnelle Antwort!

von Joe (Gast)


Lesenswert?

REN ist das Interrupt freigabe Flag für die UART.

In C gehts auch ... ;-))

void putchar_uart (char c)
{
  while (!TI);    // Transmitter busy ?
  TI = 0;         // TI Flag löschen
  SBUF = c;       // Ausgabe an UART
}

Im Interrupt Betrieb setzt du also REN + EA. Wenn dann ein Interrupt 
auftritt dann weißt du erstmal nicht war es RI oder TI. Also mußt du 
schon ein bischen mehr programmieren.

Ein ISR gleicher priorität kann sich nicht selbst unterbrechen, also im 
worst case verlierst du ein Zeichen. Derartige Fälle mußt du sowieso im 
Protokoll berücksichtigen. Eine genaue Aussage kann man aber erst machen 
wenn man alle Fakten kennt, beschreibe was du machen willst !!

von Ampfing (Gast)


Lesenswert?

Hallo Joe,

okay, hier etwas ausführlicher, was ich machen möchte:
Der PC schickt per serieller Schnittstelle verschiedene Telegramme raus. 
Diese unterscheiden sich in ihrer Länge.
Es gibt vier verschiedene Telegrammtypen, die durch zwei Bit im ersten 
Byte gekennzeichnet werden.
Wenn also der erste Receive-Interrupt kommt schaut der Controller nach, 
was für ein Telegrammtyp es ist, setzt eine Variable maxAnzahl auf die 
maximale Anzahl an Bytes des jeweiligen Telegrammtyps und speichert den 
Wert des 1. Bytes in einem Buffer.
Jetzt kommt das nächste Byte (also der nächste Interrupt), er speichert 
den Wert im Buffer und überprüft, ob die maximale Anzahl an Bytes für 
den entsprechenden Telegrammtyp schon erreicht ist.
Wenn ja schickt er eine Antwort an den Rechner. Wenn nicht gehts halt 
mit dem Empfang des nächsten Bytes weiter.

Zum Senden hatte ich mir überlegt, dass ich vier verschiedene Funktionen 
schreibe, die die jeweils gewünschte Antwort (hängt natürlich vom 
empfangenen Telegramm ab) an den Rechner schicken (auch diese 
unterscheiden sich in ihrer Länge).
Dafür hätte ich dann das ES-Bit rückgesetzt (das ist laut meinem 
Datenblatt das Interrupt-Enable bit für die UART) und ziemlich genau die 
Routine von dir übernommen.
Wenn der Transmit fertig ist wird der Interrupt wieder freigegeben, 
damit weitere Nachrichten vom PC empfangen werden können.

Dass der Prozessor während dem Senden nicht unterbrochen werden kann 
sollte eigentlich nicht weiter stören, da der PC, nachdem er ein 
Telegramm weggeschickt hat, sowieso auf eine Antwort warten muss.

Laut meinem Datenblatt ist das REN-Bit das "Reception Enable Bit" und 
dient dazu, den Empfang an- oder abzuschalten...

Hoffe mal, es ist einigermaßen klar, was ich machen möchte.?

Viele Grüße

von Joe (Gast)


Lesenswert?

Eigentlich hast du es schon, REN = Receiver ENable ...

Wo ist jetzt die Frage ??

von Ampfing (Gast)


Lesenswert?

Die Frage ist, ob ich REN während dem Senden rücksetzen muss, oder ob 
ich es auf 1 lassen kann.
Was würde denn passieren, wenn (was nicht passieren sollte, aber nehmen 
wir mal an es passiert doch) der Controller Daten empfängt, während er 
sendet und REN auf 1 wäre.
Dann würde er doch den Transmit-Buffer überschreiben (denn RI wird ja 
erst gesetzt, wenn er 9 Bits (1 Byte + Stopbit) empfangen hat), oder? Je 
nachdem ob ich gerade durch Zufall das letzte Byte sende kann ich dann 
also auf den Interrupt noch reagieren, oder das Zeichen ist verloren und 
ich laufe anschließend in den Wald, weil ich mein zuletzt geschriebenes 
Byte wieder einlese, was aber nicht einem gültigen Telegramm vom 
Computer entspricht, sehe ich das richtig?
In diesem Fall würde ich eben REN rücksetzen, dann kriege ich zwar nicht 
mit, dass der Rechner sendet, aber besser so als anschließend total in 
den Wald zu laufen!
Wollte damit nur sicher gehen, dass ich mir das richtig überlegt habe, 
da ich noch nicht besonders viel Erfahrung mit Mikrocontrollern habe.

Viele Grüße

von Joe (Gast)


Lesenswert?

In deinem Fall ist alles eine "bewußte" Aktion. Wenn ich ehrlich bin 
würde ich die UART im polling mode ganz ohne Interrupt betreiben. Den 
brauchst du eigentlich gar nicht.

Statt REN kannst du auch EA abschalten, wäre eine weitere Möglichkeit.

Wie dem auch sei, bei deiner Routine läuft alles nacheinander:

Erst Kommando.. Telegramm vom PC... Dann antwortet der Controller mit 
dem zurücksenden von Daten. Dann.... gehts weiter, warum also Interrupt 
?

von Ampfing (Gast)


Lesenswert?

Warum Interrupt?
Nun, dann kann ich zumindest auf den Receive warten ohne dass ich 
ständig das Request-Bit des Empfängers pollen muss.
Finds persönlich fast sympatischer, wenn in main irgendwo while(1); 
steht als die CPU ständig damit zu beschäftigen ein bestimmtes Bit zu 
pollen.
Aber das ist reine Geschmackssache :-)

Viele Grüße und danke für die Hilfe

von Joe (Gast)


Lesenswert?

Ja, einen Interrupt und ab diesem Zeitpunkt pollen, man muß es nur 
sinnvoll kombinieren.

Wie gesagt, ansonsten wäre dein Workflow ohne Interrupt abzubilden.

1.) ISR, MC wird empfangsbereit Interrupt
2.) Empfang der Kommandosequenzen non Interrupt
3.) Zurücksenden der MC Daten an den Host non Interrupt

Wählst du jetzt ein entsprechendes Protokoll (echo, handshake etc..) 
dann geht nichts mehr Verloren.

Ich habe in den seltensten Fällen 100% Kommunikation über ISR's 
realisiert da es überhaubt nicht notwendig ist, und glaub mir, ich habe 
schon einige geschrieben.

von Mühldorf (Gast)


Lesenswert?

Ampfing, wenn Du willst, können wir uns mal treffen. Melde Dich bitte 
nochmal hier.

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.