Forum: Compiler & IDEs Programm bleibt bei for schleife hängen


von Manax (Gast)


Lesenswert?

Hallo Leutz mit folgendem kleinen Codesnippet habe ich so meine 
Probleme. Bei der Simulation bleibt die Schleife hängen. Wenn ich nur 
mit j!=54 arbeite läuft das Programm in 1400µs durch. Wenn ich das 
komplette Array nehme dann läuft das Programm 7000µs und startet dann 
einfach neu ( anfang int main). Im array keine besondere stelle Wert 
Umlaufdauer[55] ist 2308. der Wert für für zzp[0-80] ist immer gleich 0.

int zzp_init()
{
for(uint8_t j=0;j!=80;j++)
  {
  zms[j] =(loadtime +(umlaufdauer[j]/360)*((vorzuendung+zzp[j])/5));
  }
return 0;
}

Warum schmiert mir die schleife ab ?
Watchdog ist nicht aktiv.

mfg Jan

von Mark B. (markbrandis)


Lesenswert?

j!=80;

Soll das nicht normalerweise j <= 80 heißen?

von Mark B. (markbrandis)


Lesenswert?

Nee, geht auch so... und wenn schon, dann j < 80 :-)

Manax schrieb:
> der Wert für für zzp[0-80] ist immer gleich 0.

Warum addierst Du ihn dann? ;-)

zzp[0-80] würde ja bedeuten, dass das Array 81 Werte hat... aber Du 
hörst ja bei 79 auf, da kann also nix überschrieben werden. Es sei denn 
vielleicht zms[] oder umlaufdauer[] wären kleiner.

von Jan (Gast)


Lesenswert?

Naja die Werte kann ich dann später noch eintragen die werte für zzp.
Kann das ein Problem mit vollem speicher sein der AVR attestierte mir 
137,5% ROM frei. Und im Prinzp wollte ich auch nur umgehen, dass ich den 
Wert im Programm ausrechne. Die Berechnung dauert leider 50µs im 
Programm gibt es irgendeine Möglichkeit
coilstatus_on = allticks - (loadtime 
+(allticks/360)*((vorzuendung+zzp[i])/5));
Diese Rechnung schneller zu meistern ?


mfg Jan

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Naja die Werte kann ich dann später noch eintragen die werte für zzp.
> Kann das ein Problem mit vollem speicher sein der AVR attestierte mir
> 137,5% ROM frei.

lol
137% vom ROM können nicht frei sein.
Entweder es ist komplett frei, dann ist es zu 100% frei.
Oder es ist komplett belegt, dann ist es zu 100% belegt.

Oder aber dein Programm ist so gross, dass es nicht mehr ins ROM passt. 
Dann belegt es 137% vom ROM (was aber nicht geht, denn bei 100% ist 
Schluss. Mehr passt nicht rein).

von Manax (Gast)


Lesenswert?

Es war mir schon klar das net durch mein Programm zusätzlich 37,5 % frei 
geworden sind .....
Habs vielleicht etwas schlecht formuliert

von Manax (Gast)


Lesenswert?

Fakt ist ja nur, dass das Programm im Simulator trotzdem läuft ich kann 
mir nur leider nicht erklären warum die Schleife immer abschmiert

von Klaus W. (mfgkw)


Lesenswert?

Nein.

Fakt ist, daß du hier nur Fragmente deines Programms zeigt,
eine grottige Beschreibung des Rests und des Verhalten
lieferst und ich nach mehrmaligem Durchlesen nicht weiß,
was hier passiert.

So wird das nichts.
Alles andere ist nicht Fakt sondern Spekulation.

Hilfreich wären:
- ganze Quelltexte
- ganze + verständliche Sätze
- korrekte Aussagen

von Manax (Gast)


Lesenswert?

Hallo Leutz

@ Klaus ich hab mir die komplette Seite nochmal durchgelesen und ich 
weiß beim besten Willen nicht wo ich so undeutlich formuliert haben 
soll, dass man es beim durchlesen nicht versteht.

int zzp_init()
{
for(uint8_t j=0;j!=80;j++)
  {
  zms[j] =(loadtime +(umlaufdauer[j]/360)*((vorzuendung+zzp[j])/5));
  }
return 0;
}

