Forum: Mikrocontroller und Digitale Elektronik ATMEGA8 und Long?


von Nn N. (jaytharevo)


Lesenswert?

Hallo,

also es geht darum aus vielen Werten einen Mittelwert zu berechnen.
Nun diese Werte können sich zwischen 0 und 20000 bewegen.
Sollte ich nun 4 mal 20000 hereinbekommen habe ich einen overflow,
da ein integer ja nur bis 65535 geht.
Nun wie initialisier ich einen long richtig auf dem ATMEGA8?
Vor einiger Zeit hatte ich ein ähnliches Problem, hab mich dann aber 
nicht weiter mit long beschäftig da ich einen anderen Lösungsansatz 
gefunden habe.
1
      //Algorithmus zur Leitungsberechnung
2
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
3
      
4
      uiMittelPuffer[iMittelCounter]=uiPuffer;
5
6
7
      if (iMittelCounter==2)
8
      {
9
        uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;
10
11
        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
12
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen
13
14
        //Typkonvertierung für "lcd_puts"- Funktion
15
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);
16
17
        iMittelCounter=0;
18
      }

uiMittelPuffer ist ein integer Array, folgendermaßen initialisiert 
zusammen mit uiPuffer:
1
unsigned int uiPuffer,uiMittelPuffer[4];

Ich würde den Mittelwert aber lieber aus mehr als 3 Werten ermitteln.
Kann mir jemand Helfen?

MFG Julian

von daniell (Gast)


Lesenswert?

int32_t
sollte reichen ist dann ein 32Bit int

von Nn N. (jaytharevo)


Lesenswert?

daniell schrieb:
> int32_t
> sollte reichen ist dann ein 32Bit int

Ok, dies wäre natürlich eine Möglichkeit.

Aber warum kann ich nicht einfach
1
 long lPuffer;
 schreiben?

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:
>
> Aber warum kann ich nicht einfach
1
 long lPuffer;
 schreiben?

Kannst du

uint32_t macht nur etwas klarer, dass du hier 32 Bit haben willst. Bei 
einem long alleine, weiß wieder kein Mensch auswendig, wieviele Bits das 
sind. Auf deinem AVR sind es 32, auf einem PC sind es wieviele?

Pass lieber auf, dass du hier
1
    uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;

nicht patzt :-)

von Nn N. (jaytharevo)


Lesenswert?

Hallo Karl,
kannst du dich ein wenig genauer ausdrücken?
Da ich es selber geschrieben habe bin ich der Überzeugung, dass es 
passt.
Also die Selbstkorrektur ist immer um einiges schwieriger ;).

Ich denk es mir so:
Ich addiere 3 Elemnte von diesem Feld um dividiere durch 3.
Somit sollte es eigentlich der Mittelwert sein.

MFG

von Nn N. (jaytharevo)


Lesenswert?

Hallo,
habe es nun so gelöst:
1
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
2
      
3
      uiMittelPuffer[iMittelCounter]=(uiPuffer<<2);
4
5
      // Mittelwertbildung
6
      if (iMittelCounter==3)
7
      {
8
        uiPuffer=uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2]+uiMittelPuffer[3];
9
10
        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
11
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen
12
13
        //Typkonvertierung für "lcd_puts"- Funktion
14
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);
15
16
        iMittelCounter=0;
17
      }

Die Division durch 4 lässt sich einfach durch das verschieben um 2 
Stellen
darstellen. Bevor die Werte nun ins Array gehen werden sie bereits 
ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow 
nahe kommt.

MFG

von Ampfing (Gast)


Lesenswert?

Hi Julian,

Julian Schild schrieb:
> Bevor die Werte nun ins Array gehen werden sie bereits
> ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow
> nahe kommt.
In Deinem Code teilst Du aber nicht durch 4, sondern multiplizierst 
damit.
Außerdem macht es sehr wohl einen Unterschied, ob Du erst alle Zahlen 
durch 4 teilst und dann aufsummierst, oder erst aufsummierst und dann 
durch vier teilst (Stichwort Ungenauigkeit)...
Generell gilt: möglichst spät dividieren.

