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.
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).
@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"?
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...
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.
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:
1 | #define MAX_WERTE 8
|
2 | uint16_t Werte[ MAX_WERTE ]; |
3 | uint8_t NextAdd; |
4 | |
5 | void Add( uint16_t Wert ) |
6 | {
|
7 | Werte[NextAdd] = Wert; |
8 | NextAdd++; |
9 | if( NextAdd == MAX_WERTE ) |
10 | NextAdd = 0; |
11 | }
|
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
1 | uint16_t min() |
2 | {
|
3 | uint8_t i; |
4 | uint16_t tmp; |
5 | |
6 | tmp = Werte[0]; |
7 | for( i = 1; i < MAX_WERTE; ++i ) |
8 | if( Werte[i] < tmp ) |
9 | tmp = Werte[i]; |
10 | |
11 | return tmp; |
12 | }
|
> 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.
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.
> 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.
Meine Lösung für die Messwerttabelle sieht nun so aus:
1 | #define MW_SIZE 10
|
2 | |
3 | uint16_t mw_array[MW_SIZE]; |
4 | uint8_t aeltester_wert_zeiger = 0; |
5 | |
6 | uint16_t mw_tabelle( uint16_t Wert ) |
7 | {
|
8 | mw_array[aeltester_wert_zeiger] = Wert; |
9 | aeltester_wert_zeiger++; |
10 | if (aeltester_wert_zeiger == MW_SIZE) |
11 | {
|
12 | aeltester_wert_zeiger = 0; |
13 | }
|
14 | |
15 | uint8_t i = 0; |
16 | uint16_t min = 0; |
17 | uint16_t max = 0; |
18 | uint16_t summe = 0; |
19 | uint16_t schnitt = 0; |
20 | |
21 | min = mw_array[0]; |
22 | max = mw_array[0]; |
23 | summe = mw_array[0]; |
24 | for (i = 1; i < MW_SIZE; i++) |
25 | {
|
26 | if(mw_array[i] < min ) |
27 | min = mw_array[i]; |
28 | |
29 | if(mw_array[i] > max ) |
30 | max = mw_array[i]; |
31 | |
32 | summe += mw_array[i]; |
33 | }
|
34 | schnitt = (summe - min - max) / (MW_SIZE - 2); |
35 | |
36 | return schnitt; |
37 | }
|
Danke nochmals für eure Hilfe!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.