UART repeater

Gast #283906
Lesenswert?

Hallo Jörg,
diese Lösung habe ich auch schon angedacht, nur wenn ich einen ganzen
Datenstrom habe kann es dann nicht passieren das ich gesendete Zeichen
während meiner Prüfroutine verlieren kann?

Danke und Gruß Volker
Moderator Persönliche Seite #283907
Lesenswert?

Das hängt von deiner Prüfroutine ab.

Du willst uns aber auch nicht verraten, was du denn genau beim
Eintreffen deines Sonderzeichens vorhast, insofern ist dir
schwer wirklich zu raten.

Eine andere Variante wäre es, den Empfänger interrupten zu
lassen, in der ISR dann das empfangene Zeichen nur zu testen
und damit ein Flag zu setzen (volatile nicht vergessen!) und
sofort danach neu auszugeben.

Die main loop kann dann das Flag testen (und löschen) und
ihrererseits ihre langwierigen Operationen ausführen.
Gast #283908
Lesenswert?

ja, am Ende soll es möglich sein ein Gerät von einem PC aus über den
Repeater zu Programmiern. Um das Gerät reseten zu können muss ich
schauen wann das Programmieren beendet ist, dies erfolgt nach dem als
letztes eine Zeichenfolge z.B. 0000FFFF vom PC gesendet wurde. Das
ganze soll mit 9600 Baud funktionieren.

Habe das ganze mit Peter Fleury's uartlib mal probiert und bekomme
nach geraumer Zeit einen Buffer Overflow.
Das erklärre ich mir so, daß die Empfangsinterruptroutine ständig
beansprucht wird und somit kein senden mehr möglich ist.

Werde mich aber jetzt mal hinsetzen und mir das USART-Kapitel im Manual
genau anschauen.

Vielen Dank und Gruß Volker
Moderator Persönliche Seite #283909
Lesenswert?

Ich denke, dass der einfache Interrupt-Weg dafür
funktionieren sollte.
1
volatile uint8_t rx_char, updated;
2

3
SIGNAL(SIG_UART0_RECV)
4
{
5
  uint8_t c;
6

7
  c = UDR0;
8
  UDR1 = c;
9
  rx_char = c;
10
  updated = 1;
11
}
12

13
int
14
main(void)
15
{
16
  uint8_t state = 0, c;
17

18
  init_uarts();
19
  sei();
20

21
  for (;;) {
22
    if (updated) {
23
      updated = 0;
24
      c = rx_char;
25
      switch (state) {
26
        case 0:
27
  case 1:
28
    if (c == 0) state++;
29
    else state = 0;
30
    break;
31
  case 2:
32
  case 3:
33
    if (c == 255') state++;
34
    else state = 0;
35
    if (state == 4) {
36
      state = 0;
37
      pull_external_reset();
38
    }
39
      }
40
    }
41
  }
42

43
  return 0;
44
}

Die Interruptverarbeitung sollte bei einem kontinuierlichen Datenstrom
von 9600 Bd selbst bei 1 MHz Takt kein Thema sein.  Die Zeichen kommen
dann ca. alle 1 ms, d.h. zwischen den Zeichen verbleiben knapp 1000
Takte für die Verarbeitung.  Die ISR selbst braucht 28 Takte (wenn ich
mich nicht verzählt habe), also 28 µs.  Die main loop braucht so 20
... 30 Takte pro Umlauf (je nach Zustand).

Eigentlich könnte man am Ende auch noch ein sleep_mode() plus einen
NOP dransetzen, um die restlichen 950 µs lang Strom zu sparen.  Der
Zustand kann sich ja ohnehin erst ändern, nachdem es einen neuen
Rx-Interrupt gab.  Den NOP braucht man, weil der meiner Erinnerung
nach nach dem Aufwachen abgearbeitet wird, bevor die Rx-ISR
angesprungen wird, diese aber setzt ja erst das "updated"-Flag.
Ggf.
nach dem Aufwachen so lange Kreise laufen, bis "updated" erschienen
ist.
Gast #283911
Lesenswert?

>>Habe das ganze mit Peter Fleury's uartlib mal probiert und bekomme
>>nach geraumer Zeit einen Buffer Overflow.

Überlauf gibt es immer, sobald mehr Zeichen gesendet als empfangen
werden: bei gleicher Baudrate versteht sich.
Fügst Du vielleicht in Deinen Audgangsdatenstrom noch Zeichen ein ?
Dann gibt es nach 'geraumer Zeit' Probleme.
Oder werden eventuell LFs nach CR-LF expandiert ???
Moderator Persönliche Seite #283913
Lesenswert?

Ich würde den Koloss von Peter Fleury dafür nicht benutzen.

Du hast einen Empfänger mit 9600 Bd und einen Sender mit 9600 Bd.  Es
kann dir bei ordentlicher Programmgestaltung also gar nicht passieren,
dass der Empfänger überläuft.  Warum also ...zig Tests für Dinge, die
nicht auftreten können?  (Ich gehe mal davon aus, dass du nicht noch
flow control oder sowas brauchst.)

Guck dir doch mal mein Template an.  Du solltest doch wirklich
ausreichend Reserven haben, die von dir gewünschte Aktion innerhalb
der entsprechenden Zeit auszuführen.
Gast #283914
Lesenswert?

Hallo Jörg,
ja du hast recht ich werde mal eine einfachere Lössung anstreben als
die von Peter. Eigentlich sollte es ohne FIFO funktionieren es kann ja
eigentlich nichts dazwischen funken wenn der Controller nur diese
Aufgabe erledigen soll. Alle anderen Aufgaben werden während dieser
Aktion eh abgeschaltet.

Gruß Volker
Gast #283915
Lesenswert?

Hallo Jörg,
habe neue Erkenntnisse gesammelt. Der im Anhang verwendete Code
funktioniert wenn ich schneller sende als empfange wunderbar. Bei
gleicher Baudrate aber nicht. Werde dann woll doch nicht um einen
Zwischenspeicher herum kommen. Denke aber das dieser dann auch wieder
überläuft?

Gruß Volker
Angehängte Dateien:
Moderator Persönliche Seite #283916
Lesenswert?

> Der im Anhang verwendete Code funktioniert wenn ich schneller sende
> als empfange wunderbar. Bei gleicher Baudrate aber nicht.

Das wundert mich, sollte man analysieren.

Ich hätte mir zwar den Test auf UDRE geklemmt, aber das sollte sich
nicht fatal auswirken.  Bei gleicher Baudrate sollte der Sender ja
wohl wieder bereit sein, zumal er ein Byte puffern kann.
Gast #283917
Lesenswert?

Also wenn die Bytes wirklich Start an Stop kommen, dann muß der Quarz
geringfügig schneller sein, damit nicht langsamer gesendet als
empfangen wird.

Der erste Sender sollte daher ab und zu mal Pausen machen oder mit 2
Stopbits senden.


Peter
Gast #283919
Lesenswert?

Hallo Jungs,
geht jetzt alles wie gewollt lag aber nicht am Wiederholer sondern an
meiner Sendeeinheit. Nun habe ich das Teil zwischen 2 PC's gehängt und
es geht ab wie die Feuerwehr am Stück 100kbyte geschickt und keinen
Fehler. Na ja aber jetzt habe ich wenigsten gelernt wie mann einen FIFO
bastelt.
Danke an Alle und Gruß Volker

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