Forum: PC-Programmierung linux rs232 empfängt nur sporadisch


von hotice (Gast)


Angehängte Dateien:

Lesenswert?

Ich schicke Ihnen die Fehlerbeschreibung und den Quellcode als Ergänzung 
zu meiner letzte E-Mail.
Es wäre schön, wenn Sie kurz reinschauen können und eventuell ein Paar 
Gedanken dazu schreiben.
Hallo, ich lese recht viel im Forum mit und hoffe nun eure Kompetenz 
einmal aktiv nutzen zu können ;) Ich habe ein kleinen Linux Problem beim 
Handling der RS232.

Das Problem:

Ich versuche im Linux schreibend/lesend auf eine 8-Fach Relais Platine 
zu zugreifen. Die Komm Parameter der Platine sind: 19200 Baud, 8 
Datenbits, 1 Stopbit, keine Parität, kein Handshake.
Als Softwareplattform verwende ich verschiedene Hardware, einmal einen 
etwas älteren PC mit RS232 auf dem Mainboard und einmal einen aktuellen 
PC mit USB->RS232 Adapter. Das Betriebssystem ist beide male ein Ubuntu 
9.1 mit einem 2.6 Kernel. Das Fehlerbild ist bei beiden gleich.

Zum Problem:
Ich kann mit dem geposteten Quelltext bereits problemlos schreibend auf 
die Platine zugreifen. Die Befehle werden jedes Mal ausgeführt (die 
Relais schalten). Probleme habe ich beim Empfangen der Antwort der 
Relaisplatine. Jeder Befehl wird von ihr mit einer Antwort quittiert. 
Das klappt jedoch nur manchmal. Das kuriose ist, das ich immer einen 
EAGAIN Error bekomme, außer bei zwei Befehlen. Zum Einen 1 1 0, also dem 
Initialisierungsaufruf und dem Befehl 3 1 4, der Anweisung das 3. Relais 
zu schließen. Nur bei diesen beiden Befehlen bekomme ich eine Antwort. 
Alle anderen Anweisungen werden zwar ausgeführt aber beim Abfragen des 
Eingabepuffers erhalte ich einen EAGAIN Error. Ich habe jetzt schon mit 
den input settings der termios.h herumgespielt, aber keine Erfolge 
erzielen können.

Mit Windows habe ich bereits selbige Funktionalität umgesetzt, über ein 
C# Programm. Dort geht alles, ergo ist die Relaisplatine ok und sendet 
auch.

