PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Merkwürdiges Kompilierproblem mit dem gcc...



rockin_santa
13.05.2008, 22:25
Hallo Zusammen,

Ich habe einen ATmega32, der einen kleinen Bot steuert und bin gerade dabei, die Kommunikation mit meinem Linux-PC (Ubuntu, Kernel 2.6.24) in C zu implementieren.
Mein µC gibt momentan timergesteuert über die serielle Schnittstelle ein wiederkehrendes Byte aus. Über ein Terminalprogramm kann ich sehen, wie die Bytes "einfliegen". So weit so gut.

Nun versuche ich, eine Funktion in C zu schreiben, die die serielle Schnittstelle am PC öffnet und konfiguriert, dass ich einzelne Bytes hin- und herschicken kann.
Hierzu orientiere ich mich an einigen deutsch- und englischsprachigen Tutorials im Netz (um mal eines zu nennen. (http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/x56.html)).
In diesen wird immer erläutert, dass die Konfigurationsparameter der Schnittstelle in einer Struktur vom Typ "termios" abgelegt werden. Soweit ist alles klar. Ich erzeuge also eine Struktur und öffne das Device.

Sobald ich aber die Funktionen
tcgetattr(<filedescriptor>,&<struktur>); /* Funktion der <termios.h> */ oder
cfsetispeed(&<struktur>, BAUDRATE); /* Funktion der <termios.h> */ verwende, spuckt mir der gcc beim kompilieren eine Warnung entgegen:
rs232.c:36: Warnung: Übergabe des Arguments 2 von »tcgetattr« von inkompatiblem Zeigertyp und
rs232.c:37: Warnung: Übergabe des Arguments 1 von »cfsetispeed« von inkompatiblem Zeigertyp
Seltsamerweise verwenden alle Tutorials diese Syntax. Nagut, ist nur eine Warnung, er kompiliert es ja fertig.

Nun komm ich aber zu meinem eigentlichen Problem:
In den Tutorials werden die Konfigurationsflags mit folgender Syntax gesetzt:

rs232.c_cflag = CLOCAL | CREAD; /* als Beispiel */
Hierbei wird ja bekanntlich auf eine Komponente innerhalb einer Struktur zugegriffen. Ich kann in dieser Zeile keinen Fehler sehen und sämtliche Tutorials benutzen auch genau diese Syntax in ihren Beispielprogrammen.
Dennoch reagiert mein gcc äußerst ungehalten mit der Aussage:
rs232.c:39: Fehler: Anfrage nach Element »c_cflag« in etwas, was keine Struktur oder Variante ist

Ja, und hier bin ich mit meinem Latein am Ende. Wenn ein Tutorial diese Syntax verwendet, gehe ich vielleicht noch davon aus, dass sich dort einfach ein Fehler eingeschlichen hat, aber alle verwenden diese Zeile so... :-k
Wie, wenn nicht so, kann ich meine Schnittstelle denn konfigurieren?
Oder sehe ich vielleicht den Wald vor lauter Bäumen nicht?

MfG rockin_santa

izaseba
13.05.2008, 23:47
Hallo,
es wäre besser gewesen, wenn Du Dein Programm mal gepostet hättest, warum ?

Als was wurde rs232 deklariert ?
Der Fehlermeldung nach ist es keine termios struct

Bevor wir hier lange Fehlerlesen machen schick ich Dir mal meine bewährte Routine, ok ?

Wenn Du immernoch was nicht verstehst frag mal ruhig,
achso Das Programm macht nichts anderes, als in einer Endlosschleife auf Daten vom µC zu warten.



#include <stdio.h>
#include <stdlib.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
#include <termios.h>
#include <fcntl.h>
#define DEVICE "/dev/ttyS0"
#define BAUD B9600

int open_port(void){
int fd_ser;
struct termios terminal;
fd_ser = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (fd_ser == -1)
{
perror("Kann die Serielle nicht oeffnen");
exit(1);
}
fcntl(fd_ser, F_SETFL,FNDELAY);
terminal.c_cflag = BAUD | CS8 | CLOCAL | CREAD;
terminal.c_oflag &= ~OPOST;
terminal.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tcflush(fd_ser,TCIOFLUSH);
tcsetattr(fd_ser,TCSANOW,&terminal);
return fd_ser;
}


