Tachchen ihr Dioden;)
Heut hab ich mal ein Prob, welches ich nun seit 24h nicht gelöst bekomm
und hoffe auf Eure Hilfe.
Zum System:
Atmega32
AVR STUDIO 4.13 SP1
F_CPU 8000000UL
Optimierung -01
Zum Prob:
Ich habe ein Menue, in dem ich eine einfache Zahl ( als volatile uint8_t
gespeichert ) inkrementieren lassen kann und sie über itoa aufs lcd
angezeigt wird. Alles funkt, wenn ich den Controller quasi beim Start (
vor der while(1) ) in dieses Menue gehen lass und dann den Wert per
Taste ändere. Rufe ich ein anderes ( z.B. das Hauptmenue ) erst auf und
"springe" dann in besagtes Menue, verursacht mir itoa nach genau neun
Tasterzyklen ein Reset und es wird auch keine Änderung der uint8-Zahl
angezeigt. Hier mal die Routine was abgespeckt fürs Menue:
ExIvOn ist volatile uint8_t und wird in get_ExIv_EEdata() mit dem eeprom
gefüllt. Eine Kontrolle des Integer brauch ich nicht, da die 255 und der
Überlauf gewollt wären.
void Menue_Ex_IV(void)
{
get_ExIv_EEdata();
STHM_yn = 0; //Auswahlschalter On/Off 0 = On
lcd_command(0x0C); //Cursor löschen
lcd_command(0x01); //Clear Display
lcd_pos(0,0);
lcd_text( (u8*) "Ex Interval:");
lcd_pos(1,9);
lcd_text( (u8*) "ON: ");
//Minuten
lcd_pos(1,13);
volatile char EXOnSekAsk[4];
itoa(ExIvOn,EXOnSekAsk,10);
lcd_text((u8*)EXOnSekAsk);
lcd_pos(1,15);
lcd_command(0x0F); //Cursor setzen
}
Hier mal der Code der Tasterroutine:
switch(STHM_yn){
default:
STHM_yn = 0;
break;
case 0:
ExIvOn++;
lcd_pos(1,13);
volatile char EXOnSekAsk[10];
itoa(ExIvOn,EXOnSekAsk,10);
lcd_text((u8*)EXOnSekAsk);
lcd_pos(1,15);
break;
case 1:
// kommt später
break;
}
Mein Prog verursacht keine Fehler oder Warnungen beim Compilieren.
Kommentiere ich itoa in der Tasterabfrage aus, zählt sie ExIvOn auch
hoch. MIT itoa wird ( sobald ich von wo anders aus das Menue aufruf )
nach 9 Zyklen ein Reset ausgelöst und itoa auch scheinbar garnicht
abgearbeitet. Optimierung -00 kann und will ich mir nicht leisten, weil
mein Prog sonst nicht inne Flash passt unds hilft auch nich ab. Wie im
QT zu sehen hab ich schon alles mögliche volatilisiert g aber hilft
nix:(
Bitte helft mir. Wie kann dieses Verhalten auftreten? Beim einen Mal
korrekt, beim anderen mal ERROR?
Matthias T. schrieb:> QT zu sehen hab ich schon alles mögliche volatilisiert
Alle Volatiles die ich oben sehe sind falsch. Versuch lieber zu
verstehen, was volatile genau macht, und setz es dann "richtig" ein.
Als zweite Stufe: Verstehen, warum volatile zwar hilft, aber eigentlich
doch nicht "Das Richtige"™ ist, und stattdessen mit Atomic_blocks und
Memory barriers arbeiten.
Zum Problem: Ich vermute einen Überlauf. Entweder der Stack ist zu
klein, oder der buffer "EXOnSekAsk[4];"
Schorsch schrieb:> klein, oder der buffer "EXOnSekAsk[4];"
Zur Erklärung: Du verwendest itoa, das ist für Signed Integers. d.H.
aus deinem uin8_t wird bei der Parameterübergabe ein (auch gerne
negativer) int.
und "-100\0" passt nicht mehr in die 4 Characters des Buffers.
Dank dir Schorsch!
Das Volatile versteh ich soweit ich auch die Controllerstruktur verstehe
( und das noch nicht so ganz! ) Allerdings vermutete ich eine
Rationalisierung des Optimierers und versuchte so den Compiler daran zu
hindern, Code anders zu interpretieren als ich es vorsah. Deshalb die
volatiles und es hat ja auch nix geändert.
Warum nur falsch gesetzt? daran hätte es doch liegen können, wenn der
Compiler die Variablen hätte erst im Zwischenspeicher abgelegt und so
der unkontrollierten Manipulation freigegeben. Wo hätten die volatiles
denn Sinn?
Das mit dem Stack werd ich gleich mal testen, obwohl ExIvOn nie >255 und
kleiner als 0 sein kann ( uint8 halt ) und daher EXOnSekAsk[4] auch nur
zum einen positiv und zum anderen nicht überlaufen sein kann.
leider versteh ich von Atomic_blocks und
Memory barriers noch nix. wenn es aber dem Prob dienlich ist werd ich
mich daran setzen. Mein Verständnis kommt aus der PC-Programmierung und
tut sich daher bissi was schwer mit SRAM Register, Flag und dergleichen.
Man lernt!
das mit itoa und unsigned ist mir schon klar, nur w.o. beschrieben kann
der Wert von EXOnSekAsk nicht außerhalb 0-255 liegen...meines Wissens!
aber daaaanke erstmal ich bin hier am zweifeln:(
>> Bitte helft mir.
1. raus mit dem volatile.
Ist nur wichtig, wenn du nicht direkt drauf zugreifst bzw. der Compiler
die Verwendung nicht erahnen kann.
2. keine Magic Numbers. Gewöhn dir mal
1
#define TEXTLEN 10
en.
3. ein array ist 4, eins 10 gross. Hmm??
Mach ein globales
1
chartext[10];
und fertich. Ist auch besser, und du sparst sogar 4 (nein, 10) Bytes
RAM.
Ausserdem:
klasse - danke! hab ich geändert. nur leider der Fehler bleibt:(
Die "Magic Number" ist "Schnicklschmack" und kann ich später sicher
anpassen. Ich versteh ja, das es ins Dec wandelt.
Und wie bitte soll ich ohne itoa arbeiten? zumal es beim direkten
ansteuern ( noch vor der while(1) ) funkt?!
übrigens...das itoa wird abgearbeitet (laut neuester Tests;). Nur
verursacht genau das den Absturz?!
verbeug
Matthias T. schrieb:> übrigens...das itoa wird abgearbeitet (laut neuester Tests;).
Du hast gelesen, was ich dir oben geschrieben hab?
itoa ist FALSCH. Du brauchst utoa. Das ist nämlich extra für
Unsigned Variablen gedacht, wie es dein uint8_t ist.
es gibt mir den wert ( ASCII ) aufs DISPLAY und zeigt mir eigene Zeichen
aus meiner ASCII-Tabelle an, die den Werten 0x00-0x09 entsprechen.
Danach - also nach 9 inkrements resetet er.
Über lcd_text ist aber gewährleistet, dass der String auch terminiert
sein muss. Sonst käme ja der ganze Speicher aufs Display.
So - gelöst ******breitgrins**********
hab die char EXOnSekAsk[4]; laut thorstendb mal global gemacht und alles
funzt. Sparen kann ich daran allerdings nicht. die Variante lokal hat
die Vars ja nach beenden immer wieder aufgelöst und nun nich mehr.
Warum nun der Fehler behoben ist...ich würde es Euch gern sagen; Aber
weiss es auch nicht.
Danke aller Hilfe eurerseits!
Matthias T. schrieb:> So - gelöst ******breitgrins**********>> hab die char EXOnSekAsk[4]; laut thorstendb mal global gemacht und alles> funzt.
Sieht nur so aus.
Du hast das eigentliche Problem höchst wahrscheinlich nicht behoben,
sondern nur an eine andere Stelle verfrachtet.
> Sparen kann ich daran allerdings nicht. die Variante lokal hat> die Vars ja nach beenden immer wieder aufgelöst und nun nich mehr.>> Warum nun der Fehler behoben ist...ich würde es Euch gern sagen; Aber> weiss es auch nicht.
Und genau ds ist das bedenkliche an der Situation.
Wieviel Platz hast du am Stack noch frei? geht sich das genau um das
Byte nicht mehr aus, wenn das "innere" utoa ein char mehr schreiben muss
("9" => "10")
MAch mal ein paar bytes mehr platz im Ram, z.B. duch kürzen des Strings
1
lcd_text((u8*)"Ex Interval:");
in
"ExI" o.Ä.
Saubere Lösung: pgmspace.h, PSTR, lcd_text_P.
Schorsch schrieb:> Wieviel Platz hast du am Stack noch frei? geht sich das genau um das> Byte nicht mehr aus, wenn das "innere" utoa ein char mehr schreiben muss> ("9" => "10")>> MAch mal ein paar bytes mehr platz im Ram, z.B. duch kürzen des Strings>
1
>lcd_text((u8*)"Ex Interval:");
2
>
> in> "ExI" o.Ä.>> Saubere Lösung: pgmspace.h, PSTR, lcd_text_P.
genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash.
Dann ggf. den Pointer drauf holen und weiterverwenden:
char *pText = ....
Strings sind - wie mein Vorredner schon sagte - immer (char *).
VG,
/th.
AVR Memory Usage
----------------
Device: atmega32
Program: 14596 bytes (44.5% Full)
(.text + .data + .bootloader)
Data: 435 bytes (21.2% Full)
(.data + .bss + .noinit)
EEPROM: 16 bytes (1.6% Full)
(.eeprom)
Mit - im Stack platz machen - kenne ich mich noch nicht aus. Was es ist
und wie er funkt weiß ich heilwegs. Aber wie lese ich den Stand des
Stack zur Runtime aus?
Random ... schrieb:> Strings sind - wie mein Vorredner schon sagte - immer (char *).
ich verwende Peter F.s LCD-Routinen und ( ohne es zu ändern ) die
verlangen bei lcd_text ein u8 ??!
Matthias T. schrieb:> Data: 435 bytes (21.2% Full)> (.data + .bss + .noinit)
wenn da nicht exzessiv große Arrays am Stack allokiert werden, ist der
Speicher kein Problem
Random ... schrieb:> genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash.> Dann ggf. den Pointer drauf holen und weiterverwenden:> char *pText = ....
joi - da bin ich an nen Fachmann geraten ;) Keeeeine Ahnung im Mom wovon
du sprichst. Aber ich verfolge es weiter!
Matthias T. schrieb:> Random ... schrieb:>> Strings sind - wie mein Vorredner schon sagte - immer (char *).>> ich verwende Peter F.s LCD-Routinen und ( ohne es zu ändern ) die> verlangen bei lcd_text ein u8 ??!
Das kann ich mir nicht wirklich vorstellen.
Schon alleine deswegen, weil die entsprechende Routine beim Peter Fleury
Matthias T. schrieb:> global:> uint8_t ExIvOff;> utoa(ExIvOn,EXOnSekAsk,10);> ist natürlich nur der heilwegs relevante Text!
Glaub ich nicht. Die Variablen heißen ganz anders.
Poste ALLES
Dein Code ist ein einziger Saustall!
> Die "Magic Number" ist "Schnicklschmack" und kann ich später> sicher anpassen.
Das sagen sie immer. Hinten nach, hinten nach
Nur eigenartigerweise sind es immer genau die Progammierer mit dem
scheuslichsten Code, die die meisten Fehler haben.
Matthias T. schrieb:> global:> uint8_t ExIvOff;> unsigned char EXOnSekAsk[4];
Bei derartigen Arrays definiert man die Länge nie auf 'passt genau',
sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler
nicht gleich in Desaster auswirken.
Matthias T. schrieb:> ah - ok! das kann ich berücksichtigen. Danke!>> geb ich da besser mehr Bytes ( also zb [10]) oder gleich []?
Du brauchst ein C-Buch
Wie willst du denn ein Array mit[] definieren?
In C muss alles eine definierte Größe haben. Von alleine wächst da gar
nichts.
Karl heinz Buchegger schrieb:> Du brauchst ein C-Buch>> Wie willst du denn ein Array mit[] definieren?> In C muss alles eine definierte Größe haben. Von alleine wächst da gar> nichts.
"Jetzt lerne ich C" S.210 Z.007 ( mit 1 beginnend ) ISBN 3-8272-5361-6
Verlag Markt&Technik. Zugegeben etwas älter und ob es auf µC funkt weiß
ich auch nicht.
Matthias T. schrieb:> Karl heinz Buchegger schrieb:>> Du brauchst ein C-Buch>>>> Wie willst du denn ein Array mit[] definieren?>> In C muss alles eine definierte Größe haben. Von alleine wächst da gar>> nichts.>> "Jetzt lerne ich C" S.210 Z.007 ( mit 1 beginnend ) ISBN 3-8272-5361-6> Verlag Markt&Technik. Zugegeben etwas älter und ob es auf µC funkt weiß> ich auch nicht.
OK. Jetzt musst du es nur noch durcharbeiten :-)
ich will ja hier kein konfrogespräch entfachen und mein text ist (
erstrecht ) insgesamt sicher lausig. Es gibt VIELES was ich noch nicht
weiß und sich als Fehler herausstellen wird. Aber hast du auch vor 15
Monaten begonnen und weißt jetzt alles? Mir geht es um lernen und das
geht nur nach und nach.
Meines Wissens hast Du Karl Heinz mir vor nem halben Jahr schonmal mit
meinem LCD geholfen und ich bin dir sehr dankbar, denn auch da hab ich
ja viel gelernt. Hier soll es genau so sein. C hab ich gelesen ( auch in
Ruhe ) Aber die Praxis muss noch wachsen. Hinzu kommen ja die ganzen
Controllerarchitekturen, Datenblätter u.u. Muss ich auch alles lernen
nach und nach.
bitte immer sachlich bleiben:)
Matthias T. schrieb:> Random ... schrieb:>> genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash.>> Dann ggf. den Pointer drauf holen und weiterverwenden:>> char *pText = ....>> joi - da bin ich an nen Fachmann geraten ;) Keeeeine Ahnung im Mom wovon> du sprichst. Aber ich verfolge es weiter!
Naja, genau das, was da steht.
Der AVR ist ein Harvard-Modell, d.h. er hat getrennte Busse für Befehle
(Flash) und Daten (SRAM).
Konstante Strings kann man aus Platzgründen am besten im Flash ablegen.
Wenn man auf diese Strings zugreifen muss, holt man sich die in einen
char pointer, und übergibt diesen an print....(was auch immer). Dazu
braucht man bestimmte Funktionen, die den Zugriff auf den Flash
umlenken.
ARMs / Cortex Prozessoren z.B. basieren ebenfalls auf einem
Harvard-Modell, aber da bei 32Bit (4Gig) mehr als genug Adressen da
sind, ist der Flash mit in den Datenbereich gemapped, kurzum: der ganze
Adressraum ist linearisiert ('Von Neumann' Programmiermodell). Dort
braucht man diese Konstrukte nicht.
Der AVR ist aber nur 8Bit (16Bit Adressen?), und daher muss man diese
Klimmzüge machen.
Hoffe, ich hab mich jetzt nirgendwo auf die Schnelle vertan :-)
Weiterhin:
Strings sind stets mit '\0' (DEC 0) terminiert, das kennzeichnet das
Stringende. Bedeutet, dass in 'char text[10]' neun Zeichen plus '\0'
passen, mit dem Index von [0...9].
Die Array-Klammern ohne Grössenangabe kann man zum Init eines Strings
verwenden, z.B.
char text[] = "Hallo, Welt"
oder besser:
char *text = "Hallo, Welt"
Dabei wird Speicher für den String angelegt, und die Adresse des Strings
im pointer 'text' gespeichert.
Will man (unsauber) diesen Text ändern, braucht man die Länge.
VG,
/th.
Karl heinz Buchegger schrieb:> Bei derartigen Arrays definiert man die Länge nie auf 'passt genau',> sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler> nicht gleich in Desaster auswirken.
Das ist Unsinn.
Besser ist immer, man weiß, was man tut.
Und wenn ich weiß, daß ich max 30 Byte benötige, dann nehme ich auch
genau 30. Mehr bringt nämlich genau 0,nix.
Hier mal ein Beispiel für einen Puffer für eine 32Bit-Zahl:
1
staticuint8_tbuff[sizeof("-2147483648")];// maximum number length
Peter Dannegger schrieb:> Karl heinz Buchegger schrieb:>> Bei derartigen Arrays definiert man die Länge nie auf 'passt genau',>> sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler>> nicht gleich in Desaster auswirken.>> Das ist Unsinn.
Ja.
Bis dann in 3 Monaten man auf die Idee kommt, dass man da noch einen
kleinen Text davor haben will.
Alles schon gesehen, alles schon gehabt, schon öfter drauf reingefallen.
> Besser ist immer, man weiß, was man tut.
Als ob Neulinge das im Regelfall tun.
> Und wenn ich weiß, daß ich max 30 Byte benötige, dann nehme ich auch> genau 30. Mehr bringt nämlich genau 0,nix.
Wenn ich einen globalen Buffer zur Textwandlung habe, dann mach ich den
nicht auf Knirsch, denn irgendwann in nächster Zeit fällt man nämlich
drauf rein, dass 3 Zeichen bei einer int-Wandlung zu wenig ist. Und sei
es nur, weil die Zahl aus irgendeinem Grund tatsächlich mal größer als
255 wird.
Ist auch im Regelfall völlig wurscht, wenn ich dem noch 7 Bytes
dazuspendiere. Das kostet nichts. 2 Stunden Fehlersuche wegen so einem
Blödsinn hingegen kosten Geld.
Nennt sich defensives Programmierern.
Karl heinz Buchegger schrieb:> Wenn ich einen globalen Buffer zur Textwandlung habe, dann mach ich den> nicht auf Knirsch, denn irgendwann in nächster Zeit fällt man nämlich> drauf rein, dass 3 Zeichen bei einer int-Wandlung zu wenig ist.
Ist es ja auch. Du brauchst für 16Bit genau:
1
staticuint8_tbuff[sizeof("-32768")];// maximum number length