Forum: Mikrocontroller und Digitale Elektronik Ein Zeichen von der UART lesen (ASM)


von Holger P. (Gast)


Lesenswert?

Hallo Forum User,
ich bekomme jedesmal ein Timeout. Muss ich den Fehler hier suchen? Oder 
müsste die Routine funktionieren? Mit dem Debugger sieht alles gut aus.
1
; ***********************************************************************
2
; * Liest ein Zeichen von der USART                                     *
3
; * Dummy1=FF Timeout. Dummy1=1 Zeichen empfangen                       *
4
; ***********************************************************************
5
Read_Char:
6
    ldi  Dummy1,0xFF
7
    ldi  Dummy2,0xFF ;  0x40=55µS = 1Bit bei 19200Baud
8
Read_Char_Wait:
9
    dec  Dummy2
10
    breq Read_Char_Ende 
11
    lds  Dummy3, UCSR0A 
12
    sbrs Dummy3, RXC0 
13
    rjmp Read_Char_Wait 
14
   ; Speichert das empfangene zeichen in EZeichen (r20) 
15
    lds  EZeichen, UDR0 
16
  ldi  Dummy1,0x01
17
Read_Char_Ende:
18
  ret

von Karl H. (kbuchegg)


Lesenswert?

Holger P. schrieb:
> Hallo Forum User,
> ich bekomme jedesmal ein Timeout.

Dein Timeout ist selbst bei 'nur' 1Mhz Taktfrequenz des µC verdammt 
kurz!

Timeouts bewegen sich normalerweise im knappen Sekundenbereich oder noch 
höher. Aber ein paar µs? So schnell kann doch keine Gegenstation auf ein 
empfangenes Byte reagieren und Antwort zurückschicken.

von Karl H. (kbuchegg)


Lesenswert?

Du solltest mal den Sinn eines Timeouts an dieser Stelle hinterfragen.
Ein Timeout setzt man ein, wenn man eine Anforderung an die Gegenstelle
sende und diese innerhalb eines angemessenen Zeitfensters antworten
muss.

In einer reinen Empfangsroutine macht ein Timeout nicht viel Sinn. Wenn
du in der Hauptschleife pollst, dann lautet die erste Fragestellung:

* ist ein Zeichen da
   -> wenn nein, dann beschäftige dich mit dem nächsten Teilproblem
   -> wenn ja, dann hole das Zeichen und bearbeite es

Aber in einer reinen Lesefunktion, die nur den Zweck hat, die UART zu
pollen ist ein Timeout vollkommen sinnfrei. Timeout macht nur Sinn, wenn
man auf Antwort wartet. Und dann muss die Zeit auch angemessen sein.

von Holger P. (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Holger P. schrieb:
>> Hallo Forum User,
>> ich bekomme jedesmal ein Timeout.
>
> Dein Timeout ist selbst bei 'nur' 1Mhz Taktfrequenz des µC verdammt
> kurz!
>
> Timeouts bewegen sich normalerweise im knappen Sekundenbereich oder noch
> höher. Aber ein paar µs? So schnell kann doch keine Gegenstation auf ein
> empfangenes Byte reagieren und Antwort zurückschicken.

Oh klar ich habe es ja selber geschrieben

0x40=55µS = 1Bit bei 19200Baud

Ich sollte schon mal 1Byte warten ;-)

Das mit dem Timout an dieser Stelle überdenke ich mir noch mal. Doch 
sollte das schon so sein, wenn ich dort hin springe mus sofort das 
zeichen kommen.

von Karl H. (kbuchegg)


Lesenswert?

Holger P. schrieb:

> Das mit dem Timout an dieser Stelle überdenke ich mir noch mal. Doch
> sollte das schon so sein, wenn ich dort hin springe mus sofort das
> zeichen kommen.

Wenn es schon da ist, dann kriegst du es auch sofort aus dem UDR 
Register.

Wwnn es noch nicht da ist - dann kannst du höchstens sagen: gut ich 
warte jetzt erst mal 0.5 Sekunden. Aber: dann sind wir wieder beim 
allseitsbeliebten Thema: Warumn ist aktives Warten in einem µC Programm 
Mist?

Und: definiere 'sofort'.
sofort geht nicht. Denn deine zuvor rausgegangene Anfrage an die 
Gegenstelle muss von der Gegenstelle erst mal
  komplett empfangen worden sein
  bearbeitet worden sein
  ausgewertet worden sein
  die entsprechende Antwort zusammengestellt worden sein
  die Antwort per USART auf den WEg gekommen sein
  bei dir eingetroffen sein.

Du erwartest, dass du beim Briefschach deinen Zug in ein Kuvert steckst, 
das in den Briefkasten wirfst und 2 Zehntelsekunden später soll die 
Antwort deines Gegners per Post auch schon da sein. Ansonsten schreist 
du Timeout.

Das ist nicht sinnvoll :-)

