Forum: Compiler & IDEs Fehler beim Lesen von RS232


von Günther S. (guenther)


Lesenswert?

Hallo Leute,

ich habe hier ein eigenartiges Problem. Also ich habe ein Gerät, was mit 
mir per RS232 kommuniziert. Das Betriebssystem des Hosts ist Linux, die 
Gegenseite ist ein Mikrocontroller. Das funktioniert auch alles soweit. 
Aber ich habe folgendes Problem.

Ich sende ein 0xA8 und müsste ein Echo empfangen. Ich empfange aber nur 
0x28. Mit anderen Worten: Es fehlt das erste Bit.

Folgender Code ist verantwortlich:
1
int devicehandle;       // Hiermit wird später auf das geöffnete Device zugegriffen
2
  struct termios options;   // hält die Kommunikations-Konfig-Daten
3
4
unsigned char buffer[1];
5
6
//RS232-Kanal öffnen (lesen und Schreiben erlaubt)
7
  devicehandle=open(device, O_RDWR | O_NOCTTY | O_NDELAY);
8
  
9
  fcntl(devicehandle, F_SETFL, 0);
10
  
11
  //RS232 konfigurieren
12
  tcgetattr(devicehandle, &options);
13
  
14
  //setzte baudrate
15
16
  cfsetispeed(&options, B38400);
17
  cfsetospeed(&options, B38400);
18
  
19
  //Read und Local setzen
20
  options.c_cflag |= (CLOCAL | CREAD);
21
22
  //gerade Parität, 1 Start&Stopbit, 8 Datenbits
23
  options.c_cflag |= PARENB;   /* Enable parity */
24
  options.c_cflag &= ~PARODD; /* Turn odd off => even */
25
  options.c_cflag &= ~CSTOPB;  /* Set 1 Stopbit */
26
  options.c_cflag &= ~CSIZE; /* Mask the character size bits */
27
  options.c_cflag |= CS8;    /* Select 8 data bits */
28
 
29
  //Disable hardware flowcontrol
30
  options.c_cflag &= ~CRTSCTS;
31
  
32
  //Raw Data Ausgabe
33
  options.c_oflag &= ~OPOST;
34
  options.c_oflag |= ONLCR;
35
  
36
  //Raw data Einlesen mit Parity-check
37
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
38
  options.c_iflag |= (INPCK | ISTRIP);
39
  
40
  //Set timeout to 1s
41
  options.c_cc[VMIN]  = 0;
42
  options.c_cc[VTIME] = 10;
43
  
44
  //Software flowcontrol ausschalten
45
  options.c_iflag &= ~(IXON | IXOFF | IXANY);
46
47
  //Neue Einstellungen sofort auf Port übertagen
48
  tcsetattr(devicehandle, TCSAFLUSH, &options);
49
50
  //Puffer leeren
51
  tcflush(devicehandle, TCIFLUSH);
52
53
//Hier geht das senden und empfangen los.
54
55
buffer[0]=0xA8;
56
57
printf("Sende %02X\n", buffer[0]); //reelle Ausgabe ist hier: A8
58
59
write(devicehandle, buffer, 1);
60
61
tcdrain(devicehandle); //warten, bis alles gesendet.
62
63
read(devicehandle, buffer, 1);
64
65
printf("Empfange %02X\n", buffer[0]); //Ausgabe sollte sein A8, ist aber 28
66
67
close(devicehandle);

Sieht für mich irgendwie normal aus. Das Oszi-Bild ist auf Sende- und 
Empfangsseite identisch. Ich gehe also davon aus, dass er tatsächlich 
ein richtiges Echo schickt.

Ich versteh die Welt nicht mehr.

Günther

von Stefan (Gast)


Lesenswert?

Steck vielleicht mal einen Loopback-Stecker (Selbstbau ist nicht schwer) 
an die serielle Schnittstelle vom Linux-Rechner. Dann siehst du, ob es 
am µC liegt oder am Linux.

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


Lesenswert?

> Ich sende ein 0xA8 und müsste ein Echo empfangen. Ich empfange aber nur
> 0x28. Mit anderen Worten: Es fehlt das erste Bit.

Nein, es fehlt das letzte Bit.  Das niederwertigste Bit wird zuerst
übertragen.

Könnte ein Problem mit zu großen Baudratenabweichungen sein: die ersten
Bits werden noch richtig übertragen, aber beim letzten Bit sind beide
Seiten zu weit auseinandergelaufen.

von Werner B. (Gast)


Lesenswert?

So auf den ersten Blick arbeitest du im AVR mit Parity. Parity verwendet 
aber das MSB, da dieses Konzept aus dem 7-Bit ASCII Code stammt bei dem 
eben jenes Bit unbenutzt ist. Wenn es der USART richtig macht muss er 
das höchstwertige Bit mit dem Paritywert überschreiben und der Empfänger 
"sollte" es filtern. Für binäre Übertragungen eignet sich nur No-Parity. 
(idR. 8N1)

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


Lesenswert?

Naja, der Host arbeitet mit Parity, aber auch mit CS8.  Das ist ein
9-Bit-Frame-Format, bei dem das Partitätsbit zusätzlich zu den
8 Datenbits untergebracht werden kann.

Den zugehörigen AVR-Code hat er ja nicht gepostet.  Prinzipiell
können die USARTs der neueren AVRs auch das 9-bit-Format, aber das
9. Bit ist ein wenig umständlich zu be-/verarbeiten.

von Werner B. (Gast)


Lesenswert?

Das hüpfende Komma ist das "kann". Das muss man aber warscheinlich 
"manuell" das Bit7 ins das Bit8 bringen und der Empfänger wieder zurück. 
Zumindest ich,  falls ich  Chipdesigner wäre, käme nie auf die Idee 
jemand würde so etwas versuchen. Kein Standard = Kann gehen oder nicht. 
Hier gehts offensichtlich nicht :-/

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


Lesenswert?

9-bit RS-232 ist ein Standard, auch wenn in der PeeCee-Welt eher
unbekannt.  Von 5-bit (klassischer Fernschreiber) über 7, 8 und 9
bit ist da alles machbar und irgendwo benutzt worden.

von Günther S. (guenther)


Lesenswert?

Guten Morgen und Danke für eure Hilfe,


@Stefan: Du meinst, einfach RxD mit TxD verbinden? Das ist ne Idee.

@Jörg: Baudratenabweichung klingt übel. Also beide Geräte verwenden die 
gleiche Baudrate und in Hinrichtung funktioniert das ja auch. Das Echo 
wird nur gesendet, wenn 0xA8 wirklich ankommt. Hab schon probehalber 
0x28 gesendet, da bleibt er stille.

@Werner: Eigentlich ist die Gegenstelle kein AVR, sondern ein 
RFID-Reader von Feig. Ich werde aber trotzdem mal versuchen, die Parity 
auszuschalten. Da gibt es ein Register für.

> Das hüpfende Komma ist das "kann". Das muss man aber warscheinlich
> "manuell" das Bit7 ins das Bit8 bringen und der Empfänger wieder zurück.
> Zumindest ich,  falls ich  Chipdesigner wäre, käme nie auf die Idee
> jemand würde so etwas versuchen. Kein Standard = Kann gehen oder nicht.
> Hier gehts offensichtlich nicht :-/

Das verstehe ich nicht.

@Jörg: Ob 9-bit RS232 eher unbekannt ist, ist mir im Prinzip egal. Die 
Frage ist doch, kann Linux damit umgehen?

Hm, also scheinbar dubios.

Danke,

Günther

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

9-Bit-RS232 wird von den in PCs verbauten seriellen Schnittstellen nicht 
unterstützt. Mit viel Aufwand lässt sich das in Software nachbilden (vor 
dem Senden eines Bytes die Parität berechnen, Schnittstellenbetriebsart 
auf MARK bzw. SPACE umschalten, Byte senden), aber das ist bei üblicher 
Betriebssystemarchitektur kaum mit benutzbaren Datenraten hinzubekommen. 
Außerdem muss für derartige Aktionen zwingend der Sende-FIFO der 
Schnittstelle deaktiviert werden, da es keinen FIFO für die für die zu 
sendenden Zeichen zu verwendende Betriebsart gibt.

Vollkommen ausgeschlossen ist 9 Bit mit Parität.

von Michael U. (Gast)


Lesenswert?

Hallo,

bin jetzt echt zu faul zum Nachsuchen...

