mikrocontroller.net

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


Autor: hotice (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.
#include <stdio.h>   /* Standard input/output definitions */
#include <stdlib.h>   /*  */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

int fd;

int writeport(int fd, char *chars, int signs) 
{
  //int len = strlen(chars);
  //chars[4] = 0x0d; // stick a <CR> after the command
  //chars[5] = 0x00; // terminate the string properly
  int n = write(fd, chars, signs);
  printf("geschrieben: %i\n", n);
  if (n < 0) 
  {
    fputs("write failed!\n", stderr);
    return 0;
  }
  return 1;
}

int readport(int fd, char *result) 
{
  int iIn = read(fd, result, 40);
  printf("gelesen: %i\n", iIn);
  //result[iIn] = 0x00;
  if (iIn < 0) {
    if (errno == EAGAIN) 
    {
      printf("SERIAL EAGAIN ERROR\n");
      return 0;
    } else 
    {
      printf("SERIAL read error %d %s\n", errno, strerror(errno));
      return 0;
    }
  }                    
  return 1;
}

int getbaud(int fd) 
{
  struct termios termAttr;
  int inputSpeed = -1;
  speed_t baudRate;
  tcgetattr(fd, &termAttr);
  /* Get the input speed.                              */
  baudRate = cfgetispeed(&termAttr);
  switch (baudRate) 
  {
    case B0:      inputSpeed = 0; break;
    case B50:     inputSpeed = 50; break;
    case B110:    inputSpeed = 110; break;
    case B134:    inputSpeed = 134; break;
    case B150:    inputSpeed = 150; break;
    case B200:    inputSpeed = 200; break;
    case B300:    inputSpeed = 300; break;
    case B600:    inputSpeed = 600; break;
    case B1200:   inputSpeed = 1200; break;
    case B1800:   inputSpeed = 1800; break;
    case B2400:   inputSpeed = 2400; break;
    case B4800:   inputSpeed = 4800; break;
    case B9600:   inputSpeed = 9600; break;
    case B19200:  inputSpeed = 19200; break;
    case B38400:  inputSpeed = 38400; break;
  }
  return inputSpeed;
}


int initport(int fd) 
{
  struct termios options;
  // Get the current options for the port...
  tcgetattr(fd, &options);
  // Set the baud rates to 19200...
  cfsetispeed(&options, B19200);
  cfsetospeed(&options, B19200);
  // Enable the receiver and set local mode...
  options.c_cflag |= (CLOCAL|CREAD);
  //options.c_cflag &= CLOCAL;  //Ausschalten der Modem-Steuerung
  //options.c_cflag &= CREAD;  //Aktivieren des Empfänger
  options.c_cflag &= ~PARENB;  //Einschalten von Paritätsprüfung.
  options.c_cflag &= ~CSTOPB;  //Zwei Stop-Bits anstelle von einem senden
  options.c_cflag &= ~CSIZE;  //Bitanzahl für ein Zeichen (CS5 bis CS8)
  options.c_cflag |= CS8;    //8 Datenbits
  options.c_cflag &= ~CRTSCTS;  //Einschalten der Hardware-Flußkontrolle(RTS und CTS)

  options.c_cflag &= ~HUPCL;  //Verbindungsabbruch bei Beendigung des letzten Prozesses
  //options.c_iflag &= ~BRKINT;  //Generieren von SIGINT bei Tastendruck auf BREAK
  //options.c_iflag &= ~ICRNL;  //Umwandeln von CR in NL bei der Eingabe
  options.c_iflag &= IGNBRK;  //Break Ignorieren
  options.c_iflag &= IGNCR;  //CR Ignorieren
  options.c_iflag &= IGNPAR;  //Bytes mit Paritätsprüfung ignorieren
  //options.c_iflag &= ~IMAXBEL;  //Akustisches Signal wenn Eingabepuffer voll ist BREAK ignorieren
  //options.c_iflag &= ~INLCR;  //Umwandeln von NL in CR bei CR ignorieren der Eingabe
  options.c_iflag &= ~INPCK;  //Einschalten der Eingabe-Partitätsprüfung
  options.c_iflag &= ~ISTRIP;  //Abschneiden des 8.Bit bei Eingabezeichen
  //options.c_iflag &= ~IUCLC;  //Umwandeln von Groß in Kleinbuchstaben
  //options.c_iflag &= ~IXANY;  //Wartet auf ein X-beliebiges Zeichen um mit der Ausgabe fortzusetzen
  options.c_iflag &= ~IXOFF;  //Einschalten des START/STOP - Eingabeprotokolls
  options.c_iflag &= ~IXON;  //Einschalten des START/STOP - Ausgabeprotokolls
  options.c_iflag &= ~PARMRK;  //Markieren von Partitätsfehler
  

  // Set the new options for the port...
  tcsetattr(fd, TCSANOW, &options);
  return 1;
}

int main(int argc, char **argv) 
{

  fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1) 
  {
    perror("open_port: Unable to open /dev/ttyS0 - ");
    return 1;
  } else 
  {
    fcntl(fd, F_SETFL, 0);
  }
  
  printf("old baud=%d\n", getbaud(fd));
  initport(fd);
  printf("new baud=%d\n", getbaud(fd));

  //Befehle für Relaispaltiene
  char sCmd[4];
  sCmd[0] = 0x01;  //Befehl 1: init  3: set Relais
  sCmd[1] = 0x01;  //Adresse -> immer 1
  sCmd[2] = 0x00;  //Daten
  sCmd[3] = sCmd[0] ^ sCmd[1] ^ sCmd[2]; //Prüfsumme

  if (!writeport(fd, sCmd, 4)) 
  {
    printf("write failed\n");
    close(fd);
    return 1;
  }

  printf("Schreiben:\n");
  printf("Befehl   :0X%x\n", sCmd[0]);
  printf("Adresse  :0X%x\n", sCmd[1]);
  printf("Daten    :0X%x\n", sCmd[2]);
  printf("Prüfsumme:0X%x\n", sCmd[3]);
  
  //gerät Zeit zum Antworten geben  
  sleep(1);

/*
  fd_set input_fdset;
  FD_ZERO(&input_fdset);
  FD_SET(fd,&input_fdset);
  
  int test;
  test = select(fd, &input_fdset,NULL,NULL,NULL);
*/


  char sResult[40];
  fcntl(fd, F_SETFL, FNDELAY); // don't block serial read

  if (!readport(fd,sResult)) 
  {
    printf("read failed\n");
    close(fd);
    return 1;
  }
  printf("Lesen:\n");
  printf("readport=0x%u\n", sResult[0]&0x000000ff); //warum ist das erste Zeichen 4 Byte breit?
//  printf("readport=0x%u\n", sResult[0]);
  printf("readport=0x%u\n", sResult[1]);
  printf("readport=0x%u\n", sResult[2]);
  printf("readport=0x%u\n", sResult[3]);
//  printf("readport=0x%s\n", sResult);

  close(fd);
  return 0;
}

Autor: hotice (Gast)
Datum:

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

Autor: P.S. (Gast)
Datum:

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

Autor: hotice (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.