Forum: Mikrocontroller und Digitale Elektronik USART Ende der empfangenden Daten abfragen


von Mousse-T (Gast)


Lesenswert?

Hallo zusammen,

ich habe ein Ethernet - RS232 Gateway auf Basis von Ulrichs Webserver 
aufgebaut, mit ATMEGA 644. Ich habe jetzt nur noch ein Problem.

Ich möchte wenn keine Daten mehr an der RS232 für das Ethernet ankommen 
die Verbindung zum Netzwerk beenden. Dazu habe ich mir zwei 
Möglichkeiten überlegt.

1. ein Timer der nach einer Zeit abläuft, wenn keinen neuen zeichen an 
der RS232 angekommen sind

2. Das RXCn:USART Receive Complete Bit im UCSRnA auf Null prüfen

Welche ist die bessere Variante für mein Vorhaben oder gibt es andere 
Möglichkeiten?

Danke

Gruß Mousse-T

von STK500-Besitzer (Gast)


Lesenswert?

>1. ein Timer der nach einer Zeit abläuft, wenn keinen neuen zeichen an
>der RS232 angekommen sind

Besser...

>2. Das RXCn:USART Receive Complete Bit im UCSRnA auf Null prüfen

Das wird gesetzt, sobald ein Byte komplett empfangen wurde. Also auch, 
wenn danach noch mehr Daten kommen.

von Fred S. (Gast)


Lesenswert?

Hi,

das USART Receive Complete Flag zeigt Dir nur an, ob das aktuell 
empfangene Zeichen vollständig empfangen wurde. Wenn Du aber feststellen 
möchtest, ob keine weiteren Zeichen mehr kommen, bietet sich eher eine 
"Time Out"-Funktion an (Deine Lösung 1, eventuell mehrere Timer Zyklen 
nutzen; rücksetzen, falls doch wieder Zeichen eintreffen).

Gruß

Fred

von Mousse-T (Gast)


Lesenswert?

Danke für die Antworten. Dann werde ich mir das mit den Timern noch mal 
genauer anschauen, denn so aus dem Stand wüsste ich noch nicht wie ich 
das realisieren sollte.

Ich dachte an sowas: Der Timer wird aktiviert wenn eine verbindung 
aufgebaut wird. Er wird dann immer wieder zurückgesetzt wenn ein zeichen 
Empfangen wurde. Wenn kein zeichen mehr mehr kommt, läuft der Timer aus 
und löst ein Interrupt aus, mit dem ich dann die Verbindung beenden 
kann.

Kommt das in etwas so hin?

Gruß Mousse-T

von Fred S. (Gast)


Lesenswert?

Hi,
> Ich dachte an sowas: Der Timer wird aktiviert wenn eine verbindung
> aufgebaut wird. Er wird dann immer wieder zurückgesetzt wenn ein zeichen
> Empfangen wurde. Wenn kein zeichen mehr mehr kommt, läuft der Timer aus
> und löst ein Interrupt aus, mit dem ich dann die Verbindung beenden
> kann.
Ja, sollte so klappen!

Gruß

Fred

von Mousse-T (Gast)


Lesenswert?

Danke noch mal.

Dann werde ich das mal so ausprobieren.

Gruß Mousse-T

von Mousse-T (Gast)


Lesenswert?

Ich habe mich jetzt etwas eingelesen und rausgefunden, dass man das über 
das Overflow oder Compare Match Interuppt machen kann.

Was wäre denn im meinem fall besser? Nochmal dazu. Der Timer soll 
gestartet(initialisiert) werden wenn eine Verbindung aufegaubt wird und 
soll dann ca. 500ms laufen bis der Interupt auslöst.
Damit der Interuppt nicht auslöst wenn ein zeichen an der RS232 kommt, 
soll dann dort der Timer wieder zurückgesetzt werden. Auf 0?

Gruß Mousse-T

von Fred S. (Gast)


Lesenswert?

