Forum: Mikrocontroller und Digitale Elektronik Problem mit Dividieren in C für AVR


von oles (Gast)


Lesenswert?

Hallo,

gerade programmiere ich zum ersten Mal einen Atmel AVR in C, da ich bei 
meinen aktuellen Projekt viele arithmetische Operationen mit großen 
Zahlen durchführen muss. Nur passiert dabei nicht so ganz das was ich 
möchte:

Um die Geschwindigkeit eines Fahrrads zu bestimmen, messe ich die Zeit, 
die ein Rad-Umlauf benötigt. Dazu lasse ich Timer0 mit einem Vorteiler 
von 256 laufen und zähle bei jedem Überlauf dieses Timers eine extra 
Variable hoch:


uint8_t volatile TimerHigh;


ISR(TIMER0_OVF_vect)
{
  if(TimerHigh!=0xFF)
  {
    TimerHigh++;
  }
}


Ist nun ein Rad-Umaluf beendet, wird folgende Berechnung ausgeführt:
uint32_t KMHTemp;

KMHTemp = (TimerHigh<<14);
KMHTemp |= (TCNT0<<6);
KMHTemp++;
KMHTemp = 7200000/KMHTemp; // 7200000 = 2000000 um * 3,6

KMHTemp soll zunächst die Umlaufdauer in usec enthalten. Dazu: Der 
Controller ist mit 4 MHz getaktet. TimerHigh:TCNT0:Prescaler 
repräsentiert die Zahl der "Takt-Ticks" (mir fällt gerade nicht das 
richtige Wort dafür ein), die ein Radumlauf gebraucht hat. Den Prescaler 
ignoriere ich einfach. Also ist der gesuchte Wert genähert 
(TimerHigh:TCNT0)*256. Ein "Takt-Tick" dauert bei 4 MHz 0,25 usec. Also 
ist die gesuchte Dauer in usec etwa (TimerHigh:TCNT0)*256/4 = 
(TimerHigh:TCNT0)*64 "= (TimerHigh:TCNT0) << 6". Damit KMHTemp nie 0 
ist, erhöhe ich es um 1. Um jetzt die Geschwindigkeit in km/h zu 
errechnen teile 2 m * 3,6 = 2000000 um * 3,6 = 7200000 durch KMHTemp.

Nun ist das Ergebnis dieser Rechnung seltsamerweise praktisch immer 0. 
Setze ich im Simulator (AVR-Studio) TimerHigh und TCNT0 auf solche Werte 
(0x2B und 0xF2), sodass sich nach Mulitplikation mit 64 und Addition von 
1 der Wert 720001 ergeben sollte, erhalte ich an Stelle von 10 (oder von 
mir aus auch 9, ich weiß nicht, wie er rundet) das Ergebnis 0.

Hat jemand eine Idee, woran das liegen könnte? Ich benutze 
WinAVR-20090313.



Beste Grüße
Ole

von Johannes M. (johnny-m)


Lesenswert?

oles wrote:
> KMHTemp = (TimerHigh<<14);
Kannst ja mal selbst überlegen, was passiert, wenn man einen 8-Bit-Wert 
um 14 Stellen nach links schiebt. Und bevor die üblichen Zweifel kommen: 
Nein, es ist völlig egal, welcher Datentyp links vom "=" steht. die 
Zuweisung wird als letztes gemacht. Selbst wenn der Compiler die 
Berechnung in int durchführt, bleibt nicht viel übrig.

von oles (Gast)


Lesenswert?

Ah, gut, das war mir nicht klar. Also dürfte es Abhilfe schaffen, erst 
mal alles in 32 bzw. 16 Bit breite ints zu schieben und dann erst die 
Zusammensetzung zum endgültigen 32 bit Wert vorzunehmen?

von oles (Gast)


Lesenswert?

Ah verdammt Schnellschuss... So sollte es auch ohne Zwischenspeichern 
gehen:
KMHTemp = TimerHigh;
KMHTemp = KMHTemp << 8;
KMHTemp |= TCNT0;
KMHTemp = KMHTemp << 6;
KMHTemp++;
KMHTemp = 7200000/KMHTemp;


Vielen Dank Johannes!

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.