Fehler in Integer-Berechnung

Gast #3664180
Lesenswert?
• ▲
▼
Moin,

ich habe hier folgende Funktion geschrieben. Urpsrünglich hatte ich sie 
für float Werte geschrieben, was auch funktioniert hat. Jetzt möchte ich 
sie auf Integer Werte umschreiben und bekomme falsche Werte. Sicherlich 
läuft ein Integer über oder so, aber ich weiss nicht wo.
1
#define PWM_TOP 1600
2

3
void SetPWM(uint8_t dutycycle)
4
{
5
  uint16_t _ocr1a = 0;
6
  // Fehlerhafte Eingabe abfangen
7
  if (dutycycle > 100) dutycycle = 100;
8
  if (dutycycle < 0)   dutycycle = 0;  
9
  
10
        //Vergleichswert berechnen
11
  _ocr1a = ((PWM_TOP*dutycycle) / 100); 
12
  
13
  sprintf(sbuf,"OCR1A: %u", _ocr1a);
14
  usb_send_str(sbuf);
15
  
16
  //Vergleichswert setzen
17
  OCR1A = _ocr1a;
18
}

Erwarten würde ich:
_ocr1a = 1600*50/100 = 80.000/100 = 800
Das Ergebnis ist:
_ocr1a = 144

Ich dachte erst, dass das Zwischenergebnis von 80.000 das Problem wäre, 
da es nicht in uint16_t passt. Aber die Berechnung mit uint32_t ergab 
das gleiche unsinnige Ergebnis.

Ich sehe meinen Fehler gerade echt nicht...

Viele Grüße,
Christian
#3664186
Lesenswert?
• ▲
▼
Probiers mal so. Unsinnigen Vergleich <0 kannste weglassen und dutycycle 
must du erst umwandeln.
1
   uint16_t _ocr1a = 0;
2
   // Fehlerhafte Eingabe abfangen
3
   if (dutycycle > 100) dutycycle = 100; 
4
         //Vergleichswert berechnen
5
   _ocr1a = (PWM_TOP/100)*(uint16_t)(dutycycle);
6
 ...
#3664188
Lesenswert?
• ▲
▼
Christian schrieb:
> Ich dachte erst, dass das Zwischenergebnis von 80.000 das Problem wäre,

Das ist auch das Problem. Die "Falle" in C ist, daß der Compiler erst 
rechnet, und danach in das Ergebnisformat umwandelt. In deinem Fall wird 
mit unsigned int (= uint16_t) gerechnet, und da passiert der Überlauf. 
Ob das falsche Ergebnis dann einem uint16_t oder einem uint32_t 
zugewiesen wird, ändert nichts mehr.

Willst du das vermeiden, musst du die Operanden casten:
1
_ocr1a = (((uint32_t)PWM_TOP*dutycycle) / 100);

Dann wird mit 32 Bit gerechnet, und alles wird gut (und dauert dafür 
länger).

Oliver
Gast #3664190
Lesenswert?
• ▲
▼
Stimmt der Vergleich kleiner Null macht jetzt in Festkommaarithmetik 
keinen sinn mehr ;-)

Ich hatte dutycycle auch schon im Funktionsaufruf als uint16_t 
deklariert. Das Ergebnis war das gleiche. ich Probiers nochmal mit 
deiner Rechenreihenfolge! Danke!
Gast #3664574
Lesenswert?
• ▲
▼
Christian schrieb:
> void SetPWM(uint8_t dutycycle)
> {
>   uint16_t _ocr1a = 0;
>   // Fehlerhafte Eingabe abfangen
>   if (dutycycle > 100) dutycycle = 100;
>   if (dutycycle < 0)   dutycycle = 0;
Wie soll dutycycle denn bitte kleiner 0 werden?
Tipp: void SetPWM(uint8_t dutycycle)
Was haben unsigned Datentypen fuer eine Eigenschaft?

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 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.