Hi,
> ...., dass man das über
> das Overflow oder Compare Match Interuppt machen kann.
> Was wäre denn im meinem fall besser? ...
Vermutlich wirst Du Deine 500 ms mit einem CompareMatch Interrupt 
einfacher realisieren können als mit einem OVF-Interrupt. Falls Du mit 
dem OVF-Int (und den entsprechenden Vorteilern) auch auf die gewünschte 
Zeit kommt, spielt es keine Rolle, welchen Interrupt Du nimmst.
> soll dann dort der Timer wieder zurückgesetzt werden. Auf 0?
Ja, denn Du willst doch wieder einen 500ms Zyklus starten. Lies Dir aber 
genau durch, was beim Schreiben des TCNT Registers zu beachten ist 
(evtl. Vorteiler vorher auf 0).

Gruß

Fred

von Mousse-T (Gast)


Lesenswert?

So, ich habe mir das mal im Datenblatt angeschaut und hoffe das es so 
richtig ist.

16000000 MHZ/1024 = 15625                   // Prescaler auf 1024
15625 / 256 = 61,035                        // Bei diesem Wert gibts ein 
überlauf 1ms???
61,035 * 500 = 30517,578                    // Für das 
Vergleichsregister bei 500ms


INIT
1
void timer0_init(void)
2
{
3
   TCCR0A |= (1<<WGM01);                    // CTC Mode
4
   TCCR0B |= (1<<CS00 | 0<<CS01 | 1<<CS02); //Prescaler 1024
5
   TCNT0 = 0;                               // Vorbelegung mit 0
6
   0CR0A = 30518;                           // Vergleichsregister belegen
7
8
   TIMSK |=(1<<OCIE0A);                     // Compare Match Interuppt
9
}

ISR
1
ISR (TIMER0_COMP_vect)
2
{
3
   // Keine Daten von der Seriellen erhalten. Verbindung beenden
4
}

Ich würde dann TCNT0 = 0; jedes mal setzen, wenn ein zeichen empfangen 
wurde.

So ich hoffe das es stimmt, wenn nicht, dann sollte es wenigstens ein 
guter Ansatz sein ;-)

Gruß Mousse-T

von Mousse-T (Gast)


Lesenswert?

Fehler:Das OCR0A kann natürlich nur Werte <256 haben. ICh muss dann in 
der ISR bis 500 incrementieren und dann die verbidung beenden...

von Fred S. (Gast)


Lesenswert?

Hi,

> Fehler:Das OCR0A kann natürlich nur Werte <256 haben. ICh muss dann in
> der ISR bis 500 incrementieren und dann die verbidung beenden...
Du verwendest doch einen ATmega644 - oder? Dann nimm einfach den 
Timer/Counter 1; das ist ein 16 Bit Timer mit 16 Bit Output Compare 
Registern.

Gruß

Fred

von Fred S. (Gast)


Lesenswert?

Hallo,
> 16000000 MHZ/1024 = 15625                   // Prescaler auf 1024
> 15625 / 256 = 61,035                        // Bei diesem Wert gibts ein

Diese Rechnung stimmt nicht, oder ich weiß nicht, was Du rechnest.

Die Timer-Einheit (timer tick) bei 16 MHz F_CPU und Vorteiler=1024 ist 
1024/16000kHz=64us. Zeit bis zum 8-Bit OVF also 256*64us=16,384ms.

Gruß

Fred

von Karl H. (kbuchegg)


Lesenswert?

Mousse-T wrote:
> So, ich habe mir das mal im Datenblatt angeschaut und hoffe das es so
> richtig ist.
>
> 16000000 MHZ/1024 = 15625                   // Prescaler auf 1024

OK. Dein Timer kann also in 1 Sekunde 'theoretisch' bis 15625
zählen.

Da er aber ein 8 Bit Timer ist, ...
> 15625 / 256 = 61,035                        // Bei diesem Wert gibts ein
> überlauf 1ms???
... bedeutet dass, das er nicht bis 15625 zählen kann, sondern immer
nur bis 255. Das allerdings 61.035 mal in der Sekunde.

> 61,035 * 500 = 30517,578                    // Für das
> Vergleichsregister bei 500ms

Und wie bitte schön stellst du dir vor, dass ein 8 Bit Register
bis 30517 zählen soll? Das kommt maximal bis 255. Dann beginnt
es wieder bei 0.

WEnn du bei Overflows bleiben willst dann reicht es daher
aus, wenn in deiner Overflow ISR eine zusätzliche 8-Bit
Variable bis 30 hochgezählt wird (du erinnerst dich? Der
Timer produziert knapp 61 Overflows in der Sekunde).
Das sind dann ungefähr 500ms. Auf ein paar zerquetschte mehr
oder weniger kommt es bei einem Timeout ja nicht an.

von Mousse-T (Gast)


Lesenswert?

Danke für die Antworten. Werde es mal am Montag ausprobieren.

Timer1 kann ich nicht nehmen, der wird schon für was anderes verwendet.

@Karl Heinz
Ja den fehler habe ich dann auch bemerkt. Siehe Post unter der Rechnung 
;-)

Gruß Mousse-T

von 3354 (Gast)


Lesenswert?

Timeout auf die Zeichenfolge ? Windows kann egal be welcher Baudrate 
auch schon mal 100ms oder so aussetzen. Das kann dann noch vom Treiber 
abhaengen.

von Mousse-T (Gast)


Lesenswert?

Deswegen wollte ich auch ca. 500ms warten. BIn mal gespannt obs dann 
funktioniert ;-)

von Mousse-T (Gast)


Lesenswert?

So jetzt fasse ich noch mal alles zusammen und hoffe, dass ich alles 
richtig verstanden habe.

16000000 MHZ/1024 = 15625                   // Prescaler auf 1024
Der Timer kann also in 1 Sekunde 'theoretisch' bis 15625 zählen.

15625 / 256 = 61,035                        // Bei diesem Wert ist 1ms 
vorbei
bedeutet dass, das er nicht bis 15625 zählen kann, sondern immer
nur bis 255. Das allerdings 61.035 mal in der Sekunde.

Also brauche ich eine Variable in der ISR die bis 30 hochgezählt wird, 
damit ich auf 500ms komme.

So jetzt noch mal der Code:

INIT:
1
void timer0_init(void)
2
{
3
   TCCR0A |= (1<<WGM01);                    // CTC Mode
4
   TCCR0B |= (1<<CS00 | 0<<CS01 | 1<<CS02); // Prescaler 1024
5
   TCNT0 = 0;                               // Vorbelegung mit 0
6
   0CR0A = 255;                             // Vergleichsregister belegen
7
8
   TIMSK |=(1<<OCIE0A);                     // Compare Match Interuppt
9
}

ISR
1
ISR (TIMER0_COMP_vect)
2
{
3
   variable++;
4
   
5
   if(variable == 30)
6
   {
7
      // 500ms abgelaufen, Verbindung beenden
8
   }
9
   // Keine Daten von der Seriellen erhalten. Verbindung beenden
10
}


In meiner ISR_USART würde ich dann bei jedem Empfangene zeichen die 
variable auf 0 setzten, richtig?
1
ISR (USART)
2
{
3
   ....
4
   // Zeichen empfangen
5
   variable = 0;
6
}


Also wenn ich jetzt alles richtig verstanden habe, sollte es so 
funktionieren, wenn nicht, dann bitte korigieren.

Einfacher wäre es wohl mit einer 16 Bit Timer, weil da sie ISR nur 1 mal 
aufgerufen wird, aber der wird schon wo anderes verwendent.

Danke schon mal

Gruß Mousse-T

von Mousse-T (Gast)


Lesenswert?

Hallo zusammen.

Der Timer Funktioniert jetzt zum Teil. Initialisiert und gestartet wird 
der Timer beim Verbindungsaufbau.

Ich habe in die ISR(TIMER0_COMPA_vect) eine Usart ausgabe eingebaut die 
was ausgibt wenn die variable = 60 ist. Damit hatte ich jede Sekunde 
eine Ausgabe am Usart. Somit funktioniert der Timer schon mal.

Aber sobald ich Daten sende, kommt auf der Serielen keine Ausgabe mehr 
von der ISR. Der Timer müsste doch trotzdem weiter laufen, oder verstehe 
ich mal wieder was falsch???

Gruß Mousse-T

von Stefan E. (sternst)


Lesenswert?

Mousse-T wrote:

> Ich habe in die ISR(TIMER0_COMPA_vect) eine Usart ausgabe eingebaut die
> was ausgibt wenn die variable = 60 ist. Damit hatte ich jede Sekunde
> eine Ausgabe am Usart. Somit funktioniert der Timer schon mal.
>
> Aber sobald ich Daten sende, kommt auf der Serielen keine Ausgabe mehr
> von der ISR. Der Timer müsste doch trotzdem weiter laufen, oder verstehe
> ich mal wieder was falsch???

Von wo nach wo "Daten sende"? Zum µC? Ist doch klar, du setzt doch deine 
Timeout-Variable beim Empfang von Zeichen wieder zurück auf Null.

von Mousse-T (Gast)


Lesenswert?

Das habe ich zu dem Zeitpunkt noch nicht gemacht, weil ich erst mal 
wissen wollte ob der Timer überhaupt Funktioniert.

Daten senden heisst vom PC über Netzwerk an den AVR. Wenn ich das mache 
kommt der AVR nicht mehr in die ISR vom Timer. Das sollte er doch oder?

Gruß

von Stefan E. (sternst)


Lesenswert?

Mousse-T wrote:

> Daten senden heisst vom PC über Netzwerk an den AVR. Wenn ich das mache
> kommt der AVR nicht mehr in die ISR vom Timer. Das sollte er doch oder?

Dann musst du mal einen Blick in den Netzwerk-Code werfen. Wird dort der 
Timer vielleicht auch verwendet? Oder werden dort womöglich die 
Interrupts global für längere Zeit abgeschaltet (kann ich mir aber eher 
nicht vorstellen)?

von Mousse-T (Gast)


Lesenswert?

Den Timer0 habe ich ausschliesslich für diesen Zweck verwendet.

Liege ich aber in der Annahme richtig, dass der Timer weiterlaufen 
müsste solange er nicht gestoppt wird oder die Interuppts abgeschaltet 
werden?

von Stefan E. (sternst)


Lesenswert?

Mousse-T wrote:

> Den Timer0 habe ich ausschliesslich für diesen Zweck verwendet.

Ich dachte, du benutzt für das Netzwerk Fremdcode? Da musst du mal 
reinschauen.

> Liege ich aber in der Annahme richtig, dass der Timer weiterlaufen
> müsste solange er nicht gestoppt wird oder die Interuppts abgeschaltet
> werden?

Ja.

von Mousse-T (Gast)


Lesenswert?

Ja für das netzwerk benutze ich Fremdcode. Aber das ist nur der 16 Bit 
Timer im Einsatz und die Interrupts werden nicht abgeschaltet.

Aber anscheinend wird was anderes gemacht, wenn der Timer aufhört zu 
arbeiten... Muss ich dann noch mal genauer anschauen...

von Matthias (Gast)


Lesenswert?

Wenn das Ganze im Sekundentakt laufen soll, kannste auch einen 
Uhrenquarz 32,768 kHz an den asynchronen Timer hängen. Bei einem 
Teilerfaktor von 128
zählt der dann im Sekundentakt. Mehr als 255 Sekunden willst Du ja nicht 
warten, oder?

Damit ersparst Du dir ein ewiges CMP-Match / Overflow gebastel, wenn 
intern noch andere Zeitbasen benutzt werden sollen.

Nur so als kleiner Hinweis ;-)

von Mousse-T (Gast)


Lesenswert?

Ja das könnte ich auch machen, nur wollte ich eigentlich damit auskommen 
was da ist ;-).

Ich wünschte mir nur noch einen 16Bit Timer. Da würde die ISR nur einmal 
aufgerufen werden bei 500ms Timeout und nicht 30 mal wie beim 8Bit.

Auf jeden fall muss ich mal schauen, warum der Timer nicht 
weiterläuft...

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.