Rechnen mit große integer Zahlen beim ATMega328P

Gast #6615770
Lesenswert?

Hallo Leute,

Ich versuche mich grad in C und die Entwicklung von Programmen für den 
ATMega328P einzuarbeiten. Jetzt habe ich ein kleines Problem mit dem 
Casten von großen Integer Zahlen bzw. mit dem Rechnen großer Integer 
Zahlen. Konkret geht es um diese beiden Zeilen:
1
 uint16_t pwm1 = ((Hall1-Min1)/(Max1-Min1))*1023;
1
 uint8_t pwm2 = ((Hall2-Max2)/(Min2-Max2))*255;

Hall1 und Hall2 sind Analogwerte, die vom Hallsensor mit der ADC_R 
Funktion eingelesen werden. Diese Werte sollen dann mit obiger Formel in 
einen neuen Wertebereich berechnet werden. Hab das so von der Arduino 
IDE übernommen, da gibts nämlich die MAP Funktion, die im Grunde 
genommen das Gleiche ist.


Ich habe nun das Problem, dass bei ((Hall1-Min1)/(Max1-Min1))*1023 das 
Ergebnis 0 wird, weil (Hall1-Min1)/(Max1-Min1) gleich 0, irgendwas ist. 
Wenn ich es anders schreiben, so z. B. (Hall1-Min1)*1023)/(Max1-Min1) 
wird das Zwischenergebnis (Hall1-Min1)*1023) größer als 16 Bit. Um 
später aber meinen PWM Dutycycle einstellen zu können brauche ich eine 
16Bit Zahl.

Ich habe auch schon probiert das Ergebnis in einer 32-Bit variable zu 
speichern. Wenn ich diese dann allerdings an OCR1A übergebe, gibt mir 
meine Uart Schnittstelle keine richtigen Werte aus und meine PWM 
Dutycycle passt auch nicht. Jetzt müsste ich vermutlich mit einem Cast 
arbeiten oder? Ich habe das schon probiert und im Internet etwas 
recherchiert, habe aber noch keine zufriedenstellende Lösung gefunden. 
Kann mir da jemand weiterhelfen? Wahrscheinlich ist das Ganze einfach zu 
lösen, aber ich stehe schon mehrere Stunden auf dem Schlauch und komme 
nicht weiter...

Wäre sehr dankbar, wenn jemand den ein oder anderen Ratschlag dazu 
hätte.


1
while(1)
2
  {
3
    ADC1 = ADC_R(1); //read Hall1 Signal
4
    
5
    char Buffer[20];              
6
    sprintf(Buffer, "ADC1:%i", ADC1); //only for tests
7
    uart_puts(Buffer);
8
    _delay_ms(2000);    //delete for normal operation
9
    uart_puts("\r\n"); 
10
    
11
    
12
    uint16_t pwm1 = ((ADC1-Min1)/(Max1-Min1))*1023; //change of value range
13
    if(pwm1 > 1023){pwm1 = 1023;} //only for testing
14
    else if(pwm1 < 0){pwm1 = 0;}
15
    OCR1A = pwm1; //set duty cycle
16
      
17
      sprintf(Buffer, "PWM1:%i", pwm1);
18
      uart_puts(Buffer);
19
      _delay_ms(3000);    //delete for normal operation
20
      uart_puts("\r\n");
21

22

23
    ADC2 = ADC_R(0); //read Hall2 Signal
24
    
25
    sprintf(Buffer, "ADC2:%i", ADC2);
26
    uart_puts(Buffer);
27
    _delay_ms(2000);    //delete for normal operation
28
    uart_puts("\r\n");
29
    
30
    uint8_t pwm2 = ((ADC2-Max2)/(Min2-Max2))*255; //change of value range
31
    if(pwm2 > 255){pwm2 = 255;} //only for testing
32
    else if(pwm2 < 0){pwm2 = 0;}
33
    OCR0A = pwm2; //set duty cycle
34

35
      //char Buffer[20];              //only for tests
36
      sprintf(Buffer, "PWM2:%i", pwm2);
37
      uart_puts(Buffer);
38
      _delay_ms(3000);    //delete for normal operation
39
      uart_puts("\r\n"); 
40
  }
#6615809
Lesenswert?

basti schrieb:
> Wenn ich es anders schreiben, so z. B. (Hall1-Min1)*1023)/(Max1-Min1)
> wird das Zwischenergebnis (Hall1-Min1)*1023) größer als 16 Bit. Um
> später aber meinen PWM Dutycycle einstellen zu können brauche ich eine
> 16Bit Zahl.

Nur der Vollständigkeit halber, falls es doch mal zeitkritischr wird: 
Rechne das Zwischenergebnis in 32 bit, und das Endergebnis der Division 
castest du dann wieder nach 16 bit.

Oliver
#6615835
Lesenswert?

Wenn Du das Problem zerlegst, wirst Du feststellen, dass bei der 
Subtraktion nichts passieren kann.
Natürlich nur wenn beide Werte brav im positiven Bereich rumhängen.
Die Sache mit der Multiplikation hast Du aber falsch angepackt.
Hier gilt: Möglichst früh multiplizieren!
Das kann allerdings bedeuten, das der jeweilige Bereich uint16_t bzw. 
uint8_t, VOR der Division nicht, ausreicht.
Also besser:
((Hall1-Min1)*1023)/((Max1-Min1)*1023);
statt:
((Hall1-Min1)/(Max1-Min1))*1023;

Muss aber nicht sein.
Gast #6616113
Lesenswert?

Wolfgang schrieb:
> Ich habe noch keinen 10- bzw. 8-Bit Wandler gesehen, der 1024 bzw. 256
> ausgeben kann.

Natürlich nicht. Aber das sind die Endwerte. Ein 8bit Wandler skaliert 
die Wert 0..255, was 256 mögliche Werte ergibt. Deshalb.

Wenn also das Ausgangssignal 157 ist, heisst das, das Analogsignal ist 
grösser 157/256, aber kleiner als 158/256-stel der Referenz.
#6616434
Lesenswert?

Peter D. schrieb:
> Ich habe mir angewöhnt, Analogwerte in float zu rechnen.

und ich bleibe lieber bei int mit mV(milliV) dV(deziV) oder cV(centiV)

Nötige Konstanten kann man vorher rechnen und einsetzen, dezimal Punkte 
oder Komma kann man hinterher locker als Char einfügen ohne int zu 
verlassen. Die float Lib muss auch nicht eingebunden werden!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren