Forum: PC-Programmierung LINUX - C - RS232 - Raw output & input


von Oliver R. (roliver)


Lesenswert?

Linux steuert mit C Programm über RS232 einen AVR

Hallo Gemeinde,

ich bin dabei ein Programm zu schreiben mit dem ich ein Controller per 
RS232 (FT232LR) zu steuern. meine Programm ist schon fast fertig. doch 
ich habe eine Problem, denn ich kann leider nicht alle Zeichnen über die 
schnittstelle schicken.
Als beispiel, kann ich die folge: 0x0C, 0x00, 0x04 nicht senden. Denn 
0x0C ist ein Steuercode (FF) denn ich leider nicht senden kann, was ist 
den in meinem Programmcode falsch? Ich möchte alle Bytes von 0x00 bis 
0xff senden können, aber wie??
1
 
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <sys/ioctl.h>
5
#include <sys/types.h>
6
#include <sys/stat.h>
7
#include <fcntl.h>
8
#include <unistd.h>
9
#include <signal.h>
10
#include <termios.h>
11
#include <string.h>
12
#include <stdbool.h>
13
14
int fd = 0;
15
16
int main(int argc, char** argv)
17
{
18
  struct termios oldtios,options;
19
  int currstat = 0;
20
  if((argc < 2)||(argc > 3))
21
    {
22
      printf("Fehler: Ungültige Parameter-Anzahl.\n");
23
      printf("Aufruf:\n");
24
      printf("  %s <device>\n",argv[0]);
25
      return 1;
26
    }
27
28
  /* Das Device öffnen */
29
  if((fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
30
    {
31
      printf("Fehler: Device \"%s\" kann nicht geöffnet werden.\n", argv[1]);
32
      return 2;
33
    }
34
35
  tcgetattr(fd,&oldtios);
36
37
  fcntl(fd, F_SETFL, 0);
38
  if (tcgetattr(fd, &options) != 0) return(-1);
39
40
  cfsetispeed(&options, B115200);            /* setze 115200 bps */
41
  cfsetospeed(&options, B115200);
42
43
  options.c_cflag &= ~PARENB;               /*  kein Paritybit */
44
  options.c_cflag &= ~CSTOPB;               /* 1 Stopbit */
45
  options.c_cflag &= ~CSIZE;                /* 8 Datenbits */
46
  options.c_cflag |= CS8; 
47
  options.c_cflag &= ~CRTSCTS;
48
  options.c_cflag |= (CLOCAL | CREAD);      /* CD-Signal ignorieren */
49
  /* Kein Echo, keine Steuerzeichen, keine Interrupts */
50
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
51
  options.c_oflag &= ~OPOST;                /* setze "raw" Input */
52
  options.c_cc[VMIN]  = 0;                  /* warten auf min. 0 Zeichen */
53
  options.c_cc[VTIME] = 10;                 /* Timeout 10 Sekunden */
54
55
  tcflush(fd,TCIOFLUSH);
56
  if (tcsetattr(fd, TCSAFLUSH, &options) != 0) return(-1);
57
  char buffer[8];
58
59
  // Version
60
  buffer[0]=0x11;
61
  buffer[1]=0x00;
62
  buffer[2]=0x04;
63
64
65
  printf("-Eingabe---------------------\n");
66
  int i;
67
  for (i=0; i<3; i++ )
68
  {
69
    printf("0x%02x ",buffer[i]);
70
  }
71
  printf("\n");
72
  printf("-----------------------------\n");
73
74
  // buffer schreiben
75
  i = write(fd,buffer,3); //ist das OK?
76
  printf("geschrieben: %i\n",i);
77
  printf("-----------------------------\n");
78
79
  int bb = 0;
80
  int x = 0;
81
  bool cmdOK=false;
82
  char cods[10];
83
84
  /*
85
86
      ABHIER?
87
      Lese des Gerätes, antwort solte sein:
88
      0x1A, 0x03, 0x02, 0x00, 0x00, 0x04 (0x04 sollte EOT sein)
89
      aber was ist da falsch?
90
  */
91
  do
92
  {
93
    //printf("\n");
94
    if((bb = read( fd, &cods[x], sizeof( cods )-x )) > 0)
95
    //if((bb = read( fd, &cods, 5 )) > 0)
96
    {
97
      for (i=x;i<x+bb;i++)
98
        {
99
          //printf("0x%02x ",cods[i]);
100
          if (cods[i]==0x04) cmdOK=true;
101
        }
102
      x+=bb;
103
      //printf("\n");
104
      //printf("in if: x=%d\n",x);
105
    }
106
    //printf("nach if bb=%d\n",bb);
107
108
  }while(!cmdOK);
109
110
  printf("-Ausgabe---------------------\n");
111
  for (i=0; i<x; i++ )
112
  {
113
    printf("0x%02x ",cods[i]);
114
  }
115
  printf("\n");
116
  printf("-----------------------------\n");
117
118
119
  close(fd);
120
121
122
  // TTYS0 auf alten Wert setzen
123
  tcflush(fd,TCIOFLUSH);
124
  if (tcsetattr(fd, TCSAFLUSH, &oldtios) != 0) return(-1);
125
126
  return 0;
127
}

Bitte um Hilfs, Danke

Gruß

Oliver

von rant (Gast)


Lesenswert?


von Oliver R. (roliver)


Lesenswert?

Danke, wenn ja hätte ich hier nix geschrieben oder?

von Konrad S. (maybee)


Lesenswert?

Du solltest options vor der Verwendung mit Nullen füllen oder nach dem 
tcgetattr() mit oldtios vorbelegen.

Vor und nach dem tcsetattr() könntest du mit
 system(cmd);
die Einstellungen prüfen, wobei cmd mit
 sprintf(cmd,"stty -a < %s",argv[1])
zu belegen ist.

> options.c_cc[VTIME] = 10;          /* Timeout 10 Sekunden */
Wert passt nicht zum Kommentar (hat aber nichts mit dem Problem zu tun).

von Oliver R. (roliver)


Angehängte Dateien:

Lesenswert?

Hallo,

hier der CODE als Datei ;-)

Gruß

Oliver

von Oliver R. (roliver)


Lesenswert?

Hallo,

habe ich jetzt getan. Doch immer noch nicht richtig.

hier mal die Ausgabe:
1
./ioboard /dev/ttyUSB0
2
speed 115200 baud; rows 0; columns 0; line = 0;
3
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
4
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
5
werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 10;
6
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
7
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff
8
-iuclc -ixany -imaxbel -iutf8
9
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
10
-isig -icanon iexten -echo -echoe echok -echonl -noflsh xcase -tostop -echoprt
11
-echoctl echoke
12
-Eingabe---------------------
13
0x0c 0x00 0x04
14
-----------------------------
15
geschrieben: 3
16
-----------------------------
17
0xf9 0x01 in if: x=2
18
0x02 0x04 in if: x=4
19
-Ausgabe---------------------
20
0xf9 0x01 0x02 0x04
21
-----------------------------

doch es sollte: 0x1A 0x01 0x34 0x04 sein.

doch leider nicht!!

Gruß

Oliver

von Konrad S. (maybee)


Lesenswert?

Die Ausgabe sieht aus wie vor tcsetattr(). Wie sieht es denn danach aus?

von Oliver R. (roliver)


Angehängte Dateien:

Lesenswert?

so:
1
VOR tcsetattr
2
speed 115200 baud; rows 0; columns 0; line = 0;
3
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
4
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
5
werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 10;
6
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
7
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff
8
-iuclc -ixany -imaxbel -iutf8
9
opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
10
-isig -icanon iexten -echo -echoe echok -echonl -noflsh -xcase -tostop -echoprt
11
-echoctl echoke
12
13
14
15
Nach tcsetattr
16
speed 115200 baud; rows 0; columns 0; line = 0;
17
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
18
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
19
werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 10;
20
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
21
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff
22
-iuclc -ixany -imaxbel -iutf8
23
opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
24
-isig -icanon iexten -echo -echoe echok -echonl -noflsh -xcase -tostop -echoprt
25
-echoctl echoke


gleich? was ist das ?

neuster source code als file

Gruß

Oliver

PS.: schon mal danke ;-)

von Konrad S. (maybee)


Lesenswert?

> Du solltest options vor der Verwendung mit Nullen füllen oder nach dem
> tcgetattr() mit oldtios vorbelegen.

Damit meinte ich
 memset(&options,0,sizeof(options));
oder
 options = oldtios;
um sicherzugehen, dass die gesamte Struktur definierte Werte aufweist.
Deswegen: "This structure contains at least the following members:".

von Konrad S. (maybee)


Lesenswert?

Schon komisch, dass vorher und nachher die Einstellungen gleich sind!

von Oliver R. (roliver)


Lesenswert?

mist, erschreibt das alte nicht zurück und ich habe jetzt
folgendes eingefügt:
1
struct termios oldtios,options;
2
memset(&options,0,sizeof(options));
3
memset(&oldtios,0,sizeof(oldtios));
4
int currstat = 0;

doch die Steurcodes bei der Ausgabe werden immer noch beachtet.

1
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0

was mach ich den da falsch ....

es muss doch gehen ...

Gruß

Oliver

von Konrad S. (maybee)


Lesenswert?

Oliver R. schrieb:
> mist, erschreibt das alte nicht zurück

Das
 close(fd);
kommt zu früh. Da muss hinter
 if (tcsetattr(fd, TCSAFLUSH, &oldtios) != 0)

