Hi Leute, also ich brauch eure Hilfe, und zwar bekomme ich in einer C-Variable in meinem Programm eine Zeit von sagen wir mal 3438798798ns und diese Zahl möchte ich in s umwandeln. Die einzige Idee, die ich habe, war die Zahl einfach *1000000000 zu nehmen, aber da gibt es doch bestimmt eine schönere Variante, oder? Dann wollte ich noch fragen, ob die Zahlen richtig deklariert sind: die ns-Zahl hab ich als unsigned long int und die in s als int. Oder beißt es sich, wenn ich in einer Anweisungszeile zwei versch. Datentypen habe? Ich weiß, es sind bestimmt primitive Fragen für euch , aber ich würd mich trotzdem über eure Antworten freuen!
>> 3438798798ns und diese Zahl >> möchte ich in s umwandeln. Die einzige Idee, die ich habe, war die Zahl >> einfach *1000000000 zu nehmen Dann hast du "as". Um auf Sekunden zu kommen musst du durch 10^9 teilen. 1 s = 1000 ms = 1 000 000 µs = 1 000 000 000 ns. Warum "int" für eine Zeit? Brauchst du negative Werte? Rechne mit Festkomma.
hi, zunächst einmal wäre /1000000000 etwas besser. /1000000000UL müsste man auch schreiben können um der variable auch gleich den richtigen datentyp zuzuweisen. dann die frage ob du ein exaktes ergebnis benötigst oder ob auch ein ungefährer wert reicht. wenn du eine kleine abweichung vertragen kannst dann könntest du über shifting operationen dividieren (a >> 30), entspricht (a / 1073741824. wenn du unsigned long als datentyp verwendest dann kannst du gerade mal 4 sekunden abmessen. es wäre also sinnvoller wenn du schon irgendwo vorher deine ns Variable langsamer hochzählen würdest.
<zunächst einmal wäre /1000000000 etwas besser.> hab mich nur vertippt...also umwandeln kann ich! was bedeutet :/1000000000UL ? den Satz <wenn du unsigned long als datentyp verwendest dann kannst du gerade mal 4 sekunden abmessen. es wäre also sinnvoller wenn du schon irgendwo vorher deine ns Variable langsamer hochzählen würdest.> check ich gar nicht :(
Kartoffel wrote: > was bedeutet :/1000000000UL ? Das bedeutet, dass die Berechnung in unsigned long durchgeführt wird. Ohne das UL kann es passieren (wenn die anderen Datentypen in der Berechnung kleiner als unsigned long sind), dass die Berechnung in int durchgeführt wird (Standard) und es einen Überlauf gibt. > den Satz <wenn du unsigned long als datentyp verwendest dann kannst du > gerade mal > 4 sekunden abmessen. es wäre also sinnvoller wenn du schon irgendwo > vorher deine ns Variable langsamer hochzählen würdest.> check ich gar > nicht :( Ist doch eigentlich nicht schwer: In unsigned long passen nunmal nur 2^32 (also 4294967296) ns rein, das sind nicht mal 4,3 s...
Unsigned long hat nur einen bestimmten Wertebereich. Wenn Du mehr als 4e9 ns ( = 4 s ) binär darstellst ( = 31.89 Bit, also 32 ), sprengst Du den Rahmen von UL. Die Folge ist ein Überlauf und komplett falsche Ergebnisse.
>was bedeutet :/1000000000UL ? UL heist das diese Konstante als Unsigned Long zu nehmen ist >den Satz <wenn du unsigned long als datentyp verwendest dann kannst du >gerade mal >4 sekunden abmessen. es wäre also sinnvoller wenn du schon irgendwo >vorher deine ns Variable langsamer hochzählen würdest.> check ich gar >nicht :( Ganz einfach unsigned long = (2^32)-1 = 4294967295 ist der hoechste Wert den die Variable fassen kann. Einen hoehren Wert kannst du nicht darin abspeichern. 4294967295 / 1000000000 = 4.29 Sek. Gruss Helmi
<Ist doch eigentlich nicht schwer: In unsigned long passen nunmal nur 2^32 (also 4294967296) ns rein, das sind nicht mal 4,3 s...> Stimmt, ist ja eigentlich ganz klar. Welchen Datentypen brauche ich, um die Zeit zwischen 0,02 und 60 s darstellen zu können?
Sag doch erst einmal wie du an die ns kommst? Vielleicht ist das ja gar nicht kritisch und man kann es anders realisieren!
Kartoffel wrote: > <Ist doch eigentlich nicht schwer: In unsigned long passen nunmal nur > 2^32 (also 4294967296) ns rein, das sind nicht mal 4,3 s...> > > Stimmt, ist ja eigentlich ganz klar. > Welchen Datentypen brauche ich, um die Zeit zwischen 0,02 und 60 s > darstellen zu können? Wenn das ganz klar ist, solltest Du auch ohne Probleme den Bedarf für 60 s berechnen können. log(60000000000)/log(2) = 35,8 => 36 Bit Mein Vorschlag: Array von uint8 mit 5 Einträgen = 40 Bit Der Rest ist mit logischem Denken und ein wenig Programmierkenntnis einfach zu lösen.
hi, ist das überhaupt für die implementierung in einem mikrocontroller gedacht oder läuft das programm auf einem PC? wenn es eine ganz normale anwendung auf einem PC ist dann nimmst du einfach double gleitkommawerte und gut ist. wenn das programm in einem µC laufen soll, dann poste doch einfach mal deinen code rein
Kartoffel wrote: > <Ist doch eigentlich nicht schwer: In unsigned long passen nunmal nur > 2^32 (also 4294967296) ns rein, das sind nicht mal 4,3 s...> > > Stimmt, ist ja eigentlich ganz klar. > Welchen Datentypen brauche ich, um die Zeit zwischen 0,02 und 60 s > darstellen zu können? Das kommt drauf an. Brauchst du eine Auflösung auf Nanosekunden?
also ich habe eine Anwendung, die auf einem µC läuft. Ich messe mittels Timer die Zeit zw. zwei Encoderimpulsen und möchte daraus die Drehzahl errechnen. Die Timerperiode ist 1,6384000ms Die Auflösung von Encoder 500 Die max. Drehzahl vom Motor: 3000U/min also mein Code: //********************************************************************** ****** // Variablen //********************************************************************** ****** unsigned int Counter = 0; // zum Zählen der Interrupts unsigned long int Periode = 0x00000000; // Zeit zwischen zwei Impulsen unsigned long int Umdr_t = 0x00000000; // Zeit für eine Umdrehung in ns int Umdr_t_s = 0; // Zeit für eine Umdrehung in s unsigned long int help = 0x00000000; //********************************************************************** ****** // Unterfunktionen //********************************************************************** ****** unsigned long int Drehzahl(void) { unsigned long int Drehzahl = 0x00000000; if (Counter ==1) { CC9alt = 0x0000; } if (CC1_CC9 < CC9alt) { Counter_dif = 0-(CC1_CC9-CC9alt); } else { Counter_dif = CC1_CC9-CC9alt; } CC9alt = CC1_CC9; help =(int)Counter_dif; Periode = (help-1)* 25; // Angabe in ns Umdr_t = (500-1)* Periode; // Angabe in ns Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s Drehzahl = (1/Umdr_t)*60*1000000000; // Drehzahl in Umdrehungen pro Minute return Drehzahl; } void CC1_viCC9(void) interrupt CC1_CC9INT using RB_LEVEL9 { // USER CODE BEGIN (CC9,2) Counter++; // zählen der Interrupts Drehzahl_mot = Drehzahl();
> Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s Sobald der Wert in Umdr_t kleiner als 1000000000 ist, und das dürfte er die meiste Zeit sein, ausser der Motor steht, liefert diese Division immer 0 > Drehzahl = (1/Umdr_t)*60*1000000000 Ditto hier: 1 / Umdr_t wird immer 0 sein, es sein denn Umdr_t ist zufällig genau 1. Du gehst da ein bischen zu naiv ran. Und Nanosekunden wirst du überhaupt nicht brauchen. Schnapp dir deinen Taschenrechner und rechne mal ein bischen: Wenn du die Zeit zwischen 2 Encoder Impulsen um 25ns falsch bestimmst, um wieviel ändert sich dann die gemessene Frequenz und hat dein Motor überhaupt einen derartigen Gleichlauf? Dann dasselbe noch mal mit Mikrosekunden.
hi, ohne den sinn der zeilen zu überdenken habe ich die letzten zeilen mathematisch umgeschrieben:
1 | Periode = (help-1)* 25; // Angabe in ns |
2 | Umdr_t = (500-1)* Periode; // Angabe in ns |
3 | Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s |
4 | |
5 | Drehzahl = 60/Umdr_t_s; // Drehzahl in Umdrehungen pro |
6 | Minute
|
1 | Umdr_t_s = (499*help-499)/40000000; |
2 | Drehzahl = 2400000000/(499*(help-1)); |
ich weiß zwar nicht wie du auf die zeitkonstanten 500 bzw 25 kommst, aber wenn man immer die -1 weglassen würde dann kommt man auf die einfachen formeln:
1 | Umdr_t_s = help/80000; |
2 | Drehzahl = 4800000/help; |
@ Karl heinz Buchegger (kbuchegg): also dann hab ich eine grundsätzliche Frage: wie bekomme ich denn heraus, ob mir mein Timer µs oder ns liefert? Der Timer ist mit 0,025 µs getaktet. Also statk vereinfacht kann man sagen, dass die Zeit, in der er von 0 bis 1 zählt 0,025 µs beträgt, oder? Bei einer pos. Flanke wird der Zählerstand in ein Register geschrieben, bei mir CC1_CC9. Wie bekomme ich heraus, ob die Zeit in µ oder n -Sekunden ist? Das sieht man doch an der Zahl, die im CC9 steht nicht.. Oder ist die Einheit vom Takt auch automatisch die Einheit des Zählerstandes?
Der Timer liefert Dir keinen Wert in ns oder µs ... wie schnell Dein Timer ist, hängt vom Quarz ab, welches den Timer taktet. Zum Beispiel: 8 MHz => 1/8 MHz = 0,000000125 s = 125 ns Dein Timer zählt also alle 125 ns einmal hoch ... Les Dir am besten mal die Datenblätter durch und mach das AVR-GCC Tutorial von dieser Website. Dort ist alles erklärt was man dazu wissen muss ( auch wenn Du keinen AVR haben solltest ).
Kartoffel wrote: > @ Karl heinz Buchegger (kbuchegg): > also dann hab ich eine grundsätzliche Frage: > wie bekomme ich denn heraus, ob mir mein Timer µs oder ns liefert? > Der Timer ist mit 0,025 µs getaktet. Also statk vereinfacht kann man > sagen, dass die Zeit, in der er von 0 bis 1 zählt 0,025 µs beträgt, > oder? > Bei einer pos. Flanke wird der Zählerstand in ein Register geschrieben, > bei mir CC1_CC9. Wie bekomme ich heraus, ob die Zeit in µ oder n > -Sekunden ist? Das hängt davon ab, wie du deinen Timer initialisiert hast, wie schnell der zählt. Wenn der Timer mit 0.025µs getaktet wird, ja dann entspricht eine Timererhöhung um 1 einem Zeitverbrauch von 25 ns. Aber: Kann man den Timer auch langsamer laufen lassen? Ich kenn das nur von den AVR. Deren Timer haben einen Vorteiler. Je höher man diesen setzt, desto mehr Zeit vergeht aber auch bis der Timer um 1 weiter gezählt hat. Aber: Der Timer zählt dann zwischen 2 Encode Interrupts nicht mehr so hoch. Wenn also beispielweise von einem Encoder Interrupt zum nächsten der Timer bis 50000 zählt und du den Vorteiler um einen Faktor 10 vergrößerst, dann zählt er danach bei ansonsten gleichem Setup nur noch bis 5000. Dadurch werden aber auch die Zahlen kleiner, allerdings sinkt klarerweise deine zeitliche Auflösung. Konntest du vorher mit dem Timer noch 25ns unterscheiden, so kannst du jetzt nur noch 250ns unterscheiden. Aber: Das musst du mal durchrechnen, was diese verminderte zeitliche Auflöung für deine gemessene Drehzahl bedeutet. Immer davon ausgehen, dass dein Timercount auf +/- 1 genau sein wird. Wenn da im Endeffekt rauskommt, dass du die Drehzahl noch auf zehntausendstel U/min genau bestimmen kannst, dann wird das wohl immer noch genau genug sein. > Oder ist die Einheit vom Takt auch automatisch die Einheit des > Zählerstandes? Musst du im Datenblatt nachlesen. Bei einem AVR kann man zwischen CPU Takt und den Takt mit dem der Zähler betrieben wird einen Vorteiler schalten. Wenn der 1 ist, ja dann takten beide gleich schnell. Entsprechend hoch sind aber auch deine Zahlen. Bis sie so hoch sind, dass man nicht mehr sinnvoll damit Arithmetik betreiben kann, weil ständig Overflows in den Berechnungen drohen. Hier gilt es abzuwägen!
ich habe festgestellt, dass es eigentlich egal ist, was für eine Einheit man hat, ich hab ja eigenltich nur eine Zahl in dem Register und kann sie umwandeln wie ich will. Hab mich jetzt entschieden es so zu machen: zählerstand*Auflösung(0,025µs). Dann hab ich ja die Zeit in µs. Dann mache ich einfach: Drehzahl = (1/Umdr_t)*60*1000000; und dann müsste es doch passen oder? Auch von der Auflösung her...
Kartoffel wrote: > Dann mache ich einfach: > Drehzahl = (1/Umdr_t)*60*1000000; > und dann müsste es doch passen oder? Nein. 1 ist eine ganze Zahl Umdr_t ist eine ganze Zahl Daher wird die Division 1 / Umdr_t ebenfalls als Ganzzahldivision ausgeführt. Da Umdr_t aber höchst wahrscheinlich größer als 1 sein wird, steht da eine Division die immer 0 ergeben wird. Und 0 * 60 ergibt 0 und 0 * 1000000 ergibt dann in weiterer Folge wieder 0. -> Fazit: Dein Programm wird dir immer 0 als Drehzahl ausgeben. (ausser vielleicht wenn der Motor steht, dann wird es zu Overflows kommen und nur Gott alleine weiss, was dann raus kommt. 1 / 0 ergibt nämlich Unendlich) Du willst etliche Multiplikationen machen, bevor du dividierst! Nur: Wenn du mit 1000000 multiplizierst, dann riskierst du einen Overflow in der Multiplikation. > Auch von der Auflösung her... Das mag sein.
na gut, schon kapiert, aber so funktioniert's ganz sicher : Drehzahl = 60000000/Umdr_t; Und danke für die Geduld!!!
Wo kommt jetzt eigentlich die 1000000 her? Wie schnell tickt denn jetzt dein Timer? Der Faktor den du hier anwendest muss natürlich zu deiner Zählfrequenz passen! BTW: Ist dieser Timer ein 16-Bit Timer?
@ Karl heinz Buchegger (kbuchegg) es ist ein 16Bit Timer. Und wie schell er tickt hab ich dir versucht oben zu erklären. Meine Meinung ist, dass es egal ist: ich hab ja später nur eine Zahl im Register stehen, in meinem Fall ist das der CC9. Da steht jetzt der Zählerstand des Timers drin. Da der Timer mit 0,025µs zählt, denn das ist der TAkt, mit dem der gespeist wird, kann ich die Periode zw. zwei Zählerständen so bestimmen: Periode = ((CC9-CC9alt)*25)/1000. Danach bestimme ich die Umdrehungszeit(Zeit für eine Umdrehung in µs) = 500*Periode, denn 500 ist die Auflösung des Encoders. Um die Drehzahl zu bestimmen muss ich die µs in min umwandeln, daher 60*1000000 und dann noch 1/Umdrehungszeit, dann habe ich die Drehzahl. Ich löse das so :Drehzahl = 60000000/Umdr_t; Aber die Drehzahl ändert sich beim Debuggen des Programmes nicht, wo hab ich wieder nen Fehler gemacht?
Wenn das ein 16-Bit-Timer ist, dann können da aber nur Zahlen von 0 bis 65535 drin stehen. Also kann das alles schon mal so gar nicht sein...
<Wenn das ein 16-Bit-Timer ist, dann können da aber nur Zahlen von 0 bis 65535 drin stehen. Also kann das alles schon mal so gar nicht sein...> heee? Was soll da jetzt nicht stimmen, ich weiß schon, dass der Zähler bis 2^16 zählen kann.
Kartoffel wrote: > <Wenn das ein 16-Bit-Timer ist, dann können da aber nur Zahlen von 0 bis > 65535 drin stehen. Also kann das alles schon mal so gar nicht sein...> > heee? Was soll da jetzt nicht stimmen, ich weiß schon, dass der Zähler > bis 2^16 zählen kann. Also ich hab mir Deinen Code von 10:10 Uhr jetzt mal kurz angeschaut, und ich vermute mal, dass (abgesehen von den Problemen, die andere schon angebracht haben) ein weiteres Problem darin bestehen dürfte, dass die Zählvariable, die in der ISR verändert und im Hauptprogramm verarbeitet wird, nicht volatile deklariert ist. Was der Compiler dann damit macht, steht in den Sternen. Und wenn Du mittlerweile Deinen Code verbessert hast, dann lass doch einfach mal sehen. Und dann poste ihn auch gleich vernünftig formatiert (oder als Anhang, dann gibts automatisch ne formatierte und lesbarere Version)
Kartoffel wrote: > @ Karl heinz Buchegger (kbuchegg) > es ist ein 16Bit Timer. > Und wie schell er tickt hab ich dir versucht oben zu erklären. > Meine Meinung ist, dass es egal ist: Ist es eben nicht unbedingt. Aber rechnen wir doch wieder mal ein bischen: Dein Timer tickt mit 0.025µs. Da er nur bis 65535 zählen kann ... wie lange dauert es eigentlich bis der Zähler einmal rundum ist? Das dauert 65536 * 0.025µs oder 1638,4 µs. Das sind 1.6384 ms. Das ist also die längste Zeit, die du mit deinem Timer messen kannst. Ist die Zeit länger, dann läuft der Timer über und du misst Unsinn. Welche Zeit misst du denn aber? Du misst die Zeit die von einem Encoder Ereignis bis zum nächsten vergeht. Da für eine Umdrehung deines Motors 500 Encoder Ereignisse anfallen, folgt aber auch daraus, dass eine Umdrehung deines Motors maximal 500 * 1.6384 = 812.2 ms oder 0.8192 Sekunden dauern darf. Dreht sich der Motor langsamer, misst du Mist. 0.8192 Sekunden entspricht einer Drehzahl von 1.22 U/sec oder 72 U/min. Dreht dein Motor langsamer als diese 72 U/min, dann spuckt dein Drehzahlmesser Werte aus, die hinten und vorne nicht stimmen. Wenn du damit leben kannst, ist es gut. Wenn nicht, musst du dir was dazu überleben. Ich persönlich würde keinem Drehzahlmesser über den Weg trauen, der zwar 3000 U/min messen kann, aber bei 50 U/min kläglich versagt. > Ich löse das so :Drehzahl = 60000000/Umdr_t; > Aber die Drehzahl ändert sich beim Debuggen des Programmes nicht, wo hab > ich wieder nen Fehler gemacht? Lass dir einfach mal die Zwischenergebnisse ausgeben. Dann findest du schon, welche Berechnung wieder Unsinn liefert. Fang ganz vorne an, indem du dir die Differenz der Zählerstände ausgeben lässt. Von dort weg verfolgst du dann jede einzelne Berechnung, indem du dir das Result der Berechnung ausgeben lässt.
@Johannes M. ich habe keine Variable, die in der ISR verändert und in main verarbeitet wird. Wenn du counter meinst, dann ist das nur eine Hilfsvariable gewesen, um beim Debuggen auszuprobieren, ob ich überhaupt in die ISR reingehe, wenn ein Impuls vom Encoder erkannt wird, das war's. Den Code habe ich einbisschen schon verändert und stell ihn wieder rein. Also ein ,und ich hoffe, es ist wirklich nur ein Problem, besteht noch. Meine Drehzahl lässt sich noch nicht bestimmen. Also die Variable verändert ihren Wert einfach nicht (watch-Fenster):( Also ich poste, allerdings weiß ich nicht, wie man den vernünftig formatiert.. //********************************************************************** ****** // Variablen //********************************************************************** ****** unsigned int Counter = 0; // zum Zählen der Interrupts unsigned long int Periode = 0x00000000; // Zeit zwischen zwei Impulsen unsigned long int Umdr_t = 0x00000000; // Zeit für eine Umdrehung in ns //int Umdr_t_s = 0; // Zeit für eine Umdrehung in s unsigned long int help = 0x00000000; //********************************************************************** ****** // Unterfunktionen //********************************************************************** ****** unsigned long int Drehzahl(void) { unsigned long int Drehzahl = 0x00000000; unsigned long int a = 60000000; if (Counter ==1) { CC9alt = 0x0000; } if (CC1_CC9 < CC9alt) { Counter_dif = 0-(CC1_CC9-CC9alt); } else { Counter_dif = CC1_CC9-CC9alt; } CC9alt = CC1_CC9; help =(int)Counter_dif; Periode = (help*25)/1000; // Angabe in µs Umdr_t = 500* Periode; // Angabe in µs //Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s Drehzahl = a/Umdr_t; // Drehzahl in Umdrehungen pro Minute return Drehzahl; } void CC1_viCC9(void) interrupt CC1_CC9INT using RB_LEVEL9 { // USER CODE BEGIN (CC9,2) Counter++; // zählen der Interrupts Drehzahl_mot = Drehzahl();
Kartoffel wrote: > Also ich poste, allerdings weiß ich nicht, wie man den vernünftig > formatiert.. Steht alles über dem Editor-Feld, direkt unter den "Wichtigen Regeln"!
1 | //****************************************************************************
|
2 | // Variablen
|
3 | //****************************************************************************
|
4 | unsigned int Counter = 0; // zum Zählen der Interrupts |
5 | unsigned long int Periode = 0x00000000; // Zeit zwischen zwei Impulsen |
6 | unsigned long int Umdr_t = 0x00000000; // Zeit für eine Umdrehung in ns |
7 | //int Umdr_t_s = 0; // Zeit für eine Umdrehung in s
|
8 | unsigned long int help = 0x00000000; |
9 | |
10 | |
11 | |
12 | //****************************************************************************
|
13 | // Unterfunktionen
|
14 | //****************************************************************************
|
15 | unsigned long int Drehzahl(void) |
16 | {
|
17 | unsigned long int Drehzahl = 0x00000000; |
18 | unsigned long int a = 60000000; |
19 | |
20 | if (Counter ==1) |
21 | {
|
22 | CC9alt = 0x0000; |
23 | }
|
24 | if (CC1_CC9 < CC9alt) |
25 | {
|
26 | Counter_dif = 0-(CC1_CC9-CC9alt); |
27 | }
|
28 | else
|
29 | {
|
30 | Counter_dif = CC1_CC9-CC9alt; |
31 | }
|
32 | |
33 | CC9alt = CC1_CC9; |
34 | |
35 | help =(int)Counter_dif; |
36 | |
37 | Periode = (help*25)/1000; // Angabe in µs |
38 | Umdr_t = 500* Periode; // Angabe in µs |
39 | //Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s
|
40 | |
41 | Drehzahl = a/Umdr_t; // Drehzahl in Umdrehungen pro Minute |
42 | |
43 | |
44 | return Drehzahl; |
45 | |
46 | }
|
47 | |
48 | void CC1_viCC9(void) interrupt CC1_CC9INT using RB_LEVEL9 |
49 | {
|
50 | // USER CODE BEGIN (CC9,2)
|
51 | |
52 | Counter++; // zählen der Interrupts |
53 | |
54 | Drehzahl_mot = Drehzahl(); |
ach so....
volatile unsigned int CC9alt; und CC1_CC9 ist ein Register der Capcom_1 also ein 16bit Register.
Hast du mal meinen Vorschlag versucht und dir die Zwischenergebnisse ausgeben lassen? Also: Welche Werte hat Counter_dif?
also das mit dem Timerüberlauf kann gut sein, dass das nicht passt, denn ich muss erst nachschauen, wie groß die kleinste Drehzahl ist, die ich brauch. Ich glaube, die ist unter 70, muss aber erst das Lastenheft suchen. Ich kann leider erst morgen weiter versuchen am Problem zu arbeiten, denn ich muss jetzt weg. vielen Dank für die Unterstützung ich werde morgen dann alle posts lesen und bescheid sagen, wie weit ich bin lg Kartoffel
Kartoffel wrote: > @Karlheinz: > > Werte von z.B.0x00003F14 Das sind dann dezimal 16148 Was ist deine erste Berechnung? > help =(int)Counter_dif; Da passiert erst mal nichts. help sollte ebenfalls 16148 sein (kontrollieren!) help ist vom Typ int? > > Periode = (help*25)/1000; // Angabe in µs Aber hier: 16148 * 25 -> 403700 das ist reichlich zu gross für einen 16 Bit int Ich kann nur wiederholen: Überprüfe jede einzelne Berechnung. Lass sie dir von deinem Progamm ausgeben und kontrolliere sie mit einem Taschenrechner!
Ich würde die ganzen Berechnungen zu einer einzelnen zusammenwerfen. Es ist wenig zweckmäßig, erst mit 25 zu multiplizieren, dann durch 1000 zu dividieren, dann wieder mit 500 zu multiplizieren und dann noch 60 Millionen durch das Ergebnis zu dividieren. Das erhöht auf der einen Seite das Risiko, Überläufe zu bekommen, andererseits schneidest du Teile der Werte ab und verringerst so die Genauigkeit.
> Rolf Magnus wrote:
Full ACK.
Andererseits erhöht das Debuggen von solch verkorksten Dingen
ungemein das Verständnis, warum eine naive Umsetzung von
irgendwelchen Formeln in Code nicht notwendigerweise eine
gute Idee ist und wo die Fallstricke liegen :-)
Solche Fehler macht man nur einmal. Vielleicht 2 mal.
Danach setzt man sich im Vorfeld hin und vereinfacht
den Formalismus so gut es geht und hat gelernt, dass
scheinbar sinnlose Rumrechnerei (zuerst durch 1000, dann
mal 500) zwar am Papier mit exakter Mathematik kein Problem
sind, in einem Computer aber ganz was anderes bewirken. :-)
Hallo Leute, also ich kann mich wieder meinem Problem widmen. Hab jetzt schon einige Vorschläge befolgt und aus den Umrechnungen nur eine Zeile gemacht. Der Code sieht jetzt so aus:
1 | //****************************************************************************
|
2 | // Variablen
|
3 | //****************************************************************************
|
4 | unsigned int Counter = 0; // zum Zählen der Interrupts |
5 | //unsigned long int Periode = 0x00000000; // Zeit zwischen zwei Impulsen
|
6 | //unsigned long int Umdr_t = 0x00000000; // Zeit für eine Umdrehung in ns
|
7 | //int Umdr_t_s = 0; // Zeit für eine Umdrehung in s
|
8 | unsigned long int help = 0x00000000; |
9 | |
10 | |
11 | |
12 | //****************************************************************************
|
13 | // Unterfunktionen
|
14 | //****************************************************************************
|
15 | unsigned long int Drehzahl(void) |
16 | {
|
17 | unsigned long int Drehzahl =0; |
18 | //unsigned long int a = 60000000;
|
19 | |
20 | if (Counter ==1) |
21 | {
|
22 | CC9alt = 0x0000; |
23 | }
|
24 | if (CC1_CC9 < CC9alt) |
25 | {
|
26 | Counter_dif = 0-(CC1_CC9-CC9alt); |
27 | }
|
28 | else
|
29 | {
|
30 | Counter_dif = CC1_CC9-CC9alt; |
31 | }
|
32 | |
33 | CC9alt = CC1_CC9; |
34 | |
35 | help =(int)Counter_dif; |
36 | |
37 | //Periode = (help*25)/1000; // Angabe in µs
|
38 | //Umdr_t = 500* Periode; // Angabe in µs
|
39 | //Umdr_t_s = Umdr_t/1000000000UL; // Angabe in s
|
40 | |
41 | Drehzahl = 4800000/help; // Drehzahl in Umdrehungen pro Minute |
42 | |
43 | |
44 | return Drehzahl; |
45 | |
46 | void CC1_viCC9(void) interrupt CC1_CC9INT using RB_LEVEL9 |
47 | {
|
48 | // USER CODE BEGIN (CC9,2)
|
49 | |
50 | Counter++; // zählen der Interrupts |
51 | |
52 | Drehzahl_mot = Drehzahl(); |
Also am Anfang der Funktion Drehzahl tue ich die Variable Drehzahl vorinitialisieren mit 0. Beim Debuggen stellte ich fest, dass es den Kompiler oder wen auch immer nicht interessiert. Habe die einzelnen Werte im Watchfenster nachgeprüft, also help und Counter_dif passen, die Drehzahl, die dann als nächstes berechnet wird, oder besser gesagt sollte, wird nicht berechnet. Weiß vielleicht einer, woran das liegen könnte?
Kartoffel wrote: > Also am Anfang der Funktion Drehzahl tue ich die Variable Drehzahl > vorinitialisieren mit 0. Beim Debuggen stellte ich fest, dass es den > Kompiler oder wen auch immer nicht interessiert. Hast du den Optimizer des Compilers eingeschaltet. Es kann durchaus sein, dass der Compiler diese Initialisierung auslässt, da der Optimizer feststellt, dass vor der ersten lesenden Verwendung dieser Variablen in allen Codepfaden eine Zuweisung kommt und die Initialisierung daher unnötig ist. > Habe die einzelnen Werte im Watchfenster nachgeprüft, also help und > Counter_dif passen, > die Drehzahl, die dann als nächstes berechnet wird, > oder besser gesagt sollte, wird nicht berechnet. Oh. Berechnet wird sie sicherlich. Mach mal Folgendes: Aus den 4800000 mach mal 4800000L Das sollte zwar der Compiler alleine erkennen, dass diese Zahl ein long sein muss, aber sicher ist sicher. Das nächste: Es ist nicht sehr schlau eine Variable und eine Funktion gleich zu benennen. Vom C-Standard her ist das IMHO erlaubt, in der Praxis kommt es da aber manchmal zu subtilen Problemen und sei es nur, weil der Debugger damit nicht einwandfrei klarkommt.
aaalso, habe jetzt endlich die richtige Drehzahl, hoffentlich. Was ich geändert habe: hab nen anderen Prescaler für den Timer genommen, damit ich auch langsame Drehzahlen erfassen kann. Warum ich die Variable Drehzahl nicht habe anzeigen können im Debugger, weiß ich jetzt auch, sie war local deklariert. Hab einfach die Variable Drehzahl_mot angeschaut, die ist ja in der ISR verwendet, dann hat es auch gepasst. Was ich noch gerne wissen würde: Mein Motor ist an eine Gleichspannungsquelle angeschlossen. BEi 24V sollte er eine Drehzahl von 3000U/min haben. Also bei 12V sollte er ca. 1500 haben. Ich messe aber 1880, kann es so eine große Ungenauigkeit geben, oder hab ich irgendwas nicht bedacht? Wenn es jemanden interessiert, kann ich den hoffentlich entgültigen Code reinposten.
@ Kartoffel (Gast) >sollte er eine Drehzahl von 3000U/min haben. Also bei 12V sollte er ca. >1500 haben. Das ist lastabhängig und ausserdem mit einer grossen Herstellungstoleranz behaftet. MFG Falk
Kartoffel wrote: > Also bei 12V sollte er ca. 1500 haben. > Ich messe aber 1880, 'Sollte' ist ein Begriff, den du in so einem Fall nicht verwenden willst. Nimm einen anderen Drehzahlmesser und miss nach. Alles andere ist Kaffeesatzlesen. Ausserdem: 1880 ist doch circa 1500
<Ausserdem: 1880 ist doch circa 1500> also können solche Toleranzen schon vorkommen?
mit einem anderen Encoder nachmessen ist schlecht, der Encoder ist sozusagen in den Motor integriert, hängt am Motor dran.
@ Kartoffel (Gast) >mit einem anderen Encoder nachmessen ist schlecht, der Encoder ist >sozusagen in den Motor integriert, hängt am Motor dran. Damm miss mal mit nem Frequenzzähler statt deinem uC. Mfg Falk
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.