mikrocontroller.net

Forum: Compiler & IDEs uint16_t wertearray shiften


Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich hätte bezüglich Arrays einige Fragen, und hoffe daß Ihr mir 
weiterhelfen könnt.

System:
ATmega48
AVR Studio
GCC

Anforderung;
Ich möchte eine bestimmte Anzahl an Messdaten eines Sensors in ein Array 
schreiben den kleinsten und den größten Wert entfernen und anschließend 
den Mittelwert bilden. Jedesmal wenn ein neuer Wert dazukommt soll der 
älteste Wert aus dem Array entfernt werden.

Bsp.: Messwerttabelle ist 8 groß
Wertetabelle: 8; 20; 27; 21; 22; 21; 23; 22;
Auswertung: 20; 21; 22; 21; 23; 22;  --> 21(,5)
neuer Wert: (8 fällt raus) 20; 27; 21; 22; 21; 23; 22; 23
Auswertung:
.
.

Fragen:
Kann man in ein Array die Messwerte reinshiften oder muss man jedes mal 
alle Werte selbst um eine Stelle verschieben?

Gibt es fertige Funktionen für das Auffinden von min bzw max Werten in 
einem Array?

Ich hoffe ihr könnt mir helfen einen relativ optimalen Code zu 
produzieren.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So was machst Du mit einem Ringspeicher und einem Zeiger, der auf den 
aktuell ältesten Wert zeigt. Wenn ein neuer Wert reinkommt, an der 
Stelle speichern, auf die der Zeiger zeigt und den Zeiger entsprechend 
erhöhen. Wenn Du am Ende des Arrays angekommen bist, muss der Zeiger 
entsprechend wieder auf den Anfang gesetzt werden.

Für die Auswertung einfach jeweils das komplette Array in einer Schleife 
durchgehen (mit Index).

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes M.

Wenn ich das richtig verstanden habe entspricht der "Ringspeicher" einem 
Array. Ich verschiebe allerdings nicht die Werte sondern nur einen 
zeiger wo der älteste Wert zum überschreiben steht.
Oder gibt es da eine spezielle definition und handhabung für einen 
Ringspeicher"?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Norbert S. wrote:
> Wenn ich das richtig verstanden habe entspricht der "Ringspeicher" einem
> Array. Ich verschiebe allerdings nicht die Werte sondern nur einen
> zeiger wo der älteste Wert zum überschreiben steht.
Im Prinzip ist es genau das. Der "Ring" entsteht eben dadurch, dass 
nicht mehr mit den echten Array-Grenzen im Speicher gearbeitet wird, 
sondern dass ein Zeiger definiert, wo gerade der (virtuelle) Anfang bzw. 
das Ende des Arrays ist. Wenn der Zeiger eine der echten Array-Grenzen 
erreicht, muss er eben wieder an das andere Ende befördert werden.

> Oder gibt es da eine spezielle definition und handhabung für einen
> Ringspeicher"?
Eigentlich nicht... Es gibt aber ne Menge Beispiele. Ringspeicher werden 
z.B. gerne als Puffer für irgendwelche Sende- und Empfangsroutinen 
benutzt, wenn Zeichenfolgen verarbeitet werden sollen und nicht 
gewährleistet ist, dass die einzelnen Zeichen sofort nach Eintreffen 
bearbeitet werden können. Sollte im AVR-GCC-Tutorial und in der 
Codesammlung ein paar Anhaltspunkte geben...

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat irgendjemand einen Beispielcode, der ein Array als Ringspeicher 
benutzt, bei der Hand? Es genügt auch irgend ein Link mit so einem 
Beispiel.
Bei der Suche habe ich meistens nur ein Register als Puffer gefunden. 
Oder ich suche nach den falschen Stichworten.

Ihr würdet mir sehr helfen wenn ich nicht alles für mich neu erfinden 
muss.

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

Bewertung
0 lesenswert
nicht lesenswert
Was spricht gegen die gute alte Methode: Papier und Bleistift.
So kann man mal so ein Array aufeichnen und die Funktionsweise
durchschauen. Dann kommt man drauf, dass das eigentlich ziemlich
simpel ist:
#define MAX_WERTE 8
uint16_t Werte[ MAX_WERTE ];
uint8_t NextAdd;

void Add( uint16_t Wert )
{
  Werte[NextAdd] = Wert;
  NextAdd++;
  if( NextAdd == MAX_WERTE )
    NextAdd = 0;
}

Der Index NextAdd geht reihum und zeigt an, wo der nächste Wert
einzufügen ist. Ist er am Ende des Arrays angekommen, fängt
er wieder von vorne an und sorgt so dafür, daß immer der älteste
Wert überschrieben wird.

> Gibt es fertige Funktionen für das Auffinden von min bzw max
> Werten in einem Array?

Sowas wirst du ja wohl noch selbst schreiben können :-)
Falls nicht: Hier eine Funktion, die den kleinsten Wert
bestimmt
uint16_t min()
{
  uint8_t i;
  uint16_t tmp;

  tmp = Werte[0];
  for( i = 1; i < MAX_WERTE; ++i )
    if( Werte[i] < tmp )
      tmp = Werte[i];

  return tmp;
}

> relativ optimalen Code
Wenn du relativ optimalen Code haben willst, dann machst du deine
Auswertung nicht mit getrennten min, max und summe Funktionen, sondern
alles in einem Rutsch durch das Array.

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an alle!

Ich habe bei Zeiger irgendwie an Pointer usw.. gedacht und bin deshalb 
irritiert gewesen.

Die Funktionen (Funktion) für min, max, usw. waren eh nicht das problem, 
es hätte ja sein können das es da Funktionen gibt. Bin halt etwas 
verwöhnt von anderen Programmiersprachen.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich habe bei Zeiger irgendwie an Pointer usw.. gedacht und bin deshalb
> irritiert gewesen.

Das war ja auch gemeint. Der Beispielcode verwendet zwar einen Index, 
aber das geht mit einem Zeiger natürlich genauso.

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Lösung für die Messwerttabelle sieht nun so aus:
#define MW_SIZE 10

uint16_t mw_array[MW_SIZE];
uint8_t aeltester_wert_zeiger = 0;

uint16_t mw_tabelle( uint16_t Wert )
{
  mw_array[aeltester_wert_zeiger] = Wert;
  aeltester_wert_zeiger++;
  if (aeltester_wert_zeiger == MW_SIZE)
  {
    aeltester_wert_zeiger = 0;
  }

  uint8_t i = 0;
  uint16_t min = 0;
  uint16_t max = 0;
  uint16_t summe = 0;
  uint16_t schnitt = 0;

  min = mw_array[0];
  max = mw_array[0];
  summe = mw_array[0];
  for (i = 1; i < MW_SIZE; i++)
  {
    if(mw_array[i] < min )
      min = mw_array[i];

    if(mw_array[i] > max )
      max = mw_array[i];

    summe += mw_array[i];
  }
  schnitt = (summe - min - max) / (MW_SIZE - 2);

  return schnitt;
}

Danke nochmals für eure Hilfe!

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.