Forum: Mikrocontroller und Digitale Elektronik ns in s in C umwandeln


von Kartoffel (Gast)


Lesenswert?

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!

von TOM (Gast)


Lesenswert?

>> 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.

von Stefan N. (nollsen)


Lesenswert?

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.

von Kartoffel (Gast)


Lesenswert?

<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 :(

von Johannes M. (johnny-m)


Lesenswert?

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...

von thomas (Gast)


Lesenswert?

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.

von thomas (Gast)


Lesenswert?

Hupps, zu langsam ;)

von Helmi (Gast)


Lesenswert?

>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

von Kartoffel (Gast)


Lesenswert?

<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?

von Andre (Gast)


Lesenswert?

Sag doch erst einmal wie du an die ns kommst? Vielleicht ist das ja gar 
nicht kritisch und man kann es anders realisieren!

von sechseinssechs (Gast)


Lesenswert?

Na, das waere noch mindestens ein byte mehr als unsigned 32...

von Thomas H. (mac4ever)


Lesenswert?

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.

von Stefan N. (nollsen)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Kartoffel (Gast)


Lesenswert?

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();

von ... (Gast)


Lesenswert?

sieht aus wie Kartoffelsalat, was du deinem controller da zumutest!

von sechseinssechs (Gast)


Lesenswert?

Und was soll dann die ns Aufloesung ? Mikrosekunden sind genug.

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Stefan N. (nollsen)


Lesenswert?

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;

von Kartoffel (Gast)


Lesenswert?

@  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?

von Thomas H. (mac4ever)


Lesenswert?

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 ).

von Karl H. (kbuchegg)


Lesenswert?

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!

von Kartoffel (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kartoffel (Gast)


Lesenswert?

na gut, schon kapiert,
aber so funktioniert's ganz sicher :   Drehzahl = 60000000/Umdr_t;

Und danke für die Geduld!!!

von Karl H. (kbuchegg)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?


von Kartoffel (Gast)


Lesenswert?

@ 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?

von Johannes M. (johnny-m)


Lesenswert?

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...

von Kartoffel (Gast)


Lesenswert?

<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.

von Johannes M. (johnny-m)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kartoffel (Gast)


Lesenswert?

@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();

von Johannes M. (johnny-m)


Lesenswert?

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"!

von Kartoffel (Gast)


Lesenswert?

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....

von Johannes M. (johnny-m)


Lesenswert?

Was für Datentypen haben CC1_CC9 und CC9alt?

von Kartoffel (Gast)


Lesenswert?

volatile unsigned int CC9alt;
und CC1_CC9 ist ein Register der Capcom_1 also ein 16bit Register.

von Karl H. (kbuchegg)


Lesenswert?

Hast du mal meinen Vorschlag versucht und dir die
Zwischenergebnisse ausgeben lassen?

Also: Welche Werte hat Counter_dif?

von Johannes M. (johnny-m)


Lesenswert?

...und welchen Datentyp hat Counter_dif?

von Kartoffel (Gast)


Lesenswert?

@Karlheinz:

Werte von z.B.0x00003F14

von Kartoffel (Gast)


Lesenswert?

@ Johannes M. counter_dif ist volatile unsigned long int

von Kartoffel (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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!

von Rolf Magnus (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

> 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. :-)

von Kartoffel (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kartoffel (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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

von Karl H. (kbuchegg)


Lesenswert?

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

von Kartoffel (Gast)


Lesenswert?

<Ausserdem: 1880 ist doch circa 1500>
also können solche Toleranzen schon vorkommen?

von Kartoffel (Gast)


Lesenswert?

mit einem anderen Encoder nachmessen ist schlecht, der Encoder ist 
sozusagen in den Motor integriert, hängt am Motor dran.

von Falk B. (falk)


Lesenswert?

@ 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
Noch kein Account? Hier anmelden.