von Konrad S. (maybee)


Lesenswert?

Und sei nicht so geizig bei cmd: das ist zu klein!

von Oliver R. (roliver)


Lesenswert?

ok, habe ich schon geändert, an einem anderen linux pc kommt das als 
antwort

-Ausgabe---------------------
0xfffffff9 0x01 0x02 0x04
-----------------------------

doch der controler sendet nur byte weise.

auch es sind auch echte pc keine vm oder so..

von Konrad S. (maybee)


Lesenswert?

>> Du solltest options vor der Verwendung mit Nullen füllen oder nach dem
>> tcgetattr() mit oldtios vorbelegen.
>
> Damit meinte ich
>  memset(&options,0,sizeof(options));
> oder
>  options = oldtios;
> um sicherzugehen, dass die gesamte Struktur definierte Werte aufweist.
> Deswegen: "This structure contains at least the following members:".

Ah, da hab ich übersehen, dass du da noch ein tcgetattr(fd, &options) 
drin hast. Da ist ja auch OK.

von Konrad S. (maybee)


Lesenswert?

Oliver R. schrieb:
> 0xfffffff9 0x01 0x02 0x04
> -----------------------------
>
> doch der controler sendet nur byte weise.

Das ist schon OK. cods ist char, also signed. "0x%02x" gibt zweistellig 
aus, wenn es Platz hat. Hat es aber nicht, weil das signed char 0xf9 
vorzeichenrichtig auf int erweitert wird. Also entweder cods als 
unsigned char deklarieren oder mit
 printf("0x%02x ",(unsigned char)cods[i]);
casten.

von Oliver R. (roliver)


Lesenswert?

ja, das ist mir dann ach noch klar geworden, doch ich verstehe jetzt 
nicht was ich noch ändern soll, es geht immer noch nicht. mit den doffen 
windows programm in excel (ja, ist schon ..) gehts!! aber in liunx 
sollte das doch auch gehen.

Gruß Oliver

von Hans-jürgen H. (hjherbert) Benutzerseite


Lesenswert?

Aus C / C++ heraus mache ich das so:




FUNCT int seropen( u8 ser_port_no ) // LINUX

