Forum: Mikrocontroller und Digitale Elektronik FIFO-Buffer befüllung


von oliver (Gast)


Lesenswert?

Hallo!

ich habe vor, 30 int werte zu speichern. den neuesten Wert speichere ich 
mir an stelle 0 in einem array. die anderen schiebe ich durch.

Die Stellen [0] und [1] sind od, leider erhalte ich immer die gleichen 
Werte für die anderen Stellen.



meine Befüllung:

for(int i = 29; i >= 1 ;i--)
  {
    fifo_buffer[i] = fifo_buffer[i-1];
  }
fifo_buffer[0] = act_value;

von Karl H. (kbuchegg)


Lesenswert?

Im geposteten Minimalauschnnit ist nichts falsch (ausser das du deinem 
AVR unnötig Arbeit machst, indem du i als int definierst, ein uint8_t 
hätte es auch getan)
Das Problem liegt wieder mal in den nicht geposteten Codeteilen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> die anderen schiebe ich durch.
Das ist der falsche Ansatz für einen Fifo, weil die Verwaltung 
unglaublich viel Rechenleistung verbraucht.

In einem FIFO wandert nicht der Inhalt, sondern nur die Schreib- und 
Lese-Zeiger: http://www.lothar-miller.de/s9y/categories/51-Fifo

von oliver (Gast)


Angehängte Dateien:

Lesenswert?

Die anzahl der Werte soll evlt. ncoh erweitert werden auf eine Zahl, für 
die ich auf jeden fall einen int, evtl. einen unsigned int benötige. 
Werde ich alles zur einfacheren Bedienung Definen...

hier mal eine Datei im Anhang, an der man den Timerinterrupt und die 
aufgerufene fifo_handler funktion sieht.

von Karl H. (kbuchegg)


Lesenswert?

oliver schrieb:
> Die anzahl der Werte soll evlt. ncoh erweitert werden auf eine Zahl, für
> die ich auf jeden fall einen int, evtl. einen unsigned int benötige.

OK.
Gerade dann solltest du den FiFo auf jeden Fall auf einen Ringbuffer 
umstellen.


void fill_fifo( int value_dB,  int *fifo_buffer)

{
  for(int i = 29; i >= 1 ;i--)
  {
    fifo_buffer[i] = fifo_buffer[i-1];
    _delay_ms(50);
  }


30 mal 50 Millisekunden, macht 1500 Millisekunden. Und das bei einer ISR 
die alle 1000 Millisekunden aufgerufen werden soll. Das kann nicht gut 
gehen.

Aber abgesehen davon: Du machst viel zu viel in deiner ISR! Und dann 
noch dazu alles elends langsame Dinge!
So wirst du das Timing in deinem Programm nie unter Kontrolle kriegen


Aber zurück zum Problem.
Woher weißt du, dass nur die ersten beiden Werte im FiFo stimmen? Ich 
sehe nirgends etwas, was dir diesen Umstand verraten könnte.

von oliver (Gast)


Lesenswert?

dieser Umstand wird gesehen in meiner Ausgabe, die ich in meiner 
fill_fifo funktion mache.

Dort gebe ich das array komplett aus.
Die zeitliche Verzögerung war nur eine Idee. Ich habe es sogar mit einer 
Puffervariablen versucht. den wert in einem einzelnen int gespeichert, 
dann an eine andere stelle wieder eingetragen.

Ich weiß nicht, wo mein fehler ist...

von oliver (Gast)


Angehängte Dateien:

Lesenswert?

Der Bufferinhalt ist im Anhang als PNG

von Karl H. (kbuchegg)


Lesenswert?

oliver schrieb:
> dieser Umstand wird gesehen in meiner Ausgabe, die ich in meiner
> fill_fifo funktion mache.

Hmm.
Und wieso kann ich dann selbiges nicht auch sehen, wenn ich mir deine 
Funktion anschaue und analysiere?

> Dort gebe ich das array komplett aus.

Wo?
Wie?
Mit welchen Formatierungen?
Kann es sein, dass in der Ausgabe ein Fehler war?

Frageb über Fragen.

> Die zeitliche Verzögerung war nur eine Idee.

:-)
War mir schon klar.

Aber Tatsache ist, dass du wirklich viel zu viel in deiner ISR machst. 
Und dann auch noch auf die umständlichst mögliche Art und Weise. Was du 
da machst ist Beschäftigungstherapie für deinen µC.

Ach ja.
Eines wollte ich noch sagen.
Mit dem langen String bei der Ausgabe kommst du bedenklich nahe an die 
Grenze von 32 Charactern für s ran.
Nur mal so als Zwischeneinwand.

> Ich weiß nicht, wo mein fehler ist...

Du musst vor allen Dingen aufhören uns immer nur winzige Codeausschnitte 
zu zeigen.
Auch wenn hier keiner wirklich glücklich damit ist, es hilft nichts: Der 
komplette Code muss her. So wie er ist. So wie du ihn laufen lässt, 
damit du den Fehler siehst.

Alles andere ist: sich selbst und uns anlügen. Es ist sinnlos, wenn wir 
hier Fehler in Code suchen, der so nie läuft, oder wenn wir Fehler 
suchen, die durch die Interaktion des Codes mit anderen Codeteilen 
entstehen. So ist das nun mal bei globalen Variablen: Auch Codeteile, 
die scheinbar nichts damit zu tun haben, können über die globalen 
Variablen interagieren. Und sei es nur, weil dort irgendwo ein Array 
überlaufen wird.

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

> Ach ja.
> Eines wollte ich noch sagen.
> Mit dem langen String bei der Ausgabe kommst du bedenklich nahe an die
> Grenze von 32 Charactern für s ran.
> Nur mal so als Zwischeneinwand.


Bei einem Blick auf dein zwischenzeitlich geposteten Screenshot würde 
ich sogar sagen: Du bist drüber. Weit drüber. Und da das fifo_buffer 
Array ein daran benachbartes Array ist ....

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

> Hmm.
> Und wieso kann ich dann selbiges nicht auch sehen, wenn ich mir deine
> Funktion anschaue und analysiere?


Das hier nehme ich übrigens zurück.
Hab die Stelle mitlerweile gefunden

von oliver (Gast)


Lesenswert?

besten Dank für eure Stellungnahmen.

im Prinzip habe ich nur vor, in regelmaßigem(also 
timerinterruptgesteuertem) Intvervall den ADC eine Messung machen zu 
lassen. Dessen Ergebnis möchte ich in einem Array speichern. evlt werden 
es 300 sekunden mit 300 Werten. Also jede sekunde eine Messung.

Wenn ich im Interrupt den ganzen Code nicht ausführen darf, kann ich 
dann den Code in mein main schreiben, wo ich in meiner for(;;) ein vom 
Interrupt gesetztes flag abfrage und darauf hin funktionen wie read_adc, 
fill_fifo usw ausführe? Rechenintensität sollte doch so nicht abnehmen, 
macht nur die ISR selbst kleiner und beendet sich schneller. Dann wird 
der code zwar außerhalb der ISR ausgef. jedoch ist die rechenzeit die 
gleiche !?!

Danke für weitere Ratschläge!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> jedoch ist die rechenzeit die gleiche !?!
Klar, aber mal angenommen, du hast jetzt noch einen RS232-Empfang am 
Laufen. Dann könnte bei der Verwaltung des Puffers in der ISR einfach 
ein RS232-Interrupt verschlampt werden. Deshalb Interrupts kurz und 
knackig.

von Heinz (Gast)


Lesenswert?

Hallo

So könntest du deinen Buffer machen, spart Zeit:

#define BUFFER_SIZE      30


#define BUFFER_SUCCESS   0x00
#define BUFFER_OVERFLOW  0x01
#define BUFFER_EMPTY     0x02

int buffer[BUFFER_SIZE];
int bufferDataPoitner=0;

unsigned char fillBuffer(int value)
{
    if(bufferDataPointer>=BUFFER_SIZE-1)
    {
        return BUFFER_OVERFLOW;
    }
    buffer[bufferDataPointer]=newValue;
    bufferDataPointer++;
    return BUFFER_SUCCESS;
}

unsigned char getBufferVal(int *value)
{
    if(bufferDataPointer<0)
    {
        return BUFFER_EMPTY;
    }
    *value=buffer[bufferDataPointer];
    bufferDataPointer--;
    return BUFFER_SUCCESS;
}

lg

von Karl H. (kbuchegg)


Lesenswert?

oliver schrieb:

> Danke für weitere Ratschläge!