Viele Grüße

von Nn N. (jaytharevo)


Lesenswert?

Ampfing schrieb:
> In Deinem Code teilst Du aber nicht durch 4, sondern multiplizierst
> damit.

Danke, du hast natürlich recht.

> Außerdem macht es sehr wohl einen Unterschied, ob Du erst alle Zahlen
> durch 4 teilst und dann aufsummierst, oder erst aufsummierst und dann
> durch vier teilst (Stichwort Ungenauigkeit)...
> Generell gilt: möglichst spät dividieren.

Auch hier hast du recht. Aber ab dem Wert 4 gibt es keinen Fehler mehr 
der bei einer späteren Division nicht auch auftreten würden.
Und wenn mein Wertebereich von 0-20000 geht , dann hab ich einen Fehler 
von 0.02%. Das sollte OK sein.

MFG

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:

> Die Division durch 4 lässt sich einfach durch das verschieben um 2
> Stellen
> darstellen.

Wenn du durch 4 dividieren willst, dann schreibe auch eine Division 
durch 4.

WENN diese Division auf dem Prozessor durch eine Veschiebung erreicht 
werden kann UND diese Schieberei tatsächlich schneller ist als 
Dividieren DANN weiß das der Compiler und ersetzt dir das auf 
Assemblerebene.

Generell: Benutze immer die Operation, die die Absicht am besten 
ausdrückt. An dieser Stelle ist die Absicht durch 4 zu dividieren. Also 
schreib auch Division.

 Bevor die Werte nun ins Array gehen werden sie bereits
> ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow
> nahe kommt.

Wozu dann der long?


Worauf ich hinaus wollte:
Bei deiner Summierung ist es völlig unerheblich ob du als 
Ergebnisdatentyp einen long hast oder nicht. Bei einer Operation 
betrachtet der Compiler die beiden Operanden. Nur deren Datentyp zählt 
bei der Auswahl der Operation.

  long i;
  int  j, k;

  i = j + k;

j ist ein int, k ist ein int. ALso wird die Addition mit einer 
int-Addition durchgeführt. Erst dieses Ergebnis wird auf long 
umgewandelt.

wenn also i gleich 32765 ist und k gleich 32765, dann hast du einen 
Overflow! Die Tatsache dass die Ergebnisvariable als long das richtige 
Ergebnis aufnehmen könnte, ist unerheblich. Dieser Datentyp long kommt 
erst dann ins Spiel, wenn das Kind (die Addition) schon in den Brunnen 
gefallen ist.

von Nn N. (jaytharevo)


Lesenswert?

Nachtrag der Richtigkeithalber:
1
uiMittelPuffer[iMittelCounter]=(uiPuffer/4);


@Franz:
Den Long wollte ich vorher haben. Jetzt brauch ich ihn natürlich nicht 
mehr.

Danke für dein Beispiel, das war mir nicht bewusst.



Noch mal zur Genauigkeit:
Durch, dass verschieben hätte ich nur einen Fehler wenn ich ganz kleine 
Werte bekomme, Werte im Bereich von 1-3.

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:

> Noch mal zur Genauigkeit:
> Durch, dass verschieben hätte ich nur einen Fehler wenn ich ganz kleine
> Werte bekomme, Werte im Bereich von 1-3.

Na ja.
Du hast immer dann Fehler, wenn sich die Einzelwerte nur um wenig 
unterscheiden.

   200 + 201 + 202 + 203 = 806 / 4 = 201

   200 / 4  + 201 / 4 + 202 / 4 + 203 / 4 = 50 + 50 + 50 + 50 = 200


wenn du damit leben kannst, ist es ok.

von Nn N. (jaytharevo)


Lesenswert?

Auch da hast du wieder recht.
Aber es tritt wie gesagt ein max. Fehler von 0.02% auf, mit welchem ich 
leben kann ;).


Noch ein mal, GROßES DANKE an dich Karl, hilfst mir immer wieder 
kompetent und schnell.

Danke.

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.