8Bit mit Parity ist kein 9Bit-Format sondern 8Bit mit Parity.
Parity wird vom UART in Hardware erzeugt und ausgewertet. Es wird bei 
Fehlern eben ParityError gesetzt. So machen es zumindest alle UARTs, an 
die ich mich noch erinnere und offenbar auch z.B. der im Mega8.

NoPartity heißt normalerweise, daß Parity immer als H auf der RS232 
gesendet wird, für den Empfänger heißt es, daß Parity nicht ausgewertet 
wird. Schlimmstenfalls wird es also als das ohnehin erwartete Stopbit 
ausgewertet.
Das kann eigentlich nur in der Version Sender mit No Parity - Empfänger 
No Parity ein Problem geben, wenn der Sender dann wirklich keine 
Parity-Bitzeit sendet, der Empfänger aber eine prüft und verwirft. Dann 
würde u.U. sofort das nächste Startbit kommen und verloren gehen können.

Hatte ich aber eigentlich nie, Sender mit 8N1, 8E1, 8O1 und Empfänger 
immer mit 8N1 ging immer, gab dann eben nur keine Parity-Auswertung.

Gruß aus Berlin
Michael

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


Lesenswert?

Günther Schmidt wrote:

> @Jörg: Baudratenabweichung klingt übel. Also beide Geräte verwenden die
> gleiche Baudrate ...

Meine Befürchtung war, dass der Prozessortakt des Empfängers nicht
stimmen würde und damit die Baudrate.

Aber:

> Eigentlich ist die Gegenstelle kein AVR, sondern ein
> RFID-Reader von Feig.

Das hattest du uns ja vorenthalten.  Damit war ich erst einmal davon
ausgegangen, dass die Gegenseite ein von dir gezimmerter Controller
ist, der dann dieses Problem haben könnte.

> @Jörg: Ob 9-bit RS232 eher unbekannt ist, ist mir im Prinzip egal. Die
> Frage ist doch, kann Linux damit umgehen?

Ich kenne mich zwar mit Linux nicht so gut aus (hier werkelt überall
ein FreeBSD), gehe aber stark davon aus, dass es das kann (im Sinne,
dass das 9. Bit ein Paritätsbit ist, wie von Michael beschrieben).

Kann es sein, dass dein Reader 7 bits + gerade Parität haben will,
d. h. dass 0xa8 bereits das Paritätsbit beinhaltet?  Wäre aber nicht
ganz klar, warum er dann 7 bits ohne Parität antworten soll.

von Günther S. (guenther)


Angehängte Dateien:

Lesenswert?

Hallo Rufus,

Danke für die Info. Also ich habe jetzt mal RxD mit TxD verbunden und 
0xAA (alternierend für den Oszi) gesendet.

Es wird auch mit 8 bit ohne Parität um's Verrecken nicht 0xAA 
zurückgelesen, sondern nur 0x2A.

Ich habe mal ein Oszibild angehängt. Das sollten 8 bit (0xAA) mit 
gerader Parität und einem Stoppbit sein. Irgendwie haut das aber nicht 
hin, es müssten doch eigentlich 11 bit sein, ich sehe aber nur 10.

Gemessen habe ich das an meiner Rx-Tx-Brücke.

Das versteh ich aber nicht. Der Reader antwortet mir nur, wenn er 
gültige Datenpakete bekommt. Wenn schon das senden nicht richtig klappt, 
warum antwortet mir dieser Idiot dann? Oder interpretiere ich das Bild 
einfach falsch. Ist das Stoppbit high oder low? Dann würde es nämlich 
wieder passen.

Günther

von Günther S. (guenther)


Lesenswert?

> Kann es sein, dass dein Reader 7 bits + gerade Parität haben will,
> d. h. dass 0xa8 bereits das Paritätsbit beinhaltet?  Wäre aber nicht
> ganz klar, warum er dann 7 bits ohne Parität antworten soll.

Im Datenblatt steht 8E1. Und wie gesagt, der antwortet nur, wenn er mich 
versteht (ein ziemlich eigenartiges Protokoll, wie ich finde). Wenn ich 
also mit 8E1 senden würde und er würde 7E1 erwarten, würde er mir doch 
nicht antworten, oder?

Btw. diese 0xA8 ist nur ein Byte eines ganzen Datenpaketes, jedoch in 
dem Fall das einzige, was MSB=1 hat. Das ganze Datenpaket muss also 
stimmen.