sieh dir mal folgende Version an
(Warnung: ungetesteter Code, direkt im Forum eingetippt)
1
#define NR_VALUES   30
2
3
uint32_t  avgSum;
4
uint16_t  adcBuffer[ NR_VALUES ];
5
uint16_t  actAdcNr;
6
float     avg;
7
8
void fillBuffer( uint16_t nextVal )
9
{
10
  adcActNr++;
11
  if( adcActNr == NR_VALUES )
12
    adcActNr = 0;
13
14
  avgSum -= adcBuffer[ actAdcNr ];
15
  adcBuffer[ actAdcNr ] = nextVal;
16
  avgSum += nextVal;
17
18
  avg = avgSum / (double)NR_VALUES;
19
20
#ifdef CHECK_VALUES
21
  // zu Kontrollzwecken
22
  over_threshold = 0;
23
  for( uint16_t = 0; i < NR_VALUES; ++i )
24
  {
25
    uint16_t j = i + actAdcNr;
26
    if( j >= NR_VALUES )
27
      j -= NR_VALUES;
28
 
29
    if( adcBuffer[j] > THRESHOLD_VALUE )
30
      over_threshold++;
31
    sprintf( s, "%02d: buffer[%02d]: %3d\r\n", i, j, adcBuffer[j] );
32
    uputs( s );
33
  }
34
  uputs( "\r\n" );
35
  sprintf( s, "avg: %f\r\n" , avg );
36
  uputs( s );
37
  sprintf( s, "over_threshold: %d\r\n", over_threshold );
38
  uputs( s );
39
#endif
40
}

Die Messwerte werden ganz einfach reihum im Array abgelegt. Dadurch, 
dass ich weiß, wo der letzte Wert abgelegt wurde (actAdcNr), weiß ich 
klarerweise auch, welches der älteste Wert im Buffer ist, er muss an der 
nächsten Stelle stehen. Also keine Angst, wenn das logisch 0-te Element 
nicht auch am Index 0 gespeichert ist. Das ist kein allzugrosses 
Problem, wie man in der Ausgabeschleife sieht.

Schau dir auch an, wie ich die ganze Summiererei für die 
Mittelwertberechnung durch Einführen einer weiteren Variablen 
vereinfacht habe. Ich hebe mir einfach die Summe der Werte auf. Kommt 
ein neuer dazu, dann wird der älteste aus der Summe rausgerechnet, dafür 
kommt dann der neue dazu. Und schon habe ich wieder die aktuelle Summe, 
ohne alle Messwerte aufsummieren zu müssen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ich hebe mir einfach die Summe der Werte auf. Kommt ein neuer dazu,
> dann wird der älteste aus der Summe rausgerechnet, dafür kommt
> dann der neue dazu.
Für eine einfache Mittelwertbildung wäre mir schon der Speicher für die 
letzten 300 Elemente zu schade. Da würde ich einfach ein RC-Glied 
nachbilden: http://www.lothar-miller.de/s9y/categories/21-Filter

von oliver (Gast)


Lesenswert?

Gibts ne Gegenüberstellung der Rechnezeiten bei dem System, wo ich das 
Array einzeln weiterschiebe und dem Buffer von euch?

Mich würde die Laufzeit interessieren, bei nem buffer von sagen wir 300 
Werten mit Durchschnittswertbildung.

Bin auf Antwort gespannt.

von Karl H. (kbuchegg)


Lesenswert?

oliver schrieb:
> Gibts ne Gegenüberstellung der Rechnezeiten bei dem System, wo ich das
> Array einzeln weiterschiebe und dem Buffer von euch?
>
> Mich würde die Laufzeit interessieren, bei nem buffer von sagen wir 300
> Werten mit Durchschnittswertbildung.
>
> Bin auf Antwort gespannt.

Schreib ein Testprogramm mit der einen Systematik. Lade es in den 
Simulator und lass dir die Taktzyklen für einen von dir gewählten 
Testfall ausgeben.

Dann dasselbe noch einmal für die andere Systematik.

Dann weißt du es genau.

von oliver (Gast)


Lesenswert?

meinst du den Simulator von AVRStudio?
Den kenne ich bisher noch nicht, sollte ich mir aber mal ansehen. Bisher 
habe ich geflasht, weil den MK2 kann man bequem stecken lassen auf dem 
entwicklungsboard.

von Karl H. (kbuchegg)


Lesenswert?

oliver schrieb:
> meinst du den Simulator von AVRStudio?
> Den kenne ich bisher noch nicht, sollte ich mir aber mal ansehen.

Solltest du.
Der hat einen wunderbaren Zyklencounter eingebaut, bei dem er dir genau 
sagt, wieviele Taktzyklen von einem Breakpoint zum nächsten vergangen 
sind.

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.