Serielle Schnittstelle

Gast #3064839
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
Angehängte Dateien:
Gast #3064847
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.
Persönliche Seite #3064940
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.
Gast #3064974
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?
Persönliche Seite #3065238
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.
#3065259
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
#3065305
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.
#3065653
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
#3065805
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren