Forum: Compiler & IDEs Multi Instanz Funktion mit gleichem Array verwenden


von Thomas W. (ram99)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von Thomas W. (ram99)


Angehängte Dateien:

Lesenswert?

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;
}

von Rolf M. (rmagnus)


Lesenswert?

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.

von Michael A. (Gast)


Lesenswert?

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

von Thomas W. (ram99)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Thomas W. (ram99)


Lesenswert?

@ 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
Noch kein Account? Hier anmelden.