Problem mit Dividieren in C für AVR

Gast #1218290
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
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.
Gast
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?
Gast
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!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.