Hallo zusammen!
Ich bin newbie in sachen Mikrocontroller...
Aktuell versuche ich die printf-Funktion in mein Programm einzubinden.
Ich verwende AVR Studio 4 und programmiere meinen ATMGEA328P über das
AVR Dragon Board.
Ich sitze jetzt schon seit einige Tagen dran und prinzipiell
funktioniert die printf-Funktion auch.
Bzw. ich verwende die fprintf-Funktion. Kann mir da einer den
Unterschied zur "normalen" printf sagen? Und sprintf?
fprintf(&mystdout, "Hello Wordl!\n");
Funktioniert und ich kann im Terminal auch "Hello World!" lesen.
Möchte ich jetzt aber eine Variable mit übergeben, erscheint einfach gar
nichts.
fprintf(&mystdout, "Variable: %d\n", x);
Nachfolgend mein kompletter Code:
#include <stdio.h>
#include <avr/io.h>
#include "uart.h"
int uart_putchar(char c, FILE *stream);
int uart_getchar(FILE *stream);
FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, uart_getchar,
_FDEV_SETUP_WRITE);
int uart_putchar(char c, FILE *stream){
if (c == '\n'){
uart_putchar('\r', stream);
}
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return(0);
}
int uart_getchar(FILE *stream){
return 0;
}
int main(void){
int x = 42;
USART_Init(MYUBRR);
stdout = &mystdout;
fprintf(&mystdout, "Hello World!\n");
fprintf(&mystdout, "Variable: %d\n", x);
while(1){}
}
Die Initialiserung der UART-Schnittstelle mache ich in der uart.h.
Kann mir da bitte jemand helfen?! Irgendwie steh ich da total auf dem
Schlauch und je mehr ich google und Foren les, umso mehr komm ich
durcheinander...
Achja, ich hab auch 2 libraries eingebunden (stand auch mal in irgend
einem Forum...):
libprintf_flt.a
libprintf_min.a
Danke schonmal im Vorraus!
Tino
Tino B. schrieb:> Bzw. ich verwende die fprintf-Funktion. Kann mir da einer den> Unterschied zur "normalen" printf sagen? Und sprintf?
fprintf schreibt in eine Datei, sprintf schreibt in einen String. Das
sollte aber auch in der Dokumentation stehen.
1
fprintf(&mystdout,"Variable: %d\n",x);
2
while(1){}
Normalerweise puffert fprintf die Ausgabe. Entweder machst Du explizit
ein flush(), oder Du schließt Du die Datei mit fclose() (was implizit
flush() aufruft).
Parker schrieb:> Normalerweise puffert fprintf die Ausgabe. Entweder machst Du explizit> ein flush(), oder Du schließt Du die Datei mit fclose() (was implizit> flush() aufruft).
Äh, fflush() natürlich.
Danke für deine Antwort!
Allerdings versteh ich nur Bahnhof...
fclose() oder fflush() wollen einen Parameter übergeben bekommen. Der
Parameter wäre ja die Datei, die durch fprintf() geöffnet wurde,
richtig?
Aber ich hab doch eigentlich keine Datei geöffnet...
Kann man die Funktion nicht "einfach" in z.B. sprintf() ändern?
Danke
Tino
Tino B. schrieb:> Allerdings versteh ich nur Bahnhof...
In C sind externe Geräte fast alle in Form von 'Dateien' verfügbar. Auch
dein Terminal ist aus Sicht des I/O Systems nur eine Datei.
> fclose() oder fflush() wollen einen Parameter übergeben bekommen. Der> Parameter wäre ja die Datei, die durch fprintf() geöffnet wurde,
fprintf öffnet keine Datei.
fprintf SCHREIBT auf eine Datei.
Aber die Datei muss vorher schon geöffnet worden sein.
> Aber ich hab doch eigentlich keine Datei geöffnet...
Doch, hast du. stdout ist auch nichts anderes als eine Datei.
> Kann man die Funktion nicht "einfach" in z.B. sprintf() ändern?
Kann man. Aber sprintf schreibt in einen String. Daher auch das s am
Anfang
fprintf schreibt auf eine Datei
printf schreibt immer auf stdout. stdout ist auch eine Datei
Aber printf weiß, dass stdout gemeint ist, so dass man
nicht immer fprintf mit stdout benutzen muss. printf ist
also mehr als eine Vereinfachung von fprintf im Zusammenhang
mit stdout zu sehen.
sprintf schreibt nicht in eine Datei, sondern in einen String
Auf einem µC ist das alles allerdings ein wenig vereinfacht. Der printf
Mechanismus existiert nur sehr rudimentär, da es ja kein Dateisystem im
eigentlichen Sinne gibt.
Damit man aber nicht allzuviel ändern muss, wenn man bestehende
Programme übernimmt, implementiert WinAVR einen printf Mechanismus, dem
man eine 'Datei' unterjubeln kann. Genau das hast du gemacht, indem du
hier
eine 'Datei' definiert hast, mit deinen eigenen Schreibe- und
Lesefunktionen für Einzelzeichen. Die Datei hast du im Prinzip geöffnet,
indem du dafür gesorgt hast, dass die uart_putchar auch arbeiten kann,
sprich: Indem du die UART eingerichtet hast.
Und als stdout hast du diesen ganzen Mechanismus den
Bibliotheksfunktionen untergejubelt, indem du dieses FILE als stdout
angemeldet hast
1
stdout=&mystdout;
Nachdem du das getan hast, kannst du ganz normal printf benutzen. printf
formatiert den auszugebenden Text und gibt ihn dann auf der 'Datei'
stdout aus, indem es Zeichen für Zeichen über deine uart_putchar
Funktion ausgibt.
Wenn du also keine besondere Veranlassung hast, dann benutze einfach
printf anstelle von fprintf.
Oder aber du benutzt gar nicht das I/O System, sondern schreibst dir
eine Stringausgabe für die UART, formatierst den Text mittels sprintf
(oder itoa, oder ...) und schickst den String selber auf die Reise
1
voiduart_puts(constchar*str)
2
{
3
while(*str!='\0')
4
uart_putchar(*s++,NULL);
5
}
6
7
intmain()
8
{
9
charBuffer[20];
10
inti=5;
11
12
....
13
14
sprintf(Buffer,"Wert: %d\n",i);
15
uart_puts(Buffer);
16
17
while(1){
18
}
19
}
geht auch und hat den Vorteil (wenn man auf sprintf verzichtet), dass
man den ganzen printf Unterbau nicht mit im Programm hat, wenn man ihn
sowieso nicht sinnvoll einsetzen kann.
sorry, für die blöde frage, aber ist es richtig das du der uart_putchar
*s++ übergibst? was soll da den hochgezählt werden? versteh ichs nur
nich, oder müsste es
1
uart_putchar(*str,NULL);
heißen?
Aber wenn ich es mit *str versuche, kommen bei mir im Terminal nur
endlos viele 1er an. Er scheint das Stringende \0 nie zu sehen...
Und wenn ich es versuche indem ich global die Variable
1
*s=0;
deklarier, um keine Fehlermeldung für *s++ zu bekommen, sehe ich im
Terminal auch einen endlos String, aber Hauptsächlich aus 0ern
bestehend. Zwischendurch kommen einige andere Zahlen, aber nie die 5,
die ja eigentlich zu erwarten gewesen wäre, da sie ja dem string mit
übergeben wurde....
Mache ich da irgendwas grundlegend Falsch, oder was ist da los?
Vielen vielen Dank für eure bisherigen und hoffentlich noch folgenden
Beträge! :)
Tino
Tino B. schrieb:> sorry, für die blöde frage, aber ist es richtig das du der uart_putchar> *s++ übergibst? was soll da den hochgezählt werden? versteh ichs nur> nich, oder müsste es uart_putchar( *str, NULL );> heißen?
Das ist schon so in Ordnung.
So wie es da steht, entspricht es:
1
...
2
voiduart_puts(constchar*str)
3
{
4
while(*str!='\0')
5
{
6
uart_putchar(*s,NULL);
7
s++;
8
}
9
}
10
...
Dadurch wird jeweils das folgende Zeichen ausgegeben, und nicht immer
dasselbe.
>> Aber wenn ich es mit *str versuche, kommen bei mir im Terminal nur> endlos viele 1er an. Er scheint das Stringende \0 nie zu sehen...
Weil er wegen des fehlenden ++ ja auch im String nie weiterkommt; siehe
oben.
>> Und wenn ich es versuche indem ich global die Variable*s = 0;> deklarier, um keine Fehlermeldung für *s++ zu bekommen, sehe ich im> Terminal auch einen endlos String, aber Hauptsächlich aus 0ern> bestehend. Zwischendurch kommen einige andere Zahlen, aber nie die 5,> die ja eigentlich zu erwarten gewesen wäre, da sie ja dem string mit> übergeben wurde....
Was hat der übergebene String mit einem globalen s zu tun?
>> Mache ich da irgendwas grundlegend Falsch, oder was ist da los?
Offenbar; ohne das ganze Programm kann man da aber wenig darüber
lästern.
Tip: C lässt sich an einem PC wesentlich frustärmer lernen als auf einem
MC. Es macht Sinn, erst C zu lernen und dann auf einen MC damit
loszugehen.
Daher auch die Deklaration von s. Und global, weil da macht man am
wenigsten falsch hab ich gelernt.
Ich müsste doch eigentlich den String weiterzählen. Also so:
1
uart_putchar(*str++,NULL);
und nicht *s++, oder?
Aber da kommt bei meinem Terminal nur eine 1 und eine 19 an...
Der gesamte Code siehe Anhang.
Tino
Karl Heinz, Karl Heinz, Du sollst doch keine undeklarierten Variablen
verwenden. :-)
@ Tino B.
Karl Heinz hat sich nur vertan.
So
1
uart_putchar(*str++,NULL);
ist es richtig, wenn der Parameter auch "str" heisst.
Das hier
>Aber da kommt bei meinem Terminal nur eine 1 und eine 19 an...
verstehe ich allerdings nicht. Du hast doch nur eine Ausgabe im
Programm. Also kommt entweder eine 1 oder eine 19 und nicht "und". Wie
meinst Du das genau?
Ich meine, das 2 Zeichen ankommen.
Dezimal 1 und dezimal 19.
Als ASCII-string natürlich nur symbole...
Edit:
Ok, das selbe Problem wie ursprünglich.
entferne ich die Variable aus dem String, also:
1
sprintf(Buffer,"Wert: X\n");
dann sehe ich im Terminal "Wert: X"
mit Variable funktioniert das aber irgendwie nicht...
>mit Variable funktioniert das aber irgendwie nicht...
Bloss das mit "irgendwie" keiner was anfangen kann um den Fehler zu
lokalisieren oder gar zu beheben.
Was soll das hier heissen?
>entferne ich die Variable aus dem String
In dem String ist keine Variable.
Das hier:
1
sprintf(Buffer,"Wert: X\n");
>dann sehe ich im Terminal "Wert: X"
ist jedenfalls kein Fehler sondern völlig richtig. Genau so steht es im
Code.
Ich habe den Verdacht, das Du keine Ahnung hast, was Du da eigentlich
tust. Probier nicht wild herum sondern gehe Schritt für Schritt vor.
Sonst bringst Du nicht nur Dich sondern auch uns durcheinander.
Poste am besten mal den Code und einen Screenshot der
Terminalprogrammes, wenn Du die 1 und die 19 bekommst. Das scheint mir
am nächsten an der Lösung zu sein.
Der selbe Code wie bereits oben angehängt.
Habe ich die Zeile (mit Variable)
1
sprintf(Buffer,"Wert: %d\n",i);
Dann bekomm ich nur 2 Zeichen übermittelt, siehe screenshot des
Terminals wo man sieht das nur 2 Zeichen ankommen. "mit_variable.jpg"
Compiliere ich den Code mit folgender Zeile (ohne das eine Variable mit
übergeben wird):
1
sprintf(Buffer,"Wert: X\n");
Dann sehe ich im Terminal "Wert: X". Siehe angehängten Screenshot
"ohne_variable.jpg"
So, ich hoffe ich habe mich jetzt klar ausgedrückt...
Sorry wenns etwas unübersichtlich geworden ist.
Tino
Das mit dem "Wert X" kannst Du beiseite lassen. Es ist korrekt und genau
die Ausgabe die man bei dem Code
1
sprintf(Buffer,"Wert: X\n");
auch erwartet. Hat gar keinen Zweck das zu probieren. Man kann daraus
nichts weiter ableiten.
>Der selbe Code wie bereits oben angehängt.
Das wollte ich eben nachprüfen. Zuletzt ging es nicht mehr um unklare
Ausdrucksweise sondern vielmehr darum, das Du die Ausgabe mit dem
Programm, das Du hier
Beitrag "Re: printf-Funktion geht nur ohne Variable." gepostet hast,
unmöglich erhalten kannst.
Was mir am Code auffällt im Vergleich zum Screenshot vom
Terminalprogramm ist, dass Du das Terminalprogramm auf ein Stopbit
eingestellt hast, aber den UART auf zwei
Das
1
sbi(UCSR0C,USBS0);
ist falsch.
Probiere es mal mit der richtigen Einstellung.
Überprüfe bitte nochmal Deinen Taktgeber. Benutzt Du ein STK500 oder
600? Oder was für eine Schaltung benutzt Du?
Rufus schrieb:
>Und jetzt noch bitte den exakten vollständigen Quellcode, den Du da>verwendet hast.
Das ist nämlich der Punkt. Ich möchte Dir nicht zu nahe treten, aber es
ist durchaus nicht unwahrscheinlich und tritt hier öfter auf, das
Anfänger sich irren, was den Code betrifft, den sie tatsächlich
verwenden. Und Du machst mir, nimms mir bitte nicht übel, den Eindruck
als könnte das der Fall sein. Compiliere den Code. Mach den Screenshot
und poste beides direkt danach hier ohne irgendwas zu verändern.
Ihr wolltet das ich meinen EXAKTEN Code poste. Und in diesem Code steht
momentan nunmal dieser "Wert: X" drin.
Ich wollte damit nur verdeutlichen das es definitiv an der Variable
hängt, da es ja schließlich richtig funktioniert wenn ich keine Variable
übergeb.
Ob ich im Terminal ein oder 2 Stop Bits verwende ändert nichts an der
Ausgabe.
Allenfalls kann man daraus ableiten, das der Takt wahrscheinlich stimmt.
Bleibt also noch abzuwarten, was die Korrektur der Anahl der Stop-Bits
bringt.
>Ihr wolltet das ich meinen EXAKTEN Code poste. Und in diesem Code steht>momentan nunmal dieser "Wert: X" drin.
Nein. Wir wollten den exakten Code haben wenn Du die 1 und die 19
erhälst. Poste genau diesen Code. Und bitte schrei uns nicht an.
>Ob ich im Terminal ein oder 2 Stop Bits verwende ändert nichts an der>Ausgabe.
Dann stimmt irgendwas Anderes nicht, was wir hier nicht erfassen.
Wenn Die Ausgabe des Strings "Wert: X" korrekt erfolgt, ob mit einem
oder zwei Stopbits, dann ist der Takt ok.
Es bleibt also nur die Möglichkeit das Du nicht den wahren Code postest
oder Dich irrst, wenn Du das Hex-File flashst.
Compilierst Du den immer wieder neu oder nimmst Du ein bestehendes
HEX-File. Am besten compiliere nochmal neu und versichere Dich das Du
wirklich das aktuelle HEX-File nimmst.
Ansonsten gebe ich jetzt auf.
OK, kommentiere ich die Zeile für die Stop Bits aus,
1
//sbi(UCSR0C,USBS0); // Stop Bit
bekomme ich immernoch keine vernünftige Anzeige, aber anstatt 1 und 19
bekomm ich 1 und 16. Siehe Screenshot.
Ich verwende das Arduino Board Duemilanove auf dem der ATMEGA328P sitzt.
Den Arduino Bootloader verwende ich nicht, stattdessen programmiere ich
ihn mit AVRStudio 4 über den AVR Dragon.
Ich compiliere jedes mal neu. Ich sehe ja auch eine Änderung wenn ich
den String an die printf-Funktion übergebe.
Die Anzeige mit 1 und 19 bekomme ich nur wenn ich dem String eine
Variable mit übergebe.
Übergebe ich dem String keine Variable, klappt alles einwandfrei...
>Übergebe ich dem String keine Variable, klappt alles einwandfrei...
Na und? Bis auf die Tatsache, das der Takt nicht völlig falsch sein
kann, sagt uns das nichts weiter.
Das ist auch das einzige was mir noch dazu einfällt. Das mit dem Takt
was nicht stimmt. Und so ganz sicher bin ich mir wegen des Codes immer
noch nicht.
Das Du da 1 und 19 oder 16 erhälst ist nach dem Code völlig
ausgeschlossen.
Aber wiegesagt. Ich verabschiede mich jetzt in den Feierabend.
Viel Erfolg noch.
Die Stopbits können nicht Ursache des Problems sein. Stopbits sind nur
erzwungene Pausen zwischen direkt nacheinander gesendeten Zeichen; wenn
das Terminalprogramm auf 1 Stopbit eingestellt ist, das Gegenüber aber
mit mehr als einem Stopbit sendet, dann ist das genausowenig ein Fehler,
als wenn zwischen zwei Zeichen eine Weile gewartet wird.
Zurück zum Programm:
Hier wird mit sprintf ein char-Array befüllt und dessen Inhalt nachher
mit uart_puts über die serielle Schnittstelle ausgegeben.
Das Array sollte mit 20 Zeichen ausreichend groß dimensioniert sein,
also kann (wenn denn der gepostete Quellcode dem verwendeten
entspricht), das sehr merkwürdige Problem nur an sprintf selbst
liegen, das hier fehlerhafte Dinge in das char-Array einträgt.
Das aber ist eine Standardlibraryfunktion, und daß die so grundlegend
fehlschlägt, ist mit Sicherheit nicht auf diese Funktion selbst
zurückzuführen.
Ist der Stack ausreichend dimensioniert? Sowohl Buffer als auch die an
sprintf übergebenen Argumente müssen auf den draufpassen.
Ansonsten ist das eine Situation, in der schon längst ein Debugger
hätte verwendet werden sollen. Einen Breakpoint auf die Zeile mit dem
sprintf gesetzt und nachgeschaut, was das Ding in Buffer
hineinschreibt.
Anders als bei den meisten AVR-Nutzern, die nur eine ISP-Schnittstelle
verwenden, ist hier ja sogar ein JTAG-Interface vorhanden, so daß dem
Programm "auf die Bits" gesehen werden kann.
Machen!
Lass diesen Palawatsch
> Achja, ich hab auch 2 libraries eingebunden (stand auch mal> in irgend einem Forum...):> libprintf_flt.a> libprintf_min.a
mal weg.
So wie du den gcc bekommen hast, kann er int ohne Probleme in einem
sprintf formatieren. Du brauchst dazu nichts umkonfigurieren.
(Mach ein neues Projekt auf, stell Prozessor und Taktrate ein und alles
andere lässt du auf default. Den Source Code kopierst du mittels
Copy&Paste in dieses neue Projekt)
Hallo zusammen,
leider bin ich erst heute dazu gekommen weiter zu probieren.
Erstmal vielen Dank an alle die mir geholfen haben und die Geduld hatten
mir zu helfen! :)
Also, es funktioniert!
Ich habe, so wie Karl Heinz in seinem letzten Beitrag geschrieben hat,
einfach ein neues Projekt erstellt, das alte Programm per Copy und Paste
eingefügt. Compiliert, übertragen, läuft.
Ich vermute auch, so wie Rufus, das die sprintf() Funktion etwas falsch
interpretiert hat. Wahrscheinlich wegen den Libraries die ich zuvor
eingebunden hatte...
Anbei habe ich nochmal meine 2 Dateien angehängt, so wie das Programm
aktuell bei mir funktioniert.
Nochmals Danke an alle!
Gruß Tino