Günther

von max.p (Gast)


Lesenswert?

Hallo

Ist zwar kein Lösungsvorschlag, aber ich hab ein ähnliches Problem.
Beim Senden aus einem Java-Programm werden alle Bytes die im bereich von 
0x80 bis 0xFF sind zum Datenmüll. Liegt also auch am MSB. Habe auch 
schon verschiedene Baudraten versucht, ohne erfolg.
Bei mir leuft Ubuntu mir 2.6.15-27-686 Kernel.

mfg
Max

von Günther S. (guenther)


Lesenswert?

Hallo Max,

Hm, bei mir läuft auch ein 2.6.15-Kernel. Steht das im Zusammenhang? 
Kann ich mir bald nicht vorstellen.

Auf jeden Fall habe ich jetzt rausbekommen, dass das Stopbit high ist, 
also stimmt mein Oszi-Bild schonmal.

Irgendwie komme ich aber trotzdem nicht weiter.

Günther

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> NoPartity heißt normalerweise, daß Parity immer als H auf der RS232
> gesendet wird,

Nein. Das tut es nicht. Es wird überhaupt kein Bit übertragen. Was Du 
meinst, ist MARK bzw. SPACE Parity, das ist etwas anderes als "no 
parity".

Ein Byte, das 8n1 übertragen wird, benötigt exakt 10 Bitzeiten 
(Startbit, 8 Datenbits, ein Stopbit). Erst ein Byte, das 8e1 oder 8o1 
oder eben 8m1 bzw. 8s1 übertragen wird, benötigt 11 Bits, wobei 8m1 sich 
von 8n2 inhaltlich nicht unterscheidet.

> für den Empfänger heißt es, daß Parity nicht ausgewertet
> wird. Schlimmstenfalls wird es also als das ohnehin erwartete Stopbit
> ausgewertet.

... wenn denn die Polarität stimmt, anderenfalls gibt es einen Framing 
Error.

von Stefan (Gast)


Lesenswert?

Das Bild entspricht einer 8E1 Einstellung und enthält als Daten 0xAA.

MARK = keine Übertragung
0 Startbit (SPACE)
1 LSB
0
1
0
1
0
1 MSB
0 korrekt bei Even Parity
1 Stopbit
MARK = keine Übertragung

http://www.lammertbies.nl/comm/info/de_RS-232_specs.html

Das Problem kommt vermutlich von der einstellung der TTY Einleselayer 
her, also wäre dieser Code zu kontrollieren:

  //Raw data Einlesen mit Parity-check
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  options.c_iflag |= (INPCK | ISTRIP);

Und dann findet man ;-)

istrip
              lösche höchstes (8.) Bit der Eingabezeichen

http://man.cx/stty(1)/de

von Günther S. (guenther)


Lesenswert?

> istrip
>             lösche höchstes (8.) Bit der Eingabezeichen

Hm, hab ich jetzt mal rausgenommen, das Verhalten über meiner Brücke 
bleibt das gleiche.

Gibt es irgendein Kommandozeilenterminal für busybox? Dann könnte ich 
das mal so versuchen, ohne mein Programm.

Günther

von Stefan (Gast)


Lesenswert?

Wie rausgenommen?

So?
  options.c_iflag |= (INPCK /* | ISTRIP */);

oder so?
  options.c_iflag &= ~(ISTRIP);

von Günther S. (guenther)


Lesenswert?

Ahäm.

Hüstel.

Schluck!

You made my day.

Wo bitte kann ich die Flasche Wein hinschicken, die du dir jetzt 
verdient hast? Trinkst du eher rot oder weiß?

Was bitte nutzt so eine Funktion? Und dann noch als default.

Laut http://www.easysw.com/~mike/serial/serial.html#2_5 ist dieses 
ISTRIP dafür da, die Parity-bits zu löschen und nicht das 8. Datenbit.

Was also soll diese Funktion?

Wie auch immer. Danke. Danke. Danke.

Jetzt kann ich endlich rangehen, das hier in Gang zu bringen. Mal sehen, 
wann die nächste kleine Hürde sich als Barrikade vor mir auftürmt.

So long,

Günther

von Stefan (Gast)


Lesenswert?

Es war mir eine Ehre ;-)

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.