Forum: Compiler & IDEs Normale Division funktioniert nicht


von Wolfgang (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich lese das Drehzahl vom Motor meines Autos über den µC ein. Das Signal 
ist pulsweitenmoduliert. Da es nicht genau sein muss lese ich es einfach 
direkt über einen Portpin ein und zähle mit, wie lange das signal high 
ist. Das funktioniert auch relativ gut (bis auf das, dass ab und zu auch 
komplett unsinnige werte eingelesen werden, aber egal). Die umgerechnete 
Drehzahl gib ich dann am LCD aus.

Das Problem ist nun, dass die division durch 10 und wieder 
anschliessende multiplikation mit 10 anscheinend nicht immer 
funktioniert. Ich will damit nur die unsinnige Einer-Stelle des 
Drehzahlsignals abschneiden. Aber trotzdem zeigt die Drehzahl am LCD ab 
und zu noch eine einerstelle an (also irgendwas anderes als 0). eine 
zeit lang ist die drehzahl am lcd immer im zehnerbereich und dann hab 
ich auf einmal wieder 2568 rpm.

Vielen Dank schonmal im Voraus

mfg Wolfgang

von atze (Gast)


Lesenswert?

hi, sind deine daten vom typ ganzzahltyp??? gruß atze

von der mechatroniker (Gast)


Lesenswert?

Laß doch die ganze komplizierte Hin- und Herrechnerei sein, rechne von 
vornerein immer mit "drehzahl_in_10rpm" und gib nachher noch eine 0 aus. 
Sollte auch schneller gehen ;-)

also
1
if (Drehzahl_in_teile > 0)
2
{
3
        Drehzahl_in_10rpm = 700000 / Drehzahl_in_teile;
4
}
(mit einer 0 weniger)

und danach natürlich
1
if (Drehzahl_in_10rpm > 450) Drehzahl_in_10rpm = 450;
2
if (Drehzahl_in_10rpm < 50) Drehzahl_in_10rpm = 0;

später hängst du einfach die 0 dran:
1
strcat(Drehzahl_in_rpm_Temp, "0");

Bedenken mußt du nämlich, daß eine Division, auch wenn sie korrekt 
funktioniert, ganz schön Rechenleistung frißt, vor allem bei long.

von Wolfgang (Gast)


Lesenswert?

@ atze: Ja das sind Ganzzahltypen.

@ der mechatroniker: Ja das stimmt. Diese paar Berechnungen fressen mir
                     sehr die Rechenleistung auf.


Und was ist jetzt der Grund dafür, dass die Ausgabe der Drehzahl am LCD 
ab und zu stimmt und dann wieder nicht?

von GastABC (Gast)


Lesenswert?

Entweder optimiert der Compiler /10 *10 weg (kann ich mir eigentlich 
nicht vorstellen), oder der Fehler liegt wo anders:

Wie gibst du denn die Drehzahl aus? Interrupt-gesteuert? Wenn ja, dann 
könnte der Interrupt ja auch genau beim Abarbeiten des Drehzahl-lesens 
eintreffen und Dir damit deine Werte versauen. Nu so eine Idee.

von Wolfgang (Gast)


Lesenswert?

Die Ausgabe erfolgt ganz normal am Schluss der Hauptschleife. Nach den 
ganzen Berechnungen und Einlesen der Ports, usw. Das kanns nicht sein.

Dass der Compiler es weg optimiert glaub ich auch nicht, da beim Wert am 
Display die meiste Zeit die Einerstelle dann 0 ist. Ab und zu dann für 
ein paar Sekunden dann aber wieder nicht. Es ist auch kein Muster zu 
erkennen, dass es regelmäßig dann die Einerstelle wieder ausgibt.

von Uhu U. (uhu)


Lesenswert?

1
void Drehzahl_einlesen (void)
2
{
3
...
4
5
if (bit_is_clear(PIND, 3) && freigabe_drehzahl == 2)
6
{
7
freigabe_drehzahl = 0;
8
}
9
10
...
11
}

Ist es gewollt, daß freigabe_drehzahl == 2 bleibt, wenn nach dem 
Verlassen der while-Schleife bit_is_clear(PIND, 3) false zurückgibt?

von Wolfgang (Gast)


Lesenswert?

Ja das ist gewollt da die if in der while nur zum begrenzen der variable 
und somit der unteren drehzahlgrenze dient. Aber durch das hast du mich 
auf etwas anderes aufmerksam gemacht. Muss ich gleich mal nachschauen. 
Ich meld mich später wieder...

