Forum: Mikrocontroller und Digitale Elektronik Atmel Studio 6.2 - sprintf() - Problem


von Pyromaniac (Gast)


Lesenswert?

Hallo Leute,

ich habe folgendes Problem und finde seit ca. 2 Tagen keine Lösung 
dafür:

Ich bin gerade dabei ein LCD (16x2 Zeichen) anzusteuern. Initialisieren 
funktioniert und auch das beschreiben mit einzelnen Zeichen, also etwas 
wie

  send_char('L');
  send_char('i');
  send_char('n');
  send_char('i');
  send_char('e');
  send_char(' ');
  send_char('1');

zeigt "Linie 1" auf dem Display. Da das etwas umständlich ist, will ich 
das am besten mit einem "buffer", sprintf() und send_string(buf); 
machen.

Allerdings bringt

  sprintf(buf, "Linie 2");
  send_string(buf);

nur mehrere komplett gefüllte Chars aufs Display, (also jeder Buchstabe 
ist 0xff anstelle der jeweilichen ASCII-Zeichen)

Auch

  strcpy(buf, "Linie 2\0");

bringt das gleiche Ergebnis, nur wenn ich den Buffer umständlich über

  buf[x++] = 'L';
  buf[x++] = 'i';
  buf[x++] = 'n';
  buf[x++] = 'i';
  buf[x++] = 'e';
  buf[x++] = ' ';
  buf[x++] = '2';
  buf[x++] = 0;

beschreibe funktioniert es.

Die ganzen Beiträge die ich finden konnte handelten immer von 
Float-Problemen und (s)printf, aber bei mir wird ja noch nicht mal 
einfacher Text angezeigt.

Meine Includes sind:

  #include <avr/io.h>
  #include <util/delay.h>
  #include <stdio.h>

µController: ATMega2560
Atmel Studio Version 6.2

Hat jemand eine Idee woran das liegen könnte?

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Mit den paar Fetzen kann man nicht viel anfangen. Poste den gesamten 
Code.

von Pyromaniac (Gast)


Angehängte Dateien:

Lesenswert?

Bitteschön :)

von Dirk B. (dirkb2)


Lesenswert?

Pyromaniac schrieb:
> strcpy(buf, "Linie 2\0");

string.h eingebunden?
Das \0 ist überflüssig, da der Compiler bei Stringliteralen automatisch 
ein '\0' anhängt.


Wie sieht es bei
1
char buf[32] = "Linie 2";
oder
1
send_string("Linie 2");
aus?

von Pyromaniac (Gast)


Lesenswert?

Dirk B. schrieb:
> string.h eingebunden?

Jep, als ich strcpy() zum Testen benutzt habe, danach habe ich es wieder 
gelöscht da ich strcpy ja eigentlich nicht benutzen will.

Dirk B. schrieb:
> Wie sieht es bei
1
 char buf[32] = "Linie 2";
> oder
1
 send_string("Linie 2");
> aus?

Beides führt zu dem immer selben Ergebnis wie auch schon bei sprintf().

von Karl H. (kbuchegg)


Lesenswert?

Was sind das
1
    while(1)
2
    {
3
    send_command(0b10000000);
4
...
5
    send_command(0b11000000);
6
....
für Kommandos? (Genau deswegen hasse ich so einen Binärscheiss. Man 
sieht einfach nicht auf Anhieb, was da passiert).

Hintergrund: je nachdem, was das für ein Kommando ist, kann die 
Ausführung auf dem LCD einige Zeit dauern. Wenn das Kommando zu lange 
dauert, könnte es eine 'Interferenz' mit der nachfolgenden Ausgabe per 
lcd_string geben.

Du könntest mal probieren, nur probehalber, hier
1
void enable_impuls()
2
{
3
  PORTK |= 0b00000100;
4
  _delay_us(30); 
5
  PORTK &= 0b11111011;
6
  _delay_us(30);
7
}
den 2-ten delay mal wesentlich höher zu setzen. Dann geht zwar die 
Ausgabe momentan erst mal langsamer, aber es ist unwahrscheinlich, dass 
es dann noch zu gegenseitigen Beeinflussungen kommt. Falls das der Fall 
sein sollte.

: Bearbeitet durch User
von Pyromaniac (Gast)


Angehängte Dateien:

Lesenswert?

Habe die Änderungen durchgeführt, also die delays von "µs" auf "ms" 
geändert. Man sieht nun den Aufbau auf dem Display, aber das Ergebnis 
ist leider noch das gleiche.

Die binär-Kommandos waren "erste Zeile" und "zweite Zeile". Wenn man das 
Datenblatt gerade nicht im Kopf hat ist es natürlich nicht eindeutig :) 
habe ich nun aber auch deutlicher gemacht im Quellcode.

