Forum: Mikrocontroller und Digitale Elektronik Serielle Schnittstelle


von Lens (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

Habe ein Infineon-C515c. Kann mir einer sagen:
1. Wieso nach der Konfiguration der seriellen Schnittstelle, TI=1 
gesetzt werden muss? TI wird doch automatisch gesetzt durch die CPU?
2. Wenn ich TI=1 setze, ist doch ein "serial Interrupt" ausgelöst. Wieso 
wird dann nicht zur "Interrupt Service Routine" gesprungen?

Den Code habe ich angehangen. Hoffe auf Hilfe

von STK500-Besitzer (Gast)


Lesenswert?

Lens schrieb:
> 1. Wieso nach der Konfiguration der seriellen Schnittstelle, TI=1
> gesetzt werden muss? TI wird doch automatisch gesetzt durch die CPU?
> 2. Wenn ich TI=1 setze, ist doch ein "serial Interrupt" ausgelöst. Wieso
> wird dann nicht zur "Interrupt Service Routine" gesprungen?

Hast du mal ins Datenblatt zu dem Thema geguckt?
Ich bin mit dem 515C nicht mehr ganz so vertraut, aber manche andere 
Controller (AVR) setzen gewisse Flags zurück, wenn man sie mit einer 1 
beschreibt. Das wäre in diesem Zusammenhang meine Vermutung.

von Lens (Gast)


Lesenswert?

Mir ist klar, dass ich noch den "serial interrupt" im "IEN0"-Register 
aktivieren muss, doch ich versteh trotzdem nicht, wieso das "TI"-Flag am 
Anfang gesetzt werden muss.

von Lens (Gast)


Angehängte Dateien:

Lesenswert?

Jetzt könnt ihr mir vielleicht helfen. Im Bild steht "TI" direkt neben 
"/SEND". Doch es steht nirgends explizit, dass TI dem "/SEND"-Pin 
entspricht. Was meint ihr?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Lens schrieb:
> Doch es steht nirgends explizit, dass TI dem "/SEND"-Pin
> entspricht.

Tut es auch nicht; ebensowenig wie "Data" dem "Shift" entspricht.

von Lens (Gast)


Lesenswert?

Es heißt außerdem "TI = 1; /* TI: set TI to send first char of UART */
Was soll das denn heißen? Wie kann ich denn das erste Zeichen senden, 
obwohl ich noch garkeinen Sendebefehl abgesetzt hab?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es geht wohl um interruptgesteuertes Senden.

Die Interruptroutine, die aufgerufen wird, wenn die UART mit dem Senden 
des vorhergehenden Zeichens fertig ist, holt sich ein Zeichen aus dem 
(Software-)Sendepuffer und übergibt das der UART-Hardware. Die sendet 
das Zeichen, und löst wiederum einen Interrupt für das nächste Zeichen 
aus.

Ist der Sendepuffer leer, wird kein weiteres Zeichen gesendet und also 
kein weiterer Interrupt ausgelöst.

Um den ganzen Kram zu starten, genügt es nicht, Daten in den 
Softwaresendepuffer zu schreiben, sondern es muss die 
Sendeinterruptroutine gewissermaßen einmal angestupst werden -- und das 
geschieht durch manuelles Setzen des TI-Bits.

von Lens (Gast)


Lesenswert?

Das war mir schon klar :). Nur wie du in meinem Code vielleicht siehst, 
ist nirgendwo was von seriellem Interrupt, geschweigedenn von Interrupt 
Service Routinen was zu sehen. Das ganze basiert auf "polling", da ja 
printf() als "polling" programmiert ist. printf() überprüft ob TI=1 ist, 
wenn ja, dann schreibt es das Zeichen in "SBUF". Das versteh ich ehrlich 
gesagt nicht. Wieso muss es abprüfen, ob TI=1 ist? Ich mein wenn er 
"TI=0" abprüfen würde, dann fände ich das logischer?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Lens schrieb:
> printf() überprüft ob TI=1 ist,
> wenn ja, dann schreibt es das Zeichen in "SBUF". Das versteh ich ehrlich
> gesagt nicht. Wieso muss es abprüfen, ob TI=1 ist? Ich mein wenn er
> "TI=0" abprüfen würde, dann fände ich das logischer?

Wie ist denn das Bit im Datenblatt beschrieben? Ich nutze den von Dir 
verwendeten µC nicht, deswegen kenne ich natürlich seine UART auch 
nicht.

von Dietrich L. (dietrichl)


Lesenswert?

Lens schrieb:
> Das versteh ich ehrlich
> gesagt nicht. Wieso muss es abprüfen, ob TI=1 ist? Ich mein wenn er
> "TI=0" abprüfen würde, dann fände ich das logischer?

TI=1 sagt doch, dass das Senderegister leer ist und ein neues Zeichen 
geschrieben werden darf. Wenn es =0 ist, wird noch gesendet und man darf 
nicht schreiben.
TI könnte einen Interrupt auslösen, wenn das Bit "ES" im Register 
"IEN0" gesetzt ist. Aber man kann TI auch pollen.

(Hinweis: Ich habe das jetzt mal schnell im Datenblatt nachgeschaut, es 
ist also nur meine Theorie ohne praktische Erfahrung und Garantie!)

Gruß Dietrich

von Georg G. (df2au)


Lesenswert?

Dietrich L. schrieb:
> TI=1 sagt doch, dass das Senderegister leer ist und ein neues Zeichen
> geschrieben werden darf. Wenn es =0 ist, wird noch gesendet und man darf
> nicht schreiben.
> TI könnte einen Interrupt auslösen, wenn das Bit "ES" im Register
> "IEN0" gesetzt ist. Aber man kann TI auch pollen.

Genau so ist es. Auch bei polled-Betrieb, muss am Anfang explizit das 
Senderegister als "leer" deklariert werden.

Senderoutine (polling):
1.) warte, bis das Senderegister leer ist
2.) lege das nächste Zeichen in das Senderegister
3.) fertig.

Bei Interrupt Betrieb wird es etwas komplexer. Hier wird das neue 
Zeichen in den Sende-Ringbuffer gelegt - sofern gerade eine Übertragung 
läuft. Ansonsten wird es direkt in das Senderegister gepackt. Der 
Interrupt prüft dann, ob weitere Zeichen im Ringbuffer sind und lädt 
ggfs das nächste Zeichen in das Senderegister. Ist nichts mehr zu 
senden, wird "fertig" markiert, damit der nicht-Interrupt-Teil weiß, 
dass er die Übertragung neu anwerfen muss.

von Dietrich L. (dietrichl)


Lesenswert?

Georg G. schrieb:
> 1.) warte, bis das Senderegister leer ist
> 2.) lege das nächste Zeichen in das Senderegister
> 3.) fertig.

So wie ich das bei der Beschreibung von TI gelesen hab, muss TI noch 
gelöscht werden: TI=1 löst Interrupt aus, die ISR löscht TI wieder. Auch 
wenn das nur im Zusammenhang mit Interrupt genannt wurde, vermute ich 
doch, dass das auch ohne ISR gilt.

Gruß Dietrich

von Georg G. (df2au)


Lesenswert?

Dann noch mal ganz ausführlich die nicht-Interrupt Variante:
1
/*----------------------------------------------------------------------*/
2
char get_key(void) {
3
/*                                                                      */
4
/* Zeichen von der seriellen Schnittstelle holen, ggfs warten           */
5
/*                                                                      */
6
/*----------------------------------------------------------------------*/
7
  while (!RI);
8
  RI = 0;
9
  return(SBUF);
10
  }
11
12
13
/*----------------------------------------------------------------------*/
14
void put_char(char c) {
15
/*                                                                      */
16
/* Zeichen über die serielle Schnittstelle ausgeben                     */
17
/*                                                                      */
18
/*----------------------------------------------------------------------*/
19
  while (!TI);
20
  TI = 0;
21
  SBUF = c;
22
  }

Mein Datenblatt (Siemens, uralt) ist eigentlich recht eindeutig. 
Allerdings muss man wirklich jeden Satz lesen und ernst nehmen.

von Lens (Gast)


Lesenswert?

Danke an alle!

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.