int read_port(int *fd_ser,unsigned char* buffer) {
int a;
/*Variablen für select*/
fd_set rfds;
struct timeval tv;
int retval;

FD_ZERO(&rfds);
FD_SET(*fd_ser,&rfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
retval = select(*fd_ser+1,&rfds,NULL,NULL,&tv);
if (retval) {
a=read(*fd_ser,buffer,255);
return a;
} else return 0;


}


int main(void){
int bytes;
int i;
int fd_ser;
unsigned char puffer[256];
fd_ser = open_port();
while(1){
bytes = read_port(&fd_ser,puffer);
if( bytes > 0){
for (i = 0;i< bytes;i++){
printf("%i\t",puffer[i]);
}
printf("\n");
}
}
return 0;
}


Gruß Sebastian

P.S. Ich habe das Programm eben durch den Kompiler gejagt, es gab keine Fehler/Warnungen

rockin_santa
14.05.2008, 07:20
Ich danke Dir, izaseba, ich werde mir Deinen Code heute abend durchsehen.

Ich gebe zu, ich hätte den ganzen Code ruhig posten können, ich hole das mal nach:


#include <stdio.h> /* Standard I/O */
#include <string.h> /* Zeichenkettenfunktionen */
#include <unistd.h> /* UNIX Standardfunktionen */
#include <fcntl.h> /* Dateikontrolle */
#include <termios.h> /* POSIX Terminalkonfiguration */

#define BAUDRATE B2400
#define DEVICE "/dev/ttyUSB0"

int main(void)
{
/* Initialisierung */
int fd;
struct termios backup, rs232;

/* Arbeitsbeginn */
fd = rs232_oeffnen();
rs232_schliessen();
return 0;
}


/* *** Funktionen *** *** *** *** *** */

/* Oeffnen der virtuellen seriellen Schnittstelle "/dev/ttyUSB0" */
int rs232_oeffnen(fd, backup, rs232){
fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY); /* Schnittstelle oeffnen */
printf("Das Device wird geoeffnet\n");
/* Sicherheitsabfrage, ob Schnittstelle geoeffnet werden konnte */
if (fd == -1){
printf("rs232_oeffnen: Konnte /dev/ttyUSB0 nicht oeffnen\n");
return(-1);
}

/* Schnittstelle konfigurieren */
tcgetattr(fd, &backup); /* Aktuelle serielle Einstellungen sichern */
cfsetispeed(&rs232, BAUDRATE); /* eingehende Baudrate setzen */
cfsetospeed(&rs232, BAUDRATE); /* ausgehende Baudrate setzen */
rs232.c_cflag |= (CLOCAL | CREAD);
return (fd);
}

/* Schliessen der virtuellen seriellen Schnittstelle "/dev/ttyUSB0" */
int rs232_schliessen(fd){
close(fd);
printf("Das Device wurde geschlossen\n");
}


Gruß

rockin_santa

izaseba
14.05.2008, 16:09
Hallo


int rs232_oeffnen(fd, backup, rs232){


Was fällt hier auf ?

und warum dann so aufrufen ?


fd = rs232_oeffnen();

Gruß Sebastian

rockin_santa
14.05.2008, 19:38
Hmm,...
Natürlich ist die Struktur nur in der Funktion nötig, in der konfiguriert wird. Macht Sinn, die dann auch nur dort zu definieren, wie es ja in Deinem Beispiel schön zu sehen ist. Dann muss ich sie auch nicht als Argument übergeben..
Und selbst wenn, dann müßte die Funktion so beginnen:


int rs232_oeffnen(int *fd, struct termios *backup, struct termios *rs232)
{
[...]
}

und der Aufruf:


rs232(&fd, &backup, &rs232)
{
[...]
}

Dann müßte es passen, oder?
Ich werde die Struktur aber lokal definieren, macht mehr Sinn.

Vielen Dank,

rockin_santa

izaseba
14.05.2008, 20:04
Ich werde die Struktur aber lokal definieren, macht mehr Sinn.

Nun ja, wie Du das machst, ist ganz alleine Deine Sache, ich habe Dir ein Beispiel gepostet, womit ich klar komme ;-)

Zwei Anmerkungen,

1.wenn Deine Funktion rs232_oeffnen einen Filedeskriptor zurückliefert, brauchst Du wohl auch keinen der Funktion als Argument übergeben, oder ?

2. Wenn Du Deiner Funktion einen Zeiger auf eine struct gibst, muß der Zugriff auf die Member mit -> erfolgen, und nicht mit .

Am sonsten wünsche ich Dir viel Spaß weiter mit der Linuxprogrammierung und berichte was draus geworden ist.

Gruß Sebastian

rockin_santa
16.05.2008, 17:54
So, besten Dank nochmal, ich habe es hingekriegt. Nun kriege ich fein die einzelnen Chars auf der Konsole angezeigt, die mein µC ausgibt :)

Gruß

rockin_santa

izaseba
17.05.2008, 20:02
Es freut mich zu hören, daß es geklappt hat, so schwer war das doch nicht , wobei ich sagen muß, als ich damals mein Programm geschrieben habe, hat es auch etwas gedauert.

Gruß Sebastian