Nabend,
ich bin leider noch ziemlich unerfahren in der Mikrocontroller
Programmierung und habe gerade mit einem Problem zu kämpfen.
Warscheinlich ist es nur eine Kleinigkeit aber ich komm gerade einfach
nicht drauf.
1
if(flag.multiplex==1)
2
{
3
flag.multiplex=0;
4
result=ADC;
5
ADCSRA|=(1<<ADSC);
6
7
set_display_number(result*176/1024);
8
set_dot(zehn);
9
}
Um diesen Codeausschnitt handelt es sich, wobei result als uint32_t
deklariert wurde. Der angezeigte Wert ist im Prinzip auch korrekt,
ausser bei ganzen Zahlen: Wenn z.B. 10.0 angezeigt werden müsste wird
komischerweise 00.0 angezeigt und bei 12.0 wird 11.0 angezeigt.
An der set_display_number() Methode liegt es nicht, denn wenn ich dieser
die Werte direkt übergebe werden sie richtig angezeigt.
Über einen kleinen Denkanstoß würde ich mich sehr freuen!
Gruß,
Philipp
Philipp schrieb:> set_display_number(result*176/1024);
Ich vermute du wirst an der Stelle einen Overflow haben, d.h. result*176
wird größer als es uint32_t zulässt. Übrigens würde ich mir an der
Stelle die Division sparen und einfach
> result * 0.17185
rechnen.
Hallo,
leider funktioniert es damit auch nicht. Der Fehler bleibt bestehen.
Die 176 kommen übrigends dadurch zustande, dass die Referenzspannung
1,1V beträgt und die zu messende Spannung per Spannungsteiler durch 16
geteilt wird. Dann noch ein Faktor 100 um aus den 1/000V wieder meine
1/10V zu machen.
Also quasi: set_display_number(result*1100*16*100/1024)
Liegt der Fehler vielleicht dort?
@ Daniel H. (Firma: keine) (commander)
>> set_display_number(result*176/1024);>Ich vermute du wirst an der Stelle einen Overflow haben, d.h. result*176>wird größer als es uint32_t zulässt.
Kaum, denn result als ADC ergebniss ist max. 10 Bit, mal 176 (8 Bit
macht) maximal 18 Bit. Ok, result ist wahrscheinlich 16 Bit, dann wird
es ein Overflow. Also eher so.
1
set_display_number(result*176L/1024);
> Übrigens würde ich mir an der>Stelle die Division sparen und einfach>> result * 0.17185>rechnen.
Dann wäre der Sinn von Festkommaarithmetik verfehlt.
Falk Brunner schrieb:>> Übrigens würde ich mir an der>>Stelle die Division sparen und einfach>>>> result * 0.17185>>>rechnen.>> Dann wäre der Sinn von Festkommaarithmetik verfehlt.
Jo, Vorsicht. Eine einzige float in so einer Berechnung zieht die math
library rein und bläht den Code so richtig auf. Am besten immer ein Auge
auf die Codegrösse beim Compilieren werfen, damit das nicht passiert.
Philipp schrieb:> Die 176 kommen übrigends dadurch zustande, dass die Referenzspannung> 1,1V beträgt und die zu messende Spannung per Spannungsteiler durch 16> geteilt wird.
Das klingt übrigens so, als würdest du freiwillig eine Menge Auflösung
verschenken. Absicht?
Wie sieht den der Funktionsprototyp von set_display_number() aus? Hat
der auch uint32 oder nur uint16? Wenn uint16, dann versuche mal einen
Type-Cast mit
1
set_display_number((uint16t)((result*11)/64));
Die Klammern habe ich gesetzt, damit der Compiler auch sicher nicht
zuerst 11/16 rechnen will. Dabei kommt nämlich 1 raus...
tschuessle
Bernhard
Bernhard Spitzer schrieb:> damit der Compiler auch sicher nicht zuerst 11/16 rechnen will.
Will er sicher nicht, denn da steht 64...
> zuerst 11/16 rechnen will. Dabei kommt nämlich 1 raus...
Bei mir kommt mit 11/16 nur 0 raus...
Man könnte da mal eine Zwischenvariable einführen, und die genauer
anschauen. So würde ich das machen...
Philipp schrieb:> Wenn z.B. 10.0 angezeigt werden müsste wird> komischerweise 00.0 angezeigt und bei 12.0 wird 11.0 angezeigt.
Evtl. passt da auch einfach was mit dem Multiplexen nicht zusammen, und
es wird die falsche Ziffer an der falschen Stelle angezeigt...
Bernhard Spitzer schrieb:> Wie sieht den der Funktionsprototyp von set_display_number() aus? Hat> der auch uint32 oder nur uint16? Wenn uint16, dann versuche mal einen> Type-Cast mit>
1
set_display_number((uint16t)((result*11)/64));
> Die Klammern habe ich gesetzt, damit der Compiler auch sicher nicht> zuerst 11/16 rechnen will.
Das darf er sowieso nicht.
Neben Precedence gibt es ja auch noch die Assoziativität, die das klar
regelt.
Philipp schrieb:> Um diesen Codeausschnitt handelt es sich
Das ist ungefähr so, als würde von Dir jemand verlangen, ein Buch durchs
Schlüsselloch zu lesen.
Code-Pfitzelchen bringen rein garnichts!
Da muß man ewig rumraten, wie alle Funktionen, Macros und Variablen
deklariert sind und was sie vermutlich bedeuten könnten.
Zeig einen compilierbaren relevanten Code als Anhang.
Peter
Peter Dannegger schrieb:> Philipp schrieb:>> Um diesen Codeausschnitt handelt es sich>> Das ist ungefähr so, als würde von Dir jemand verlangen, ein Buch durchs> Schlüsselloch zu lesen.
Den muss ich mir merken. Der ist gut.
> set_display_number(result*176/1024);
Da mangels ausführlichen Codes sowieso Ratestunde ist, tippe ich mal
darauf dass es egal ist, wie result hier deklariert ist, falls es erst
dem Funktionsparameter übergeben und dann darauf die Rechnung ausgeführt
wird.
Leicht feststellbar, indem man den Parameter auf 32Bit ändert. Oder sich
lss ansieht.
Hallo,
Danke erstmal für die vielen antworten. Ich reiche den vollständigen
Code heute Abend noch nach. Ich komme dem Fehler nicht auf die Spur.
Als ich mir gestern zum testen mal den adc-Wert aus result
(übrigends32bit) ausgeben lassen habe ist mir aufgefallen, dass der Wert
manchmal nicht korrekt ist und "springt". Z.b. Kommt nach dem Wert 696
nicht 697 sondern 607 und danach kommt 698.
Meine set number Methode zeigt aber alle Zahlen von 0-999 korrekt an(mit
for getestet).
Bis später,
Philipp
Philipp schrieb:> Ich reiche den vollständigen Code heute Abend noch nach.
Hallo Philipp,
wichtig ist auch die Information, welchen Compiler du nutzt und auf
welchem Prozessor das Ganze läuft.
Grüße
Stefan
Hallo,
hier ist der Programmcode. Ich habe das übrigends in Eclipse (mit
AVR-Plugin) geschrieben und mit AVR-Studio4 auf meinen Atmega168PA
gebrannt. Leider gibt es in Eclipse den Atmega168PA nicht zur Auswahl
und bei dem Atmega168P lassen sich die Register nicht ansprechen,
weshalb ich den Atmega168 ausgewählt habe(Ich hoffe es liegt nicht
daran?).
Falk Brunner schrieb:> @ Philipp (Gast)>>>Meine set number Methode zeigt aber alle Zahlen von 0-999 korrekt an(mit>>for getestet).>> Wie? So hier?> if(flag.multiplex==1)> {> flag.multiplex=0;> //result = ADC;> // test> result = 1023;> ADCSRA |= (1<<ADSC);>> set_display_number(result*176/1024);> set_dot(zehn);> }
Es wird 175 Ausgegeben. Wenn ich anstelle von 1023 result per
for-schleife durchzähle funktioniert die Ausgabe bei allen Zahlen
Fehlerfrei. Ich schätze es muss irgendwie mit dem ADC-Wert
zusammenhängen, da dort manchmal schon völlig falsche Werte ausgespuckt
werden.(?)
Was macht der Timer 1?
> TIMSK1 = (1<<TOIE1);> TCCR1B = (1<<CS11);
Du gibst da einen Interrupt frei, für den ich die ISR nicht sehen kann.
Nicht gut.
> Ich schätze es muss irgendwie mit dem ADC-Wert> zusammenhängen, da dort manchmal schon völlig falsche> Werte ausgespuckt werden.(?)
Das lässt sich ja überprüfen. Du hast eine Ausgabe zur Verfügung (wenn
auch nur 3-stellig. Lässt du dir halt einfach immer die Hälfte vom ADC
Wert anzeigen, dann passt der da rein. Dein Problem hängt ja nicht damit
zusammen, dass der ADC Wert um +- 1 schwankt)
Karl Heinz Buchegger schrieb:> Du gibst da einen Interrupt frei, für den ich die ISR nicht sehen kann.> Nicht gut.
Oh Sorry, das ist noch ein Überbleibsel als ich ausprobiert habe was
passiert wenn ich den ADC in einem seperaten langsam laufenden
Timer-Interrupt auslese.
Karl Heinz Buchegger schrieb:> Das lässt sich ja überprüfen. Du hast eine Ausgabe zur Verfügung (wenn> auch nur 3-stellig. Lässt du dir halt einfach immer die Hälfte vom ADC> Wert anzeigen, dann passt der da rein. Dein Problem hängt ja nicht damit> zusammen, dass der ADC Wert um +- 1 schwankt)
Habe jetzt mal folgendes ausgeben lassen:
1
if(flag.multiplex==1)
2
{
3
flag.multiplex=0;
4
//result = ADC;
5
set_display_number(ADC/2);
6
ADCSRA|=(1<<ADSC);
7
8
//set_display_number(ADC/2);
9
//set_display_number(result);
10
}
Dabei kommt das hier heraus:
http://www.youtube.com/watch?v=gZnhV_pHSr8
Also wieder total komische Werte (von 199 -> 190 -> 101 -> 102 -> 200 ->
201). Und zwar nicht zufällig sondern diese Sprünge sind immer an der
gleichen Stelle im Wertebereich. Ist meine 7-Segment Routine so OK oder
könnte es vielleicht doch irgendwie daran liegen? Ich weiß nicht was ich
noch testen könnte.
Kann mein Atmega vielleicht auch eine Macke haben?
Karl Heinz Buchegger schrieb:> Wie ist die Aussenbeschaltung vom ADC?> ARef, AVcc?
Aref ist mit 100nF nach GND entkoppelt und AVCC mit 22µH + 100µF nach
VCC.
Philipp schrieb:> void set_display_number(uint16_t number)
Das dürfte die entscheidende Information sein.
set_display_number(result*176/1024) enthält also einen impliziten cast
des Ausdrucks result*176/1024 auf uint16_t.
Wenn ich den Abschnitt "Conversions" (C89, identisch ISO/IEC 9899:1999)
richtig verstehe, sollte dieser cast aber erst nach der Auswertung des
rvalue greifen. result*176/1024 müsste also noch uint32_t sein.
Ok, schauen wir mal:
ADC 10 bit. *176 gibt 28 bit. /1024 ist ein Rechtshift um 10 bit,
bleiben also 18 bit übrig. -> Das passt nicht in einen uint16_t.
Du hast aber nur 3 signifikante Ziffern, der Wert ist also eh zu weit
aufgelöst. Ist der Umrechnungsfaktor wirklich passend?
Grüße
Stefan
Stefan Wagner schrieb:> Ok, schauen wir mal:> ADC 10 bit. *176 gibt 28 bit. /1024 ist ein Rechtshift um 10 bit,> bleiben also 18 bit übrig. -> Das passt nicht in einen uint16_t.
Irgendwo musst du dich da verrechnet haben.
Das Ergebnis kann nur Werte im Bereich 0 bis 176 sein.
Ach ja, was mir noch auffiel:
Philipp schrieb:> volatile uint8_t segmente[]={
Wenn ich das richtig sehe, ist das doch die Tabelle mit den Werten für
die Ansteuerung der Segmente.
Warum dann die Deklaration als volatile? Diese Werte sind doch konstant
und sollen es auch bleiben. Einer Optimierung durch den Compiler steht
doch nicht im Wege, selbst wenn auch aus einer ISR auf das Array
zugegriffen wird. (Die Deklaration const uint8_t segmente[] hielte ich
für wesentlich sinnvoller.)
Grüße
Stefan
Philipp schrieb:> Also wieder total komische Werte (von 199 -> 190 -> 101 -> 102 -> 200 ->> 201).
Das sieht so aus, als ob die Segmenttabelle um 1 verschoben wäre.
eine angezeigte 9 ist eigentlich 8
0 ist eigentlich 9
1 ist eigentlich 0
usw.
> Und zwar nicht zufällig sondern diese Sprünge sind immer an der> gleichen Stelle im Wertebereich. Ist meine 7-Segment Routine so OK
Ich hätt jetzt gesagt: ja
Schreibs mal so
Karl Heinz Buchegger schrieb:> Irgendwo musst du dich da verrechnet haben.> Das Ergebnis kann nur Werte im Bereich 0 bis 176 sein.
Ups. Ja. Und das hätte mir beim genauen Hinsehen auch auffallen müssen.
(1023/1024 ist doch recht nahe an 1.) Ich war wohl doch schon zu müde.
Grüße
Stefan
Danke nochmal an euch! Mittlerweile funktioniert es sogar, obwohl ich
nicht sagen kann an was das Problem jetzt genau lag. Ich lese den ADC
jetzt einfach doch in einem extra Interrupt aus.
Gruß,
Philipp