es geht um diesen bereich Bei dem LOADTIME um eine konstante mit dem 
Wert 1600.  Bei UMLAUFDAUER handelt es sich um ein Array mit 81 Werten 
im Bereich von 15000- 2000.  VORZUENDUNG ist ein konstanter Wert ( 
Range: 0-200).
ZZP ist ein Array mit 81 Werten passendend zur Umlaufdauer ( alle Werte 
im Moment 0 Werten ( zu testzwecken)).
Die erste Möglichkeit die ich gefunden habe wäre

  zms[j] =(loadtime +((umlaufdauer[j]*(vorzuendung+zzp[j])/1800));
Bringt aber leider keinen Erfolg die Schleife bleibt immer noch hängen.

Die Zweite Möglichkeit ist die Errechnung in Echtzeit.


for(uint8_t i=81,i!=0,i--)
{
if (umlaufdauer[i]>=allticks)
                            {
                            Errechnung des Zzps hier im laufenden 
Betrieb
                            test1=umlaufdauer[i] // testweise Ausgabe
                            break;
                            }
}
Wenn ich jetzt allerdings allticks = 15000 setze dann nimmt i den Wert 
33 an ( der nicht stimmt ) da das Array Umlaufdauer[i] an dieser Stelle 
den Wert 3000 hat und das ist ja net größer als 15000 und test1 nimmt 
komischerweise den Wert 15000 an obwohl das Array eigentlich als
const uint16_t Umlaufdauer[81] PROGMEM = {
..
3300 // 33igste Stelle.
..
};
Außerdem braucht der Programmteil mit der for-if Schleife ca 220µs bei 
20 Mhz. Sodass ich mir sicher bin, dass ich irgendeinen Fehler gemacht 
habe.
Nur wo liegt er?


p.s Ich würde auch den kompletten Source posten aber so ist es glaub ich 
einfacher, da ihr euch nicht erst komplett einarbeiten müsst ( ist recht 
lang ).


Bitte helft mir ^^ ich hab gar keinen Schimmer was ich da jetzt falsch 
mache.

mfg Jan

von ege (Gast)


Lesenswert?

du mußt doch die PROGMEM read funktionen benutzen wenn du einen array 
progmem definierst ich glaub pgm_read oder so müßte das gewesen sein.

von ege (Gast)


Lesenswert?

poste doch mal bitte deine variablen deklarationen

von Karl H. (kbuchegg)


Lesenswert?

Manax schrieb:

> p.s Ich würde auch den kompletten Source posten aber so ist es glaub ich
> einfacher, da ihr euch nicht erst komplett einarbeiten müsst ( ist recht
> lang ).

Das Problem ist, dass der Fehler oft nicht dort sitzt, wo du denkst dass 
er sitzt. Aus dem bisher geposteten kann man herzlich wenig sagen, 
ausser dass du auf PROGMEM Sachen so nicht zugreifen kannst. Aber das 
alleine ist kein Grund für eine 'hängende Schleife' (an die ich sowieso 
nicht glaube, da passiert mit Sicherheit irgendetwas anderes, du 
interpretierst nur die Symptome falsch)

von ege (Gast)


Lesenswert?

hier mal ein Beispiel wie du deinen array UMLAUFDAUER lesen mußt wenn du 
ihn mit Progmem im flash hast.

read_pgm_byte(&umlaufdauer[3])

probiere doch mal all deine werte auszugeben auf RS232 (falls vorhanden) 
dann siehst du ob deine zugriffe richtig sind oder du nur auf adressen 
zugreifst.

von g457 (Gast)


Lesenswert?

wie schon mehrfach vorgeschlagen: Zeig mal (den vollständigen) 
Quellcode, ohne geht nichts. Die pgm_read*() brauchts auf jeden Fall, 
das dürfte aber wie schon gesagt nicht zum Verrecken beitragen sondern 
nur zu falschen Berechnungen.

Zwei klitzekleine Vermutungen hab ich noch: Ist "zms" auch im PROGMEM 
(von hinten durch die Brust ins Auge funktioniert das (aber halt nicht 
richtig))? Oder: Geht Dir möglicherweise der Ram aus?

von Manax (Gast)


Lesenswert?

Ok jetzt hab ichs mal andersrum gemacht um dieses Problem zu lösen.

((calcticks>>10)-(calcticks>>11)) mit calcticks im bereich von 
1667-15000 leider kommt bei dieser Rechnung eine Zahl raus mit der ich 
mal so gar nichts anfangen kann. Denn bei dieser division 1/1024-1/2048 
kommt mit calcticks ein wert von ca 0,81... raus leider interpretiert 
das Programm das als 1.
Wie bekomme ich hier eine erhöhte Genauigkeit hin ( 3-4 Stellen nach dem 
Komma) und ohne in der Rechnung zu dividieren( dauert zu lange ) ohne 
den Speicher zu sprengen.

mfg Jan

von Mark B. (markbrandis)


Lesenswert?

Vielleicht kann Dir der Artikel Festkommaarithmetik weiterhelfen.

Und vielleicht möchtest Du - immer noch - Deinen Programmcode hier 
hochladen, so dass man Dir vernünftig helfen kann.

von Grrrr (Gast)


Lesenswert?

Manax schrieb:
> ((calcticks>>10)-(calcticks>>11))

Dieser Ausdruck lässt sich noch dramatisch vereinfachen, wenn man 
bedenkt, dass gilt: a-a/2 = a/2

von Manax (Gast)


Lesenswert?

a/2 = 1/2 = 0.5 das ist aber net der Wert den ich brauche.

von Karl H. (kbuchegg)


Lesenswert?

Manax schrieb:
> a/2 = 1/2 = 0.5 das ist aber net der Wert den ich brauche.

Mag sein.
Aber letztenedes ist das genau das was du berechnest

((calcticks>>10)-(calcticks>>11))

ist identisch zu

 (calcticks>>11)

egal, wie gut du das versteckst. Und das wiederrum ist identisch zu

  calcticks / 2048

(wenn calticks ein unsigned Wert ist). Und genau so (also mit Division) 
solltest du das auch schreiben und da nicht lange rumkünsteln. Dann 
sieht man nämlich was Sache ist. Wenn die Division durch Schieben 
ersetzbar ist, dann macht das der Compiler ohnehin.

von Manax (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang hab ich jetzt mal den Source hochgeladen.

Mit dem Beispiel aus der Festkommaritmetik dauert die Schleife wenn ich 
1667 als allticks nehme leider 129 µs schöner wären weniger, da es sich 
um eine zeitkritische Schleife handelt.

Ich habe schon das Teilen durch 1800 versucht ( 100µs ) .
Das verschieben ( Zahl wird zu klein und zu stark gerundet).

Könnt ihr mir weiterhelfen ?
Erreichen würde ich gerne einen Wert von ca 20-50 µs  .

mfg Jan

von Manax (Gast)


Lesenswert?

Als test für die Rechnung habe ich nur das letzte if im prog verändert ( 
das ist ja der Wert der maximalen Zeit ).


mfg Jan

von Karl H. (kbuchegg)


Lesenswert?

Puh.

Der Code ist .... nun ja ...

Wenn das beschleunigt werden soll, wäre es vielleicht gut, wenn du 
erzählen würdest, was das wird, was die Grundlagen dafür sind und welche 
Idee im Programm verfolgt wird.

von Manax (Gast)


Lesenswert?

Das Programm ist nun ja... weils mein erstes ist. Ich geb kurz die 
wesentliche Funktion wieder.

Timer triggert alle 4 µs und erhöht tick immer um 1. Wenn der externe 
Interrupt triggert wird hall auf 1 geschaltet und in der main schleife 
wird das programm checktick ausgeführt. Dieses prüft anhand einer 
Routine ob OT des Motors erreicht wurde und speichert die komplette Zeit 
der Umdrehung.
Wenn Ot des Motors erreicht wurde dann wird das Programm choosetable 
ausgeführt.
Dieses wählt anhand der kompletten Zeit der Umdrehung einen 
entsprechenden Zündzeitpunkt aus.
Das Problem ist nun meinen Wert vorzündung ( in Grad ) + den Wert 
Zündzeitpunkt (in Grad ) in µs umzurechnen.

Daher die Routine    ztimer= allticks -( loadtime + 
(allticks/(360*5))*(ZZp+Vorzündung)
Ztimer wird dann in der mainroutine geprüft und wenn er übereinstimmt 
dann wird die Zündspule geladen.  allticks sind die µs*4 der Umdrehung. 
loadtime ist die Ladezeit der Spule in µs/4    (allticks/360*5)  rechnet 
µs*4 / 0.2 Grad um und verrechnet es dann mit zzp und vorzündung.

Die If-Schleifen in choosetable brauchen alleine 30µs im schlechtesten 
Fall.
Leider finde ich keine bessere Möglichkeit das zu Verbessern, da hier ja 
immer allticks>= Wert geprüft werden muss.
Die anderen 70µs im schlechtesten Fall gehen für die Rechnung drauf. 
Daher hab ich es wie oben schon erwähnt noch nicht verbessern können.

Der Grund warum es möglichst schnell gehen soll ist, dass der Motor ja 
nur ca 13µs pro 1 Grad braucht bei ca 13000 Umdrehung. Das lässt sich 
natürlich über das Zündkennfeld verrechnen es wäre nur eleganter wenn es 
halt möglichst schnell geht.


mfg Jan

von Karl H. (kbuchegg)


Lesenswert?

Manax schrieb:

> Routine ob OT des Motors erreicht wurde und speichert die komplette Zeit
> der Umdrehung.
> Dieses wählt anhand der kompletten Zeit der Umdrehung einen
> entsprechenden Zündzeitpunkt aus.

OK.
Soweit ist das klar.
Du willst den Zündzeitpunkt an die gemessene Drehzahl anpassen.

> Das Problem ist nun meinen Wert vorzündung ( in Grad ) + den Wert
> Zündzeitpunkt (in Grad ) in µs umzurechnen.

Warum musst du das umrechnen?
Kannst du nicht einfach eine Tabelle nehmen, in der der Zündzeitpunkt in 
Abhängigkeit von diesem Winkel für, sagen wir alle 4 Grad (4 .. wegen 
2-er Potenz), abgelegt ist?
Dann brauchst du so gut wie gar nichts rechnen. Kostet ein wenig 
Speicher, aber was solls.

> Leider finde ich keine bessere Möglichkeit das zu Verbessern, da hier ja
> immer allticks>= Wert geprüft werden muss.

Ich hab das jetzt nicht kontrolliert ob das geht. Aber wenn du deine 
Abhängigkeit von der Drehzahl auf zb vielfache von 256 beschränken 
könntest, könnte man dann auch dort wieder eine einfache 
Tabellenindizierung machen.

> Der Grund warum es möglichst schnell gehen soll ist, dass der Motor ja
> nur ca 13µs pro 1 Grad braucht bei ca 13000 Umdrehung.

Seh ich ehrlich gesagt nicht ganz ein.
Der Motor ändert ja seine Drehzahl nicht wesentlich bei einer einzigen 
Umdrehung. Wenn also der veränderte Zündzeitpunkt eine Umdrehung zu spät 
kommt, ist das sicherlich auch kein Beinbruch. Vom Zeitpunkt des 
Feststellens des OT hast du eine komplette Motordrehung Zeit, den neuen 
Zündzeitpunkt auszurechnen und erst im nächsten OT aktivierst du ihn 
(und startest die Berechnung erneut mit dem dann gemessenen Wert für die 
nächste Umdrehung)

von Manax (Gast)


Lesenswert?

Uiui danke für die schnelle Antwort.

zu 2 )
Die Zeit die der Motor für ein Grad braucht ist ja abhängig von der 
Drehzahl.
Ich wüsste jetzt gerade net wie man da nen guten ZZP hinbekommt ohne das 
man ausrechnet wieviel µs dem gewollten zzp entsprechen.


zu 3)
könntest du das mit der Tabellenindizierung genauer erklären?

meinste sowas wie
for (uint8_t i=0, i<=Maximalwert, i+256) { mach was ? }

zu 4)

Gemeint ist den ZZp möglichst präzise zu errechnen. Wenn die Rechnung 
sehr lange dauert ist es schwieriger den ZZP zu treffen sagen wir von 
13° vor OT, 13µs zu spät würde bedeuten man zündet erst 12° vor OT.

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.