Hallo Der Betreff ist bestimmt nicht optimal gewählt aber ich versuch mal zu erklären was ich gern machen würde. Eine Funktion in C welche AD-Kanäle (Atmega8) einliest und eine Mittelwertbildung durchführt. Es wird die Kanalnummer übergeben und als Rückwert bekommt man einen Mittelwert über z.B. 20 Werte des angewählten Kanals. Die Funktion wird alle 50ms aufgerufen. Der angewählten Kanal wird einmal gelesen und in ein Array für die Mittelwertbildung geschrieben. Es dauert also 20 X 50ms pro Kanal bis ein korrekter Mittelwert zurückkommt. Das alles funktioniert auch wunderbar mit einem Kanal aber wenn ich jetzt einen anderen Kanal wähle wird in das Array für die Mittelwertbildung natürlich Werte von einem anderen Kanal geschrieben und die Mittelwerte von allen Aufrufen ist daneben. Meine Idee wäre ein 2 Dimensionales Array in der Funktion. Die Kanalnummer 0-5 welche übergeben wird wäre der erste Index. Der zweite von 0-19 für die Werte der Mittelwertbildung selbst. Was haltet ihr davon? Wäre das die richtige/schöne Lösung oder kann man Arrays übergeben und so die Funktion mit unterschiedlichen AD-Kanälen ausführen. Ich fang erst wieder an mit C. Bin deshalb ein wenig eingerostet und freu mich über Lösungsvorschläge. Gruß und Danke Thomas
Thomas Webster schrieb: > Der Betreff ist bestimmt nicht optimal gewählt Naja, nachdem ich ihn gelesen hab, war ich gespannt, welche Frage sich wohl dahinter verbergen wird. ;-) > Meine Idee wäre ein 2 Dimensionales Array in der Funktion. Die > Kanalnummer 0-5 welche übergeben wird wäre der erste Index. Der zweite > von 0-19 für die Werte der Mittelwertbildung selbst. > Was haltet ihr davon? Wäre das die richtige/schöne Lösung oder kann man > Arrays übergeben und so die Funktion mit unterschiedlichen AD-Kanälen > ausführen. Diese Möglichkeiten würden beide funktionieren. Ich würde noch für die Kanal-Anzahl und die Anzahl an Werten, über die gemittelt wird, ein #define machen, damit man möglichst wenige Stellen anfassen muß, wenn sich diese Zahl mal ändern sollte. Magische Zahlen, die an mehreren Stellen im Code auftauchen, sind immer schlecht.
Ich bin inzwischen ur Agro. Mache bestimmt schon seit 3 Stunden rum und
finde den Fehler nicht.
Der Code unten macht das was ich vorgeschlagen habe. In Main wird die
AD_Read Funktion dreimal alle 50ms aufgerufen mit Kanal 0, 1 und 5.
Zurück soll dann der Mittelwert vom angewähltem Kanal.
Irgendwie funktioniert das mehr oder weniger. Einzelne Kanäle laufen
aber er verschluckt sich manchmal. Der Index 0 von beiden Arrays ist die
Kanalnummer welche von Main übergeben wird (0, 1 und 5)
Kanal 0 oder 1 allein läuft perfekt. 0 und 1 zusammen beeinflussen sich
gegenseitig und Kanal 5 allein kommt nur Müll.
Hier hat er irgendwie Probleme:
Mittel_Array[ADKanal][Zaehler[ADKanal]] = F_ADWERT;
Nach dieser Operation steht Bullshit in dem Array. Ich weiß aber nicht
warum da Kanal 0 und 1 einzeln funktionieren. Kann mir jemand ein Tip
geben?
Im Anhang auch Bilder vom Code!
Gruß
Thomas
// Variablen für Funktion AD_Read
uint8_t a;
uint16_t AD_Mittelwert;
uint16_t F_ADWERT;
uint16_t Zaehler[5];
uint16_t Mittel_Array[5][19];
// AD_Read Funktion
uint16_t AD_READ(uint8_t ADKanal)
{
//---- AD-Wert einlesen ---------------------------------
ADMUX = ADMUX + ADKanal;
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC) )
{}
F_ADWERT = ADCL;
F_ADWERT += (ADCH << 8);
ADMUX = ADMUX - ADKanal;
//---- AD Mittelwertbildung ----------------------------------
if (Zaehler[ADKanal]<20)
{
Mittel_Array[ADKanal][Zaehler[ADKanal]] = F_ADWERT;
Zaehler[ADKanal]++;
}
else{ Zaehler[ADKanal]=0; }
//---- AD Mittelwertberechnung --------------------------------
AD_Mittelwert = 0;
for(a=0;a<20;a++)
{
AD_Mittelwert = AD_Mittelwert + Mittel_Array[ADKanal][a];
}
AD_Mittelwert = AD_Mittelwert / 20;
return AD_Mittelwert;
}
Thomas Webster schrieb: > uint16_t Mittel_Array[5][19]; Wenn du 6*20 Werte speichern willst, solltest du das Array auch mit einer Größe von 6*20 Elementen anlegen und nicht mit 5*19. Entsprechendes gilt für das Zähler-Array.
Rolf Magnus schrieb: > Thomas Webster schrieb: >> uint16_t Mittel_Array[5][19]; Und da sind sie schon wieder, die Magic Numbers WARUM nimmst du kein #define
Uhhhh, ich Depp. Das passiert wohl wenn der Aktionismus morgens um 04.00 Uhr durch kommt. Das Programm funktioniert jetzt natürlich mit den [6][20] Arrays. Mit den Magic Numbers gebe ich dir 100% recht. Habe eben die Anzahl der Mittelwerte als Übergabewert and die Funktion übergeben. Jetzt kann man beim Aufruf schon entscheiden wie viele Mittelwerte (max.20) man möchte und die Magic Numbers sind fort. Danke für die Hilfe :) Thomas
Ich hätte es anders aufgezogen. Denn: da gehören immer ein paar Dinge zusammen. Kanalnummer, die Samples selber und die Stelle an die der nächste Sample zu schreiben ist bilden eine logische Einheit. Diese 3 Informationen gehören zusammen, so wie bei einem Geburtstag der Tag, Monat und Jahr zusammengehören. Die Einheit aus Tag, Monat und Jahr nennt man ein Datum. Hier in deinem Fall gibt es keine übliche Bezeichnung dafür, was dich aber nicht daran hindern soll dir eine zu definieren. Nennen wie sie einfach mal eine "Messung". Also definiere ich mir eine derartige Struktur
1 | struct messung_ |
2 | {
|
3 | uint8_t ADKanal; |
4 | uint8_t nextSample; |
5 | uint816_t ADSamples[NR_SAMPLES]; |
6 | };
|
Gut. Von diesen 'Messungen' hast du 6 Stück
1 | struct messung_ Messungen[NR_MEASUREMENTS]; |
und bei jedem Aufruf der ADC Routine übergibst du einen Pointer auf die jeweils aktuelle 'Messung' die fortgeführt werden soll.
1 | uint16_t AD_read( struct messung_* pMessung ) |
2 | {
|
3 | uint16_t value; |
4 | uint16_t middle; |
5 | uint8_t i; |
6 | |
7 | // welcher AD Kanal?
|
8 | ADMUX = ADMUX + pMessung->ADKanal; |
9 | ADCSRA |= (1<<ADSC); |
10 | while (ADCSRA & (1<<ADSC) ) |
11 | {}
|
12 | |
13 | value = ADCW; |
14 | |
15 | // Kanal wieder rausnehmen, damit ADMUX 'sauber' bleibt
|
16 | ADMUX = ADMUX - pMessung->ADKanal; |
17 | |
18 | |
19 | // Messung in die Samples einpflegen
|
20 | pMessung->nextSample++; |
21 | if( pMessung->nextSample == NR_SAMPLES ) |
22 | pMessung->nextSample = 0; |
23 | |
24 | pMessung->ADSamples[ pMessung->nextSample ] = value; |
25 | |
26 | |
27 | // Mittelwert ausrechnen
|
28 | middle = 0; |
29 | for( i = 0; i < NR_SAMPLES; i++ ) |
30 | {
|
31 | middle += pMessung->ADSamples[i]; |
32 | }
|
33 | middle /= NR_SAMPLES; |
34 | |
35 | return middle; |
36 | }
|
(benutz lokale Variablen, wenn es nicht viele sind und sie tatsächlich nur lokale Bedeutung haben!) und in main gibst du dann von deinen 6 'Messkanälen', die du korrekt Initialisiert hast, zb auf die ADC Kanäle 0, 1, 3, 4, 5 und 7
1 | struct messung_ Messungen[NR_MEASUREMENTS] = |
2 | { { 0, 0, { 0 } }, |
3 | { 1, 0, { 0 } }, |
4 | { 3, 0, { 0 } }, |
5 | { 4, 0, { 0 } }, |
6 | { 5, 0, { 0 } }, |
7 | { 7, 0, { 0 } } |
8 | };
|
einen nach dem anderen auf die ADC Routine
1 | int main() |
2 | {
|
3 | |
4 | ...
|
5 | |
6 | nrMeasurement = 0; |
7 | |
8 | while( 1 ) |
9 | {
|
10 | |
11 | nrMeasurement++; |
12 | if( nrMeasurement == NR_MEASUREMENTS ) |
13 | nrMeasurement = 0; |
14 | |
15 | value = AD_read( &Messungen[nrMeasurement] ); |
16 | |
17 | ...
|
18 | }
|
19 | }
|
die Funktion AD_read findet in der übergebenen Struktur (die Struktur wird in Form eines Pointers drauf übergeben) alles vor, was sie benötigt um die Messung durchzuführen und das Ergebnis korrekt einzuordnen. Und wenn du auf unterschiedlichen ADC-Kanälen unterschiedliche Anzahl an Samples zum Mittelwert zusammenfassen willst, dann ist auch das einfach möglich. Du erweiterst einfach die Struktur, so dass auch diese Information enthalten ist
1 | struct messung_ |
2 | {
|
3 | uint8_t ADKanal; |
4 | uint8_t nextSample; |
5 | uint8_t nrSamples; |
6 | uint816_t ADSamples[NR_SAMPLES]; |
7 | };
|
erweiterst die Funktion, so dass sie diese INformation benutzt, anstelle der Konstanten
1 | uint16_t AD_read( struct messung_* pMessung ) |
2 | {
|
3 | uint16_t value; |
4 | uint16_t middle; |
5 | uint8_t i; |
6 | |
7 | // welcher AD Kanal?
|
8 | ADMUX = ADMUX + pMessung->ADKanal; |
9 | ADCSRA |= (1<<ADSC); |
10 | while (ADCSRA & (1<<ADSC) ) |
11 | {}
|
12 | |
13 | value = ADCW; |
14 | |
15 | // Kanal wieder rausnehmen, damit ADMUX 'sauber' bleibt
|
16 | ADMUX = ADMUX - pMessung->ADKanal; |
17 | |
18 | |
19 | // Messung in die Samples einpflegen
|
20 | pMessung->nextSample++; |
21 | if( pMessung->nextSample == pMessung->nrSamples ) |
22 | pMessung->nextSample = 0; |
23 | |
24 | pMessung->ADSamples[ pMessung->nextSample ] = value; |
25 | |
26 | |
27 | // Mittelwert ausrechnen
|
28 | middle = 0; |
29 | for( i = 0; i < pMessung->nrSamples; i++ ) |
30 | {
|
31 | middle += pMessung->ADSamples[i]; |
32 | }
|
33 | middle /= pMessung->nrSamples; |
34 | |
35 | return middle; |
36 | }
|
und erweiterst die Messungen selber, so dass du angibst, wieviele Samples zu nehmen sind.
1 | struct messung_ Messungen[NR_MEASUREMENTS] = |
2 | { { 0, 10, 0, { 0 } }, |
3 | { 1, 15, 0, { 0 } }, |
4 | { 3, 3, { 0 } }, |
5 | { 4, 19, { 0 } }, |
6 | { 5, 20, { 0 } }, |
7 | { 7, 8, { 0 } } |
8 | };
|
Im Moment gibt es noch eine Einschränkung, dass du keine größere Zahl an Samples angibst als das Array groß ist. Aber auch dieses 'Problem' könnte man noch lösen. Codeorganisation und Datenstrukturen sind kein Selbstzweck, sondern bringen dir sauberen Code, der auch flexibel sind. Aber dazu muss man sein C kennen. Arrays sind gut, aber sie sind bei weitem nicht die einzige Möglichkeit um Struktur in Daten reinzubringen. Ganz im Gegenteil.
@ Karl Heinz Buchegger Huj, auch eine Interessante Lösung wenn auch für mich auf den ersten Blick deutlich komplexer da ich noch nie mit Strukturen gearbeitet habe. Was da ober passiert habe ich aber verstanden. Danke für den Lösungsvorschlag.
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.


