je nach Variablenwert Endlosschleife bei ATMega32

Gast #761762
Lesenswert?

Hallo ich programmiere gerade eine Software für einen ATMega 32. Beim 
ersten Test lief alles Problemlos, jetzt habe ich jedoch eine Variable 
geändert und plötzlich stecke ich anscheinend in einer Endlosschleife.

Durch Debugausgaben auf ein Display konnte ich das Problem auf folgende 
Stelle eingrenzen.
1
volatile uint16_t puls;    // Pulsbreite des Hauptstroms
2
volatile uint64_t mittelwert;  // Variable für den Mittelwert
3
volatile uint8_t messwerte[960];  // Feld für Messwerte von A/D-Wandlung
4
uint16_t c;      // Zählvariable für FOR-Schleifen
5

6
puls=((zih*1000)/290);
7
for(c=0; c<puls; c++){  // Summe über "Pulsbreite" für ersten Messwert
8
    mittelwert+=messwerte[c];  // berechnen
9
}

In der Standardeinstellung hat zih einen Wert von 30 (puls=103)und alles 
läuft ohne Probleme, wenn ich diesen nun auf 40 oder mehr erhöhe bleibt 
das Programm in der FOR-Schleife hängen weil die Variable puls einen 
irrsinnig hohen Wert bekommt, anstatt 137.

Ich habe bisher schon mit verschiedenen anderen Datentypen rumprobiert 
aber das Problem bleibt nach wie vor. Vielleich stehe ich nur auf dem 
Schlauch und bin nach mehreren Stunden der Fehlersuche nur blind für 
meine eigenen Fehler geworden.

Falls also jemand einen Fehler im Code entdeckt oder eine Idee hat wie 
ich das Problem beheben könnte... ich bin für jede Hilfe dankbar.

Ach ja ich programmiere mit AVR-Studio und winavr 20070525,
Optimierung: -Os
Moderator Persönliche Seite #761777
Lesenswert?

Gallig wrote:

> puls=((zih*1000)/290);

> In der Standardeinstellung hat zih einen Wert von 30 (puls=103)und alles
> läuft ohne Probleme, wenn ich diesen nun auf 40 oder mehr erhöhe bleibt
> das Programm in der FOR-Schleife hängen weil die Variable puls einen
> irrsinnig hohen Wert bekommt, anstatt 137.

40 * 1000 = 40000

Beide Seiten haben den Typ `int', der kann nur maximal 32767 darstellen.
Das Ergebnis ist eine negative Zahl: -25536.  Diese wird jetzt durch
290 dividiert, das ergibt -88.  Anschließend erfolgt eine implizite
Typumwandlung auf uint16_t, da das der Zieltyp der Variablen puls ist.
Die Umwandlung von signed nach unsigned int bei gleicher Bitanzahl
ist dabei ein einfaches kopieren des Bitmusters, d. h. das Bitmuster
von -88 wird jetzt nur anders bewertet und heißt dann 65448.

Du musst dich also darum kümmern, dass der innere Multiplikationsterm
nicht überläuft.  Falls zih keine Werte größer 65 annehmen kann,
genügt es dafür bereits, den ganzen Ausdruck komplett in der uint16_t-
Domain zu berechnen:

puls = ((zih * 1000U) / 290U);
Gast #761778
Lesenswert?

Der Compiler rechnet alles als int, wenn nicht explizit anders 
vorgegeben.

Jetzt schau dir den Wertebereich von int an, dann kommst du auch darauf, 
was da passiert.

Wenn du aus 1000 1000UL machst, sollte es auch mit 40 funktionieren.

Oliver
Gast #761792
Lesenswert?

Vielen Dank für eure schnellen Antworten, jetzt habe sogar ich es 
kapiert ;)
Also werden konstanten generell als INT betrachtet, zufern sie in diesen 
Datentyp "rein passen"?
Richtet sich die Berechnung mit Variablen dann auch immer automatisch 
nach dem größten Datentyp im Term?
Gast #761805
Lesenswert?

Noch eine kurze Frage, der maximale Wert für zih wäre 300, d.H. ich 
bräuchte bei der Berechnung ein uint32_t wenn ich das soweit richtig 
verstehe. Wie wäre das das Postfix für diesen Datentyp? 1000ULL?
Gast #764326
Lesenswert?

Danke für die Hilfe. Das mit dem Kürzen ist auch ein guter Tip aber ich 
lasse es lieber so, denke dann ist der Code leichter zu verstehen da die 
Zeitvariable dort von ms in µs umgerechnet wird.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren