Hallo, WinAVR - 20050214 gcc - 3.4.5 avrlibc - 1.4.2 stdio.h ist included Beispiel aus AVR-gcc-Tutorial zum Senden von Zeichenketten Ich bekommen beim kompilieren das Warning: main.c:54: warning: passing arg 1 of `fdevopen' from incompatible pointer type die Zeile lautet fdevopen(uart_putc,NULL); Wenn ich - wie im Tutorial-Beispiel - eintrage: fdevopen(uart_putc,NULL,0); erhalte ich: main.c:54: warning: passing arg 1 of `fdevopen' from incompatible pointer type main.c:54: error: too many arguments to function `fdevopen' Was mache ich falsch bzw. wie mache ich es richtig? Die erste Variante funktioniert im übrigen... Gruß, Axel
In die Doku schauen.
Der Prototype von fdevopen sieht so aus:
FILE* fdevopen ( int(* put)(char),
int(* get)(void),
int opts __attribute__((unused))
)
Argument 1 sollte also sein:
Ein Pointer auf eine Funktion. Diese Funktion nimmt einen char
und liefert einen int zurueck.
Wie sieht Deine Funktion (aus dem Tutorial) aus:
int uart_putc(unsigned char c)
{
while(!(USR & (1 << UDRE))); /* warte, bis UDR bereit */
UDR = c; /* sende Zeichen */
return 0;
}
Nun. Die Funktion liefert einen int wie gefordert, nimmt
aber einen unsigned char und keinen char. Damit hat diese
Funktion eine andere Signatur als fdevopen sie haben moechte.
Karl Heinz, du hast den Prototypen von avr-libc <= 1.2.x gezeigt, Axel benutzt offensichtlich eine 1.4.x. Axel, das wichtigste hast du vergessen uns zu sagen: den Prototypen (oder die Implementierung) deines uart_putc(). Ich vermute mal, du hast den zweiten Parameter (FILE *) vergessen, der in der avr-libc 1.4 neu hinzugekommen ist. Guck mal ins stdiodemo. Der Sinn dieses Parameters ist, dass man mittels fdev_set_udata() an den Stream user data anhängen kann und innerhalb von uart_putc() mittels fdev_get_udata() über diese verfügen kann. Damit kann man einerseits Dinge wie einen Gerätestatus über mehrere Aufrufe pro Stream abspeichern, andererseits kann man ein und dieselbe backend-Funktion (also uart_putc() in deinem Falle) für mehr als ein Gerät (z. B. zwei verschiedene UARTs) benutzen, indem man sie anhand der user data unterscheidbar macht. Wenn du diese Funktionalität nicht brauchst, deklarierst du den zweiten Parameter einfach nur als Dummy, ohne ihn zu benutzen.
> Karl Heinz, du hast den Prototypen von avr-libc <= 1.2.x gezeigt, > Axel benutzt offensichtlich eine 1.4.x. Danke fuer den Hinweis.
Hm, ich bin wohl noch viel zu weit weg mit meinen Kenntnissen, um das so
richtig zu verstehen...
so sieht das bei mir aus (das sollte genau dem Beispiel aus dem
gcc-Tutorial entsprechen), damit erfolgt auch eine Ausgabe auf meinem
ATMega32, nur gibt es halt das entsprechende oben beschrieben
fdevopen-Warning:
void USART_Init( void )
{
UCSRB |= (1<<TXEN);//UART TX einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0);//Asynchron 8N1
UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
}
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */
UDR = c; /* sende Zeichen */
return 0;
}
void uart_puts (char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem
"String-Endezeichen" */
uart_putc(*s);
s++;
}
}
int main(void)
{
USART_Init();
fdevopen(uart_putc,NULL);
printf("%s: stdout erfolgreich auf UART umgeleitet\n",
_FUNCTION_);
sei();
return 0;
}
Was muss ich in die Klammern von fdevopen schreiben, damit kein warning
mehr kommt?
Gruß, Axel
OK. Du musst lernen wie man sowas loest.
Der Compiler meckert, weil der Prototyp von fdevopen
etwas andere Parameter vorschreibt also Du tatsaechlich
verwendet hast.
Das ist noch kein Beinbruch und das kriegt man raus indem
man ganz einfach mal einen Blick auf den Prototypen wirft.
Den wiederum sieht man entweder in der Doku, oder aber
was meist besser ist direkt im Code. Irgendwiw muss
der Compiler ja den Prototypen sehen und da Du ihn nicht
selbst geschrieben hast, kann er nur ueber ein #include
hineingekommen sein.
Also geht man mal alle #include durch und ueberlegt in welchen
dieser Files der Progtrammierer der Library sinnvollerweise
den Prototyp hineingegeben haben wird. Im vorliegenden Fall
ist 'stdio.h' ein heisser Kandidat.
Ich hab bei mir am Rechner eine etwas aeltere Version davon
(die findet sich bei mir unter c:\winavr\avr\includes) und bei
mir lautet der Prototyp
extern FILE *fdevopen(int (*__put)(char), int (*__get)(void),
int __opts);
Aber wie gesagt, ich hab eine etwas ältere Version. Deine
sieht anders aus, wie Jörg weiter oben schon ausgefuehrt hat.
Aus den Ausfuehrungen von Jörg schliesse ich folgendes:
* fdevopen uebergibt man ja 2 Funktionspointer
* diese Funktionspointer sind Zeiger auf Funktionen, die
jeweils aufgerufen werden, wenn ein Zeichen entweder ausgegeben
oder eingelesen werden soll.
* damit das aber funktioniert, muessen Deine Funktionen so aussehen
wie fdevopen sich das so vorstellt. Insbesondere muessen
die Argumente in Anzahl und Type uebereinstimmen.
* der erste Funktionszeiger im Aufruf von fdevopen ist ein Zeiger
auf die Ausgabefunktion. In meiner Version ist das eine Funktion
die einen char annimmt und einen int zurueckliefert. Jetzt hat Jörg
aber gesagt, dass er diese Funktion mit einem zusaetzlichen
Parameter, einem File-Pointer ausgestattet hat.
d.h. Der Protoyp von fdevopen wird wahrscheinlich so aussehen
(aber pruef das bitte nach!)
extern FILE *fdevopen(int (*__put)(char, FILE*),
int (*__get)(FILE*),
int __opts);
* Daraus folgt: damit Deine uart_putc Funktion dazu kompatibel
ist, muss sie daher der Signatur
int (*put)(char, FILE*)
genuegen.
int uart_putc( unsigned char c, FILE* dummy )
{
....
}
Dieser zusätzliche Parameter 'dummy' ist wohl der Stream, auf
dem die Ausgabe tatsaechlich erfolgen soll. Da Du weist, dass
die Ausgabe auf den UART gehen soll, ist sein Inhalt fuer Dich
wahrscheinlich uninteressant und daher hab ich das auch 'dummy'
genannt. Das muss aber nicht so sein. Warum soll eine einzige
uart_putc Funktion nicht die Ausgabe auf verschiedene Geräte
regeln können. Dann braucht man den zusätzlichen Parameter
um die unterschiedlichen Ausgabeanfoerderungen zum richtigen
Gerät zuordnen zu können.
Disclaimer: Wie bereits ausgefuehrt verwende ich noch eine ältere
Version der Library. Alles hier geschriebene hab ich aus Jörgs
Info von oben abgeleitet bzw. 'geraten'. Ich denke aber nicht,
daß ich alzuweit daneben liege. Alles beginnt damit, dass Du mal
den Prototypen von fdevopen() in stdio.h ueberpreufts, wie der
tatsächlich aussieht.
Uff, danke erstmal. ja, ich muss (und will) lernen, wie man sowas löst... Der Berg ist aber noch ganz schön hoch. Deine Mutmaßungen bzgl. fdevopen sind alle richtig; eigentlich hatte aber schon Dein erster Hinweis gereicht -> aus unsigned char musste char werden. -> Jedoch ist dann auch das Beispiel im avr-gcc-Tutorial falsch, dort steht 'int uart_putc(unsigned char c)... Jetzt läuft es zumindest 'warning'-frei durch; auf zum nächsten Schritt, die nächste Frage kommt bald. Gruß, Axel
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.