{

int rv ;

struct termios xt ;

char cmdbuf[80] ;



if ( ser_port_no < MAX_INTERFACENO )

  {

  if ( !seropened[ser_port_no] )

    { // 2012-01-08

    nsprintf( cmdbuf, sizeof(cmdbuf), // Dahin die Kommandozeile fuer 
das Umschalten der Baudrate

        "stty <%s %lu",

        sername[ser_port_no],

        ser_settings_field[ser_port_no].baud );


    system( cmdbuf );

    fdser[ser_port_no] = normopen( sername[ser_port_no] , O_RDWR );

    if ( fdser[ser_port_no] >= 0 )

      {

      fcntl( fdser[ser_port_no], F_SETFL, O_NONBLOCK );

      tcgetattr( fdser[ser_port_no] , &xt );        /* Aktuelle 
Einstellung holen für Änderung */

      tcgetattr( fdser[ser_port_no] , &ser_stat_orig[ser_port_no] );  /* 
Aktuelle Einstellung für Exit */

      xt.c_lflag &= ~ICANON ;

      xt.c_lflag &= ~ECHO ;

      xt.c_iflag &= ~ICRNL ;

      xt.c_iflag &= ~BRKINT ;

      xt.c_iflag &= ~IGNBRK ;

      xt.c_iflag &= ~IGNCR ;

      xt.c_iflag &= ~IGNPAR ;

      xt.c_iflag &= ~IMAXBEL ;

      xt.c_iflag &= ~BRKINT ;

      rv = tcsetattr( fdser[ser_port_no] , TCSANOW, &xt );

      if ( rv < 0 )

        {

        uprintf( "cannot tcsetattr serial line %s", sername[ser_port_no] 
);

        }

      seropened[ser_port_no] = true ;

      return 0 ;    // opened succesful

      }

    printf( "cannot open %s for RW, errno=%d", sername[ser_port_no] , 
errno );

    return 1 ;

    }

  return 2 ;

  }

else

  {

  printf( "bad interface number" );

  return 4 ;

  }

}




FUNCT int serclose( u8 ser_port_no )    // LINUX

{

int rv ;



if ( ser_port_no < MAX_INTERFACENO )

  {

  tcsetattr( fdser[ser_port_no], TCSANOW, &ser_stat_orig[ser_port_no] );

  close( fdser[ser_port_no] );

  // vt_opened = false ;

  rv = 0 ;      // no error

  }

else

  {

  rv = 1 ;      // some error

  }

}

von Hans-jürgen H. (hjherbert) Benutzerseite


Lesenswert?

Aus der Kommandozeile heraus, z.B. für JAVA-Programme mache ich das so:

stty -F /dev/ttyUSB0 speed 9600 cs8 -parenb -parodd raw -echo


Besonders wichtig ist hier -echo, sonst wird euf jedes hereinkommende 
Zeichen geantwortet, z.B: auf 0x02 mit "^B"


und zurück in den Textmodus geht es mit:


stty -F /dev/ttyUSB0 speed 9600 cs8 -parenb intr 3 quit 28 erase 127 
kill 21 eof 4 eol 13 eol2 undef swtch undef start 17 stop 19 susp 26 
rprnt 18 werase 23 lnext 22 flush 15 min 1 time 0 -parenb -parodd -hupcl 
-cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck 
-istrip -inlcr igncr icrnl ixon ixoff -iuclc -ixany -imaxbel -iutf8 
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 
vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase 
-tostop -echoprt echoctl echoke


(Alles in eine einzige Zeile)

von Oliver R. (roliver)


Lesenswert?

Hallo,
ja danke, das geht auch, doch ich wollte gerne die Einstelung der 
schnittstelle in meinem C code haben. Aber genau das wäre die
Einstellung für die Schnittstelle.

stty -F /dev/ttyUSB0 speed 9600 cs8 -parenb -parodd raw -echo

-parend => kein Paritätsbit
-parodd => Ungrade Paritätsbit

ergo: ttyUSB0 9600 8N1 RAW keine echo ;-)

und das jetzt in C !!! ;-)

das ist noch die Frage, denn mein Programm hängt sich noch auf ;-)

Hat da jemand eine Code?


Gruß

Oliver

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.