Wörter wie 'sofort', 'optimal', etc. haben in der Progammierung nichts 
verloren. Ein 'sofort' existiert schlicht und ergreifend nicht. Du 
kannst eine Grenze festlegen, bis zu der du bereit bist zu warten, mehr 
aber auch nicht. Das ist aber nicht sofort ... und ... diese Grenze darf 
nicht absurd niedrig sein. Du musst deiner Gegenstelle schon auch die 
Zeit einräumen, die sie im Worst Case braucht, um zu antworten. Und dann 
nimmt man diese Zeit zur Sicherheit noch mal 2 oder mal 3.

von Holger P. (Gast)


Lesenswert?

Ich klinken mich in einem Datenstrom ein. Ich fordere nich an sondern 
möchte was aufschnappen was gerade vorbei läuft. Und auch nur das, nicht 
ein Zeichen davor.

Wobei ich gerade gemerkt habe das er mir trotzdem die vorab empfangenen 
Zeichen nicht verwirft. :-(

von Udo S. (urschmitt)


Lesenswert?

Dann schreibe dir einen Ringpuffer in den die Zeichen eingelesen werden. 
Sobald ein Zeichen da ist sorgt die Interruptfunktion daß er im 
Ringpuffer landet.
In deinem Hauptprogramm kannst du jetzt auf den Ringpuffer pollen und 
wenn die Startbedingung da ist die Zeichen abholen sobald sie da sind. 
Damit hast du dann sogar Zugriff auf die Zeichen vorher, falls das 
notwendig ist.

Holger P. schrieb:
> Ich klinken mich in einem Datenstrom ein.

Und woher weisst du daß der Sendende nicht mal ne kurze Pause macht weil 
er gerade was anderes (Interrupt, bei PC andere Prozesse) zu tun hat?

von Karl H. (kbuchegg)


Lesenswert?

Holger P. schrieb:

Genau darauf will ich dich die ganze Zeit sensibilisieren.

> Ich klinken mich in einem Datenstrom ein. Ich fordere nich an sondern
> möchte was aufschnappen was gerade vorbei läuft.

Wozu dann ein Timeout?
Entweder ein Zeichen ist da, oder es ist kein Zeichen da.


Timeouts machen nur Sinn, wenn du auf ANTWORT WARTEST!

von Karl H. (kbuchegg)


Lesenswert?

Hier

    lds  Dummy3, UCSR0A
    xxxx Dummy3, RXC0


Ist RXC0 in UCSR0A nicht gesetzt, dann ist kein Zeichen da.
Raus aus der Routine und was anderes gemacht, bis man dann ein paar µs 
später wieder neu nachsieht, ob was da ist. Kein Mensch braucht da ein 
Timeout. Hier geht es nicht um die Frage "Ist zuviel Zeit vergangen". 
Hier geht es einfach nur um die ganz banale Fragestellung "Zeichen da 
oder Zeichen nicht da".


(Oder das ganze eben auf Interrupt Betrieb umstellen).

von Holger P. (Gast)


Lesenswert?

Nachdem ich ein Triggersignal bekommen habe muss das Zeichen sofort 
(<52µs) da sein, ansonsten muss ich reagieren. Ist das Zeichen da so 
muss ich es abspeichern.

Ich habe das nun so gemacht:
1
; ***********************************************************************
2
; * Liest ein Zeichen von der USART                                     *
3
; * Dummy1=FF Timeout. Dummy1=1 zeichen empfangen                       *
4
; ***********************************************************************
5
Read_Char:
6
    ldi  Dummy1,0xFF
7
    ldi  Dummy2,0x40 ; 40
8
    ldi  Dummy4,0x20 ; 10
9
Read_Char_Wait:
10
    dec  Dummy2
11
    breq Read_Char_Timeout
12
    lds  Dummy3, UCSR0A 
13
    sbrs Dummy3, RXC0 
14
    rjmp Read_Char_Wait 
15
   ; Speichert das empfangene zeichen in EZeichen (r20) 
16
    lds  EZeichen, UDR0 
17
    ldi  Dummy1,0x01
18
Read_Char_Ende:
19
  ret
20
Read_Char_Timeout:
21
    dec  Dummy4
22
    breq Read_Char_Ende 
23
    ldi  Dummy2,0x40
24
    rjmp Read_Char_Wait


Diese Routine wird hier aufgerufen.
1
Weiter_Zeichen_Lesen:   
2
   rcall   Read_Char
3
   dec     Dummy1
4
   breq    Zeichen_abspeichern
5
   rjmp    Fertig   
6
Zeichen_abspeichern:
7
; ***********************************************************************
8
; * Zeichen abspeichern                                                 *
9
; ***********************************************************************
10
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
11
    ldi   xh,high(RS232Buffer)          ;
12
    
13
    clr   Dummy2
14
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
15
16
    add   xl,Dummy1
17
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
18
    st    x,EZeichen
19
20
    inc   Dummy1                        ; Zeiger um eins weiterschieben
21
    cpi   Dummy1,21                     ; Auf Speichergrenze von 20 Byte testen 
22
    brne  SOK_1                         ; Noch keine 20 Byte gespeichert 
23
    ldi   Dummy1,0                      ; 20 Byte überschritten wieder bei 1 anfangen  
24
SOK_1:
25
    sts   RS232Zeiger,Dummy1
26
    rjmp  Weiter_Zeichen_Lesen

Und was soll ich sagen, es GEHT :-) Jouuuuuuuuu

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.