von kast (Gast)


Lesenswert?

was passiert bei:

sprintf(buf, "Linie %d", 2);

von Stefan F. (Gast)


Lesenswert?

Komisch, ich sehe keine Grund, warum strcpy() und sprintf() nicht 
funktionieren.

Aber mir ist etwas anderes aufgefallen:

strcpy(buf, "Linie 2");

Diese Zweile belegt gleich dreifach Speicher:
- "Linie 2" steht im Programmspeicher.
- Der String wird automatisch vor main() ins RAM kopiert.
- Dein Code kopiert ihn nochmal, nämlich in den Buffer.

Alternative:

strcpy_P(buf,PSTR("Linie 2"));

So liegt der Quellstring nicht im RAM, sondern er wird direkt aus dem 
Programmspeicher gelesen.

von Pyromaniac (Gast)


Angehängte Dateien:

Lesenswert?

kast schrieb:
> was passiert bei:
>
> sprintf(buf, "Linie %d", 2);

Hi kast, das übliche, siehe Foto.

Stefan us schrieb:
> Komisch, ich sehe keine Grund, warum strcpy() und sprintf() nicht
> funktionieren.
>
> Aber mir ist etwas anderes aufgefallen:
>
> strcpy(buf, "Linie 2");
>
> Diese Zweile belegt gleich dreifach Speicher:
> - "Linie 2" steht im Programmspeicher.
> - Der String wird automatisch vor main() ins RAM kopiert.
> - Dein Code kopiert ihn nochmal, nämlich in den Buffer.
>
> Alternative:
>
> strcpy_P(buf,PSTR("Linie 2"));
>
> So liegt der Quellstring nicht im RAM, sondern er wird direkt aus dem
> Programmspeicher gelesen.

Damit erhalte ich dann folgende Fehler:

