Forum: Compiler & IDEs UART repeater


von Volker (Gast)


Lesenswert?

Hallo Forum,
benötige eine Möglichkeit die daten die über Uart0 empfängt auf ein
Steuerzeichen prüft und gleich wieder auf Uart1 weiter sendet.

Hat jemand sich mit einer solchen Aufgabe schonmal auseinander
gesetzt?
Habe irgendwie keine so richtige Idee!

Gruß Volker

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

1
int
2
main(void)
3
{
4
  uint8_t c;
5
6
  init_uarts();
7
  for (;;) {
8
    c = UDR0;
9
    if (c == ein_Steuerzeichen) {
10
      /* do whatever you need */
11
    }
12
    UDR1 = c;
13
  }
14
  return 0;
15
}

Oder an was dachtest du?

(Obiges setzt natürlich voraus, dass die Baudraten auf beiden Seiten
gleich sind.)

von Volker (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Volker (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die Einrückungen des C-Beautifiers hier sind nicht gerade
sehr konsistent...

von Michael (Gast)


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 ???

von Volker (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal der erste Ansatz von mir!

@Jörg: Vielen vielen Danke, möchte dich aber nicht von deiner Arbeit
abhalten.

Gruß Volker

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Volker (Gast)


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

von volker (Gast)


Angehängte Dateien:

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Peter Dannegger (Gast)


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

von Volker (Gast)


Lesenswert?

Hallo Peter,
danke für deine Antwort,das mit 2 Stopbits werde ich auch mal
ausprobieren.

Gruß Volker

von Volker (Gast)


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

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.