Ich habe den unten stehnden Code nochmal als*.c File angehängt, fals es 
mal jemand mit dem gcc testen will.
1
#include <stdio.h>   /* Standard input/output definitions */
2
#include <stdlib.h>   /*  */
3
#include <string.h>  /* String function definitions */
4
#include <unistd.h>  /* UNIX standard function definitions */
5
#include <fcntl.h>   /* File control definitions */
6
#include <errno.h>   /* Error number definitions */
7
#include <termios.h> /* POSIX terminal control definitions */
8
9
int fd;
10
11
int writeport(int fd, char *chars, int signs) 
12
{
13
  //int len = strlen(chars);
14
  //chars[4] = 0x0d; // stick a <CR> after the command
15
  //chars[5] = 0x00; // terminate the string properly
16
  int n = write(fd, chars, signs);
17
  printf("geschrieben: %i\n", n);
18
  if (n < 0) 
19
  {
20
    fputs("write failed!\n", stderr);
21
    return 0;
22
  }
23
  return 1;
24
}
25
26
int readport(int fd, char *result) 
27
{
28
  int iIn = read(fd, result, 40);
29
  printf("gelesen: %i\n", iIn);
30
  //result[iIn] = 0x00;
31
  if (iIn < 0) {
32
    if (errno == EAGAIN) 
33
    {
34
      printf("SERIAL EAGAIN ERROR\n");
35
      return 0;
36
    } else 
37
    {
38
      printf("SERIAL read error %d %s\n", errno, strerror(errno));
39
      return 0;
40
    }
41
  }                    
42
  return 1;
43
}
44
45
int getbaud(int fd) 
46
{
47
  struct termios termAttr;
48
  int inputSpeed = -1;
49
  speed_t baudRate;
50
  tcgetattr(fd, &termAttr);
51
  /* Get the input speed.                              */
52
  baudRate = cfgetispeed(&termAttr);
53
  switch (baudRate) 
54
  {
55
    case B0:      inputSpeed = 0; break;
56
    case B50:     inputSpeed = 50; break;
57
    case B110:    inputSpeed = 110; break;
58
    case B134:    inputSpeed = 134; break;
59
    case B150:    inputSpeed = 150; break;
60
    case B200:    inputSpeed = 200; break;
61
    case B300:    inputSpeed = 300; break;
62
    case B600:    inputSpeed = 600; break;
63
    case B1200:   inputSpeed = 1200; break;
64
    case B1800:   inputSpeed = 1800; break;
65
    case B2400:   inputSpeed = 2400; break;
66
    case B4800:   inputSpeed = 4800; break;
67
    case B9600:   inputSpeed = 9600; break;
68
    case B19200:  inputSpeed = 19200; break;
69
    case B38400:  inputSpeed = 38400; break;
70
  }
71
  return inputSpeed;
72
}
73
74
75
int initport(int fd) 
76
{
77
  struct termios options;
78
  // Get the current options for the port...
79
  tcgetattr(fd, &options);
80
  // Set the baud rates to 19200...
81
  cfsetispeed(&options, B19200);
82
  cfsetospeed(&options, B19200);
83
  // Enable the receiver and set local mode...
84
  options.c_cflag |= (CLOCAL|CREAD);
85
  //options.c_cflag &= CLOCAL;  //Ausschalten der Modem-Steuerung
86
  //options.c_cflag &= CREAD;  //Aktivieren des Empfänger
87
  options.c_cflag &= ~PARENB;  //Einschalten von Paritätsprüfung.
88
  options.c_cflag &= ~CSTOPB;  //Zwei Stop-Bits anstelle von einem senden
89
  options.c_cflag &= ~CSIZE;  //Bitanzahl für ein Zeichen (CS5 bis CS8)
90
  options.c_cflag |= CS8;    //8 Datenbits
91
  options.c_cflag &= ~CRTSCTS;  //Einschalten der Hardware-Flußkontrolle(RTS und CTS)
92
93
  options.c_cflag &= ~HUPCL;  //Verbindungsabbruch bei Beendigung des letzten Prozesses
94
  //options.c_iflag &= ~BRKINT;  //Generieren von SIGINT bei Tastendruck auf BREAK
95
  //options.c_iflag &= ~ICRNL;  //Umwandeln von CR in NL bei der Eingabe
96
  options.c_iflag &= IGNBRK;  //Break Ignorieren
97
  options.c_iflag &= IGNCR;  //CR Ignorieren
98
  options.c_iflag &= IGNPAR;  //Bytes mit Paritätsprüfung ignorieren
99
  //options.c_iflag &= ~IMAXBEL;  //Akustisches Signal wenn Eingabepuffer voll ist BREAK ignorieren
100
  //options.c_iflag &= ~INLCR;  //Umwandeln von NL in CR bei CR ignorieren der Eingabe
101
  options.c_iflag &= ~INPCK;  //Einschalten der Eingabe-Partitätsprüfung
102
  options.c_iflag &= ~ISTRIP;  //Abschneiden des 8.Bit bei Eingabezeichen
103
  //options.c_iflag &= ~IUCLC;  //Umwandeln von Groß in Kleinbuchstaben
104
  //options.c_iflag &= ~IXANY;  //Wartet auf ein X-beliebiges Zeichen um mit der Ausgabe fortzusetzen
105
  options.c_iflag &= ~IXOFF;  //Einschalten des START/STOP - Eingabeprotokolls
106
  options.c_iflag &= ~IXON;  //Einschalten des START/STOP - Ausgabeprotokolls
107
  options.c_iflag &= ~PARMRK;  //Markieren von Partitätsfehler
108
  
109
110
  // Set the new options for the port...
111
  tcsetattr(fd, TCSANOW, &options);
112
  return 1;
113
}
114
115
int main(int argc, char **argv) 
116
{
117
118
  fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
119
  if (fd == -1) 
120
  {
121
    perror("open_port: Unable to open /dev/ttyS0 - ");
122
    return 1;
123
  } else 
124
  {
125
    fcntl(fd, F_SETFL, 0);
126
  }
127
  
128
  printf("old baud=%d\n", getbaud(fd));
129
  initport(fd);
130
  printf("new baud=%d\n", getbaud(fd));
131
132
  //Befehle für Relaispaltiene
133
  char sCmd[4];
134
  sCmd[0] = 0x01;  //Befehl 1: init  3: set Relais
135
  sCmd[1] = 0x01;  //Adresse -> immer 1
136
  sCmd[2] = 0x00;  //Daten
137
  sCmd[3] = sCmd[0] ^ sCmd[1] ^ sCmd[2]; //Prüfsumme
138
139
  if (!writeport(fd, sCmd, 4)) 
140
  {
141
    printf("write failed\n");
142
    close(fd);
143
    return 1;
144
  }
145
146
  printf("Schreiben:\n");
147
  printf("Befehl   :0X%x\n", sCmd[0]);
148
  printf("Adresse  :0X%x\n", sCmd[1]);
149
  printf("Daten    :0X%x\n", sCmd[2]);
150
  printf("Prüfsumme:0X%x\n", sCmd[3]);
151
  
152
  //gerät Zeit zum Antworten geben  
153
  sleep(1);
154
155
/*
156
  fd_set input_fdset;
157
  FD_ZERO(&input_fdset);
158
  FD_SET(fd,&input_fdset);
159
  
160
  int test;
161
  test = select(fd, &input_fdset,NULL,NULL,NULL);
162
*/
163
164
165
  char sResult[40];
166
  fcntl(fd, F_SETFL, FNDELAY); // don't block serial read
167
168
  if (!readport(fd,sResult)) 
169
  {
170
    printf("read failed\n");
171
    close(fd);
172
    return 1;
173
  }
174
  printf("Lesen:\n");
175
  printf("readport=0x%u\n", sResult[0]&0x000000ff); //warum ist das erste Zeichen 4 Byte breit?
176
//  printf("readport=0x%u\n", sResult[0]);
177
  printf("readport=0x%u\n", sResult[1]);
178
  printf("readport=0x%u\n", sResult[2]);
179
  printf("readport=0x%u\n", sResult[3]);
180
//  printf("readport=0x%s\n", sResult);
181
182
  close(fd);
183
  return 0;
184
}

von hotice (Gast)


Lesenswert?

Ahh, ich kann als Gast nicht editieren, sorry, die ersten 4 Zeilen bitte 
einfach ignorieren.

von P.S. (Gast)


Lesenswert?

Beim Lesen im Non-Blocking-Modus liefert read EAGAIN, wenn keine Daten 
vorhanden sind.

von hotice (Gast)


Lesenswert?

Hallo P.S.,

danke für deine Antwort. Das ist mir bereits bekannt. Wie oben aber 
schon geschrieben, weis ich das die Paltine 100% etwas an mich zurück 
sendet.

Ich ahbe das Problem gerade gelöst. Ich ahbe aber gerade 3 Änderungen 
vorgenommen, wenn ich weis welche für den Erfolg zuständig war, werde 
ich die Antwort noch posten.

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.