mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATMEGA8 und Long?


Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht 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.
      //Algorithmus zur Leitungsberechnung
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
      
      uiMittelPuffer[iMittelCounter]=uiPuffer;


      if (iMittelCounter==2)
      {
        uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;

        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen

        //Typkonvertierung für "lcd_puts"- Funktion
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);

        iMittelCounter=0;
      }

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

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

MFG Julian

Autor: daniell (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int32_t
sollte reichen ist dann ein 32Bit int

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht 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
 long lPuffer; 
 schreiben?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Julian Schild schrieb:
>
> Aber warum kann ich nicht einfach
 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
    uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;

nicht patzt :-)

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
habe es nun so gelöst:
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
      
      uiMittelPuffer[iMittelCounter]=(uiPuffer<<2);

      // Mittelwertbildung
      if (iMittelCounter==3)
      {
        uiPuffer=uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2]+uiMittelPuffer[3];

        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen

        //Typkonvertierung für "lcd_puts"- Funktion
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);

        iMittelCounter=0;
      }

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

Autor: Ampfing (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag der Richtigkeithalber:
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.