von Wolfgang (Gast)


Lesenswert?

So, hab eine neue Methode ausprobiert, die das Signal genauer einliest 
ohne Schwankungen, aber dafür blockiere ich den µC damit. Dachte am 
Anfang das wär nicht so arg, aber anscheinend doch. Die 
Aktualisierungszeit des Drehzahlsignals ist dadurch auf ein paar 
Sekunden gestiegen!

Hier der Code:

if (bit_is_clear(PIND, 3))
{
  Drehzahl_in_teile = 0;

  while (bit_is_clear(PIND, 3)) {};
  while ((bit_is_set(PIND, 3)) && (Drehzahl_in_teile < 65000)) 
Drehzahl_in_teile++;
}

Der Code an sich stimmt ja oder? Aber kann es wirklich sein, dass dieser 
code den µC so ausbremst?

von Wolfgang (Gast)


Lesenswert?

Wie würde bei euch der Code für das Einlesen eines PWM-Signals von einem 
Datenpin aussehen? (ohne Timer und Interrupt, die sind schon für eine 
pwm-ausgabe in verwendung) Ich brauche keinen kompletten Source-Code, 
sondern eh nur die Stelle mit der Abfrage.

Das Signal hat eine Periodendauer von ein paar ms, der Takt des µC ist 
16MHz und die Abfrage sollte den µC nicht zu lange auslasten, da ich 
auch noch Spannungen mittels ADC einlese und die dann immer schnell am 
LCD angezeigt werden sollen, ohne "Ruckler". es wäre gut wenn das Signal 
um die 10 mal/s eingelesen wird, nicht langsamer.

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang wrote:

> Aber kann es wirklich sein, dass dieser
> code den µC so ausbremst?

Dein Code pollt das Signal. Er wartet also solange in der
Schleife, bis er einen kompletten High-Puls des Signals gesehen
hat.
Das 'Ausbremsen' ist also per Design: In der Zeit, in der der
Eingangspegel des Signals auf High ist, passiert nichts weiter
(ausser einem möglichen Interrupt) und kann auch nichts weiter
passieren.

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang wrote:
> Wie würde bei euch der Code für das Einlesen eines PWM-Signals von einem
> Datenpin aussehen? (ohne Timer und Interrupt, die sind schon für eine
> pwm-ausgabe in verwendung)

Es gibt nur die beiden Möglichkeiten
* entweder du pollst das Signal
* oder du lässt dir einen Interrupt vom Signal erzeugen, wenn
  es den Pegel wechselst. Allerdings brauchst du dazu einen Timer,
  denn irgendwie musst du ja auch die Zeit messen.

von Wolfgang (Gast)


Lesenswert?

Dass der µC durch das Pollen ausgebremst wird ist mir klar, mir ist nur 
nicht klar, warum die Aktualisierungsrate des LCD auf einmal alle 3 
sekunden ansteigt mit diesem code hier:

if (bit_is_clear(PIND, 3))
{
  Drehzahl_in_teile = 0;

  while (bit_is_clear(PIND, 3)) {};
  while ((bit_is_set(PIND, 3)) && (Drehzahl_in_teile < 65000))
Drehzahl_in_teile++;
}

Mit dem alten Code hier hingegen funktioniert es einwandfrei, dass die 
Werte am LCD mehrere Male pro Sekunde aktualisiert werden, ohne dass 
irgend ein anderer Programmteil geändert wurde.

if (bit_is_clear(PIND, 3) && freigabe_drehzahl == 0)
  {
    freigabe_drehzahl = 1;
    Drehzahl_in_teile = 0;
  }

  while ((bit_is_set(PIND, 3) && freigabe_drehzahl == 1))
  {
    Drehzahl_in_teile++;

    if (Drehzahl_in_teile > 65000)
    {
      freigabe_drehzahl = 2;
    }
  }

  if (bit_is_clear(PIND, 3) && freigabe_drehzahl == 2)
  {
    freigabe_drehzahl = 0;
  }

Will den ganz obigen neuen Code aber lieber verwenden, da er genauer ist 
als der untere, bezüglich wann der Beginn des High ist. Der µC läuft ja 
mit 16MHz und das Signal hat eine Periodendauer von maximal 50ms. Warum 
schaut es dann so aus, als ob der µC für mehrere Sekunden blockiert ist 
mit dieser Polling-Methode? Denkfehler im Code?

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.