mikrocontroller.net

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


Autor: oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

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

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: oliver (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

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

Bewertung
0 lesenswert
nicht 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.

Autor: oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: oliver (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Der Bufferinhalt ist im Anhang als PNG

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

Bewertung
0 lesenswert
nicht 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.

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

Bewertung
0 lesenswert
nicht 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 ....

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

Bewertung
0 lesenswert
nicht 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

Autor: oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Heinz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

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

Bewertung
0 lesenswert
nicht lesenswert
oliver schrieb:

> Danke für weitere Ratschläge!


sieh dir mal folgende Version an
(Warnung: ungetesteter Code, direkt im Forum eingetippt)

#define NR_VALUES   30

uint32_t  avgSum;
uint16_t  adcBuffer[ NR_VALUES ];
uint16_t  actAdcNr;
float     avg;

void fillBuffer( uint16_t nextVal )
{
  adcActNr++;
  if( adcActNr == NR_VALUES )
    adcActNr = 0;

  avgSum -= adcBuffer[ actAdcNr ];
  adcBuffer[ actAdcNr ] = nextVal;
  avgSum += nextVal;

  avg = avgSum / (double)NR_VALUES;

#ifdef CHECK_VALUES
  // zu Kontrollzwecken
  over_threshold = 0;
  for( uint16_t = 0; i < NR_VALUES; ++i )
  {
    uint16_t j = i + actAdcNr;
    if( j >= NR_VALUES )
      j -= NR_VALUES;
 
    if( adcBuffer[j] > THRESHOLD_VALUE )
      over_threshold++;
    sprintf( s, "%02d: buffer[%02d]: %3d\r\n", i, j, adcBuffer[j] );
    uputs( s );
  }
  uputs( "\r\n" );
  sprintf( s, "avg: %f\r\n" , avg );
  uputs( s );
  sprintf( s, "over_threshold: %d\r\n", over_threshold );
  uputs( s );
#endif
}

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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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

Bewertung
0 lesenswert
nicht 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.

Autor: oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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

Bewertung
0 lesenswert
nicht 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.

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.