Error  2  ld returned 1 exit status  collect2.exe  0  0  16x2 LCD
Error  1  undefined reference to `PSTR'  E:\Ei...D\Debug\16x2 LCD.c  1 
1  16x2 LCD

von Pyromaniac (Gast)


Lesenswert?

@kast: Einen kleinen Unterschied gibt es doch. Wenn ich
1
sprintf(buf, "Linie 2");
 benutze, dann werden da zwei dieser Blöcke weniger dargestellt. 
Vielleicht ist das ein wichtiger Hinweis? Mir sagt es nichts, hätte 
gedacht dass es identisch sein sollte.

von OldMan (Gast)


Lesenswert?

Ich nehme eher an, dass es ein Problem in den Initialisierung des 
LCD-Displays ist und nicht ein Compilerproblem. Sonst würde
die Ausgabe "Line 1" nicht erscheinen.
Ich benutze die Lib von Fleury und da sehen die Commands für die zweite 
Zeile etwas anders aus.
Ich würde dort suchen und nicht beim Compiler.
1
#define LCD_START_LINE1  0x00     /**< DDRAM address of first char of line 1 */
2
#define LCD_START_LINE2  0x40     /**< DDRAM address of first char of line 2 */
3
#define LCD_START_LINE3  0x14     /**< DDRAM address of first char of line 3 */
4
#define LCD_START_LINE4  0x54     /**< DDRAM address of first char of line 4 */
5
6
7
    if ( pos < (LCD_START_LINE2) )
8
        addressCounter = LCD_START_LINE2;
9
    else
10
        addressCounter = LCD_START_LINE1;

von Pyromaniac (Gast)


Lesenswert?

Hm, das glaube ich eigentlich weniger. Wenn die Initialisierung 
fehlgeschlagen wäre, dann würde das Display weder Zeile 1, noch Zeile 2 
anzeigen.

Ich habe auch schon versucht die Zeilen zu tauschen, das Ergebnis ist 
das gleiche, nur eben mit vertauschten Zeilen.


1
#define LCD_START_LINE1  0x00     /**< DDRAM address of first char of line 1 */
2
#define LCD_START_LINE2  0x40     /**< DDRAM address of first char of line 2 */
3
#define LCD_START_LINE3  0x14     /**< DDRAM address of first char of line 3 */
4
#define LCD_START_LINE4  0x54     /**< DDRAM address of first char of line 4 */

Das ist soweit richtig, denn das sind ja die ADRESSEN. Um nun die 
Adresse zu ändern, muss das "command" (0x80) und die "adress" 
miteinander oder-verknüpft werden, was zu dem 0x80 (0x00 | 0x80) für 
Zeile 1 und 0xC0 (0x40 | 0x80) für Zeile 2 führt.

Mit dem Code hier
1
#define POSITION_ERSTE_ZEILE (0x80 | 0x00)
2
#define POSITION_ZWEITE_ZEILE (0x80 | 0x40)
funktioniert es genauso wie vorher auch

von Pyromaniac (Gast)


Lesenswert?

Ich habe jetzt das Display genommen und mit einem Breadboard an einen 
ATTiny26 gehängt. Der Code ist 1:1 identisch (in AVR natürlich auch auf 
ATTINY26 geändert), compiliert, hochgeladen: GEHT!

Also entweder hat der ATMEGA2560 einen schuss. Aber es ist eigentlich 
neu und das Display-Programm ist das erste das drauf geladen wurde.
Oder aber das Atmel Studio übersetzt den Quellcode nicht richtig?

Was meint ihr?

von Pyromaniac (Gast)


Lesenswert?

So, heute ein weiterer Test: Wenn ich den generierten string "buf" über 
die serielle Schnittstelle sende, dann kommt beim Empfänger ebenfalls 
nur müll raus. Es liegt also definitiv nicht am Display, sondern an 
etwas anderem. Ich vermute immernoch dass das Atmel Studio den Code 
falsch generiert/übersetzt. Wie könnte man das denn überprüfen?

von Pyromaniac (Gast)


Lesenswert?

Hi Leute,
ich habe mich gerade wieder dem Thema angenommen und bin immer noch 
davon überzeugt, dass AVR-Studio den Code falsch übersetzt (warum sonst 
sollte es beim Attiny26 problemlos funktioniert, aber beim ATMEGA2560 
weder über LCD noch Seriell?)

Hat keiner eine Idee wie ich den compilierten Code dahingehend 
überprüfen kann, dass man sagen kann, dass der ASM-Code für die 
"sprintf"-Funktion korrekt aus der C/C++-Funktion übersetzt wurde?

Oder hat sonst noch jemand eine Idee woran es liegen könnte? Ich bin für 
alles offen, mittlerweile auch für Voodoo-Zeugs ;-)

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Pyromaniac schrieb:
> Hat keiner eine Idee wie ich den compilierten Code dahingehend
> überprüfen kann, dass man sagen kann, dass der ASM-Code für die
> "sprintf"-Funktion korrekt aus der C/C++-Funktion übersetzt wurde?

sprintf() – wie auch die verwandte Prozedur printf() – braucht sehr viel 
Speicherplatz. Könnte mit vorstellen, dass es hier zu einem Überlauf des 
Stacks kommt – oder irgendwas Ähnliches. Kannst du den Speicherbereich 
für den Stack testweise vergrößern? Aber ok, ist nur eine vorsichtige 
Vermutung.

sprintf() würde ich ohne Not sowieso nicht verwenden, es frisst einfach 
zu viele Ressourcen. Klappt es mit einer selbstgeschriebenen Prozedur? 
Z.B. so:
1
void sendstr(const char sp) {
2
  while(*sp!=0) send_char(*sp++);
3
  }
4
5
...
6
7
sendstr("Linie 2");

von Pyromaniac (Gast)


Lesenswert?

Markus Weber schrieb:
> sprintf() – wie auch die verwandte Prozedur printf() – braucht sehr viel
> Speicherplatz. Könnte mit vorstellen, dass es hier zu einem Überlauf des
> Stacks kommt – oder irgendwas Ähnliches. Kannst du den Speicherbereich
> für den Stack testweise vergrößern? Aber ok, ist nur eine vorsichtige
> Vermutung.
>
> sprintf() würde ich ohne Not sowieso nicht verwenden, es frisst einfach
> zu viele Ressourcen. Klappt es mit einer selbstgeschriebenen Prozedur?
> Z.B. so:
>
1
void sendstr(const char* sp) {
2
while(*sp!=0) send_char(*sp++);
3
}
4
5
...
6
7
sendstr("Linie 2");
>

ich hab in deinem Code bei "const char sp" noch ein * eingefügt, dann 
wurde es compiliert, soweit ging es also schonmal. allerdings wird auch 
hierbei nichts vernünftiges angezeigt. vielleicht hast du recht und es 
liegt am stack, allerdings habe ich noch nie an den einstellungen 
rumgespielt. wo findet man denn die einstellungen für den stack?

von Stefan F. (Gast)


Lesenswert?

>> strcpy_P(buf,PSTR("Linie 2"));
> Damit erhalte ich dann folgende Fehler:
> undefined reference to `PSTR'

Hast du denn die include Datei avr/pgmspace.h eingebunden?
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

von Pyromaniac (Gast)


Lesenswert?

Stefan Us schrieb:
>>> strcpy_P(buf,PSTR("Linie 2"));
>> Damit erhalte ich dann folgende Fehler:
>> undefined reference to `PSTR'
>
> Hast du denn die include Datei avr/pgmspace.h eingebunden?
> http://www.nongnu.org/avr-libc/user-manual/group__...

Ja jetzt schon :) sorry, hatte das nicht weiter verfolgt. Das Ergebnis 
ist leider das gleiche wie bei den anderen.
Was mir auch noch gerade eingefallen ist: Was, wenn der Programmer das 
Problem ist? Ich benutzen den "khazama AVR Programmer" für meine 
"USBasp" Box. Ich werde gleich mal sehen ob ich mit einer anderen 
Software vielleicht andere Effekte oder gleich die Lösung des Problemes 
haben...

von Pyromaniac (Gast)


Lesenswert?

Also mit dem "extreme Burner - AVR" sieht es genauso aus :(

von Pyromaniac (Gast)


Lesenswert?

Hat keiner mehr eine Idee oder Vorschläge? Wie sieht es denn mit dem 
Stack aus? Lohnt es sich die Idee weiter zu verfolgen? Über Google habe 
ich leider nichts brauchbares gefunden :-\

von Stefan F. (Gast)


Lesenswert?

> Das Ergebnis ist leider das gleiche wie bei den anderen.

Das dachte mir schon. Es war nur ein Vorschlag, etwas RAM zu sparen. Zu 
deinem eigentlichen Problem fällt mir leider auch nichts mehr ein.

von Stefan E. (sternst)


Lesenswert?

Poste bitte mal die lss-Datei.

von Pyromaniac (Gast)


Angehängte Dateien:

Lesenswert?

Hey Stefan,
ich habe jetzt mal die "release"- und die "debug"-Versionen der 
lss-Dateien dran gehängt.
Ich hoffe du (oder ein anderer) wird daraus schlau. Ich wundere mich nur 
dass in der release-version von der lss-Datei kein "sprinft" auftaucht 
:-\

von Pyromaniac (Gast)


Lesenswert?

Hat keiner mehr eine Idee? Sehen die Dateien für die Profis "normal"/OK 
aus?

von Pyromaniac (Gast)


Lesenswert?

Ich habe es endlich geschafft! Durch diesen Eintrag bin ich drauf 
gekommen: 
http://www.avrfreaks.net/forum/solved-atmega2560-and-memory-using-setting-atmel-studio-6-graphic-displays-pcd8544-hd44780-etc

bei dem "H-Fuse" war bei mir der "boot reset vector" enabled. Nachdem 
ich diesen "disabled" habe, läuft es endlich so wie es soll.

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.