mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mittelwert über 11 Messwerte


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo alle zusammen,

in meinem Programm bekomme ich eine Periodenzeit mit Hilfe des 16-Bit 
Timers. Ich möchte die gemessene Zeit über 11 Messungen addieren und 
davon dann den Mittelwert bilden. Wie baue ich das im Programm ein?

Vielen Dank
//#define F_CPU  16000000
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#include <avr/interrupt.h>


/*unsigned int read_ad(void)
{
  // Funktion zum Auslesen des A/D-Wandlers
    ADCSRA |= (1<<ADSC);  // Wandler starten
  while(!(ADCSRA & (1<<ADIF)));  //warten auf Wandler
  return ADCW;
}
*/

volatile uint16_t messung = 0;
volatile uint32_t periodenzeit;
volatile uint16_t start;
volatile uint16_t ende;
int i;



ISR(ADC_vect)        // Interrupt zum Auslesen des Wandlers
{
  messung = ADCW;



}


int main (void)
{
  DDRB = 0b01001000;
  

  ADMUX  = (0<<REFS1)|(1<<REFS0)|(1<<MUX0);  // Ref=AVCC, PA1
  ADCSRA = (1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);  // Wandler an
                    // Teiler 128 -> 125kHz Takt,
  
                      

 sei();                // Interruptverarbeitung AN
 
  
  lcd_init();
  //lcd_string("TESTPROGRAMM ADC");
  lcd_setpos(1,0);
  lcd_string("Wert: ");



  
  while(1)                // Hauptschleife
  {

  

  if (messung >= 200)      // ADC-Wert bei 200 Timer Starten
                
  {
      

      
      
        TCCR1B = (1<<CS12)|(1<<CS10);        // Timer-Konfiguration mit 1024 Vorteiler
      
        start=TCNT1;

  }

  else 

  {
          TCCR1B = (0<<CS12)|(0<<CS10);
          ende=TCNT1;

          periodenzeit=ende;
          TCNT1 = 0b00000000;

          


  }
    




    if((periodenzeit*0.064)>=585)    // pro Timer-Schritt = 0.000064 us
    {                  // Vergleich in Mikrosekunden
      
    
      PORTB = (1<<PB6);
      
    
        
       
    
    }
    else 
    {
      PORTB = (1<<PB3);
      
      
        
    } 


  

  lcd_setpos(1,5);
  lcd_int(messung);
  lcd_char(' ');
  lcd_setpos(1,10);
  lcd_int(0.064);
  
  //lcd_string("Wert: ");
  
  
  lcd_setpos(0,0);
  lcd_string("Zeit: ");
  lcd_setpos(0,5);
  lcd_int((TCNT1*0.064));
  lcd_setpos(0,10);
  lcd_int(periodenzeit);
  

  
  };
  return 0;
}







Autor: Jim M. (turboj)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Gegenfrage: Du weisst wie man in C ein Array programmiert?

Wenn "Nein": Buch über die Programmiersprace C besorgen und 
durcharbeiten.

Wenn "Ja": Array benutzen.

Autor: Stephan (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Warum ausgerechnet 11 Werte ?
1,2,4,8,16 usw. macht die DIV einfacher...schieben.

Autor: Pieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Warum ausgerechnet 11 Werte ?

warum sagt der TO nicht.
Auch nicht welche Werte zu mitteln sind.
Alles unklar.

Autor: Theor (Gast)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
@ Daniel
Ich würde Dir folgendes raten:

1. Überlege wie man einen Mittelwert auf dem Papier berechnet. Schau in 
einem Mathematik-Buch nach, falls Du Dich nicht mehr genau erinnerst, 
wie das geht.

2. Denke Dir ein paar zufällige Zahlen aus und rechne das einfach mal 
von Hand bzw. mit dem Taschenrechner.

3. Nimm auch ein paar Zahlen, bei denen Du am Ergebnis sofort siehst, 
dass die Rechnung richtig verlaufen sein muss! Etwa nur gleiche Zahlen. 
Oder Zahlen die, der Grösse nach geordnet, immer die gleiche Differenz 
zu dem Vorgänger und Nachfolger haben.

4. Versuche die wesentlich wichtigen Schritte, bei dieser Berechnung 
aufzuschreiben. Vielleicht ein einer Liste von nacheinander 
abzuarbeitenden Punkten.

5. Überlege Dir, wie Du das Papierverfahren in der Programmiersprache 
ausdrückst. Dabei sind folgende Fragen von entscheidender Bedeutung: A) 
Wie und wo werden die Werte abgespeichert. B) Gibt es bestimmte 
Gegebenheiten, die vor dem Beginn der Berechnung vorhanden sein müssen? 
C) Lassen sich, bestimmte Schritte als Wiederholungen formulieren? D) 
Wovon hängt die Anzahl dieser Wiederholungen ab?

Autor: Joachim B. (jar)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Stephan schrieb:
> Warum ausgerechnet 11 Werte ?
> 1,2,4,8,16 usw. macht die DIV einfacher...schieben.

genau
#define READS 5 // vielfache von 2^X READS 5 nimmt den Mittelwert aus 32 Messwerten
uint16_t lese_analog(uint8_t _port)
{ uint16_t _adc=0;
  for(i=0; i<(1<<READS); i++)
    _adc += analogRead(_port);    // read the input pin
  _adc >>= READS;  
#ifndef SCHNAUZE  
  DEBUG_PRINT(F("_adc: ")); DEBUG_PRINTLN(_adc);  
//  Serial.println();
  delay(500);
#endif
  return _adc;
}

noch besser wirds wenn man obere und untere Extremwerte nicht nimmt, ein 
Array + Sortalgorythmus und erste und letzte ausserhalb der Toleranz 
verwerfen

: Bearbeitet durch User
Autor: fop (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Also ein Array bräuchte ich nicht. Die einzelnen Werte will ja nachher 
keiner mehr wissen. Einfach die Summe in einer Variablen speichern. 
Dabei ein wenig aufpassen, dass die Variable genug Platz für die 
größtmögliche Zahl bietet.
Und natürlich darauf achten, dass es auch 11 Werte sind, die da 
aufaddiert werden.
Damit reduziert sich das Problem auf ein Teilen durch 11.

Wenn Du dann weißt wie, kannst Du Dich an einem Median-Wert der 11 
Messungen versuchen. Der bügelt Ausreisser durch Messfehler besser aus.
Und ab da kommen dann doch wieder die Arrays ins Spiel.

Autor: Joachim B. (jar)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
fop schrieb:
> Also ein Array bräuchte ich nicht

bist du der TO unter Doppelnamen?
Der TO stellt eine Frage und du antwortest brauche ich nicht?

fop schrieb:
> Die einzelnen Werte will ja nachher
> keiner mehr wissen

stimmt auch kann man wenn ausserhalb der Toleranz auch gleich vor dem 
Aufaddieren verwerfen, nur darf man dann nicht mehr durch die Anzahl der 
Durchläufe teilen!

fop schrieb:
> nd natürlich darauf achten, dass es auch 11 Werte sind, die da
> aufaddiert werden.
> Damit reduziert sich das Problem auf ein Teilen durch 11.

was unheimlich viel Zeit braucht u.U. übermäßig viel mehr als man hat 
gegenüber einem einfachen RECHTS Shift!

aber jeder wie er mag.

: Bearbeitet durch User
Autor: Arduino Fanboy D. (ufuf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim B. schrieb:
> was unheimlich viel Zeit braucht
> ....
> aber jeder wie er mag.

Wenn ich nicht auf jeden Takt schauen muss, ist dieses mein Arbeitsesel 
für solcherart Probleme.

Ist natürlich im Arduino Style, aber der Kern sollte sich auf C 
übertragen lassen.

    
    template<typename DatenType> 
    class GleitenderMittelwert   // eher ein Tiefpassfilter
    {
      private:
        const double factor;
        double mittelwert;
        
      public:
         GleitenderMittelwert(const double factor):factor(factor),mittelwert(0){}
         
         void setInitial(double value)
         {
             mittelwert = value;
         }
    
         operator DatenType() const
         {
            return mittelwert;
         }  
         
         DatenType doValue(DatenType value) // neuen Wert verarbeiten
         {
             mittelwert *= 1.0 - factor;
             mittelwert += factor * value;
             return  mittelwert;
         }
         
         DatenType operator= (DatenType value)
         {
             return doValue(value);       
         }
         
         DatenType operator() (DatenType value)
         {
             return doValue(value);       
         }
         
         DatenType operator() () const
         {
             return mittelwert;       
         }
    };
    


PS:
Hier sollte dann der Faktor 1.0/11.0 betragen.

: Bearbeitet durch User
Autor: Andi (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim B. schrieb:
> fop schrieb:
>> Also ein Array bräuchte ich nicht
>
> bist du der TO unter Doppelnamen?
> Der TO stellt eine Frage und du antwortest brauche ich nicht?

Wenn ich fop wäre würde ich dir antworten, dass das "bräuchte" eben im 
Konjunktiv steht, um anzudeuten, dass er es ohne Array machen würde, 
wenn er es machen würde oder der TO wäre.

Und nein ich bin nicht fop unter anderem Namen.

Autor: npn (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Andi schrieb:
> Und nein ich bin nicht fop unter anderem Namen.
Daniel unter anderem Namen?

Autor: Wolfgang (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Arduino F. schrieb:
> class GleitenderMittelwert   // eher ein Tiefpassfilter

Wenn es allerdings wirklich ein gleitender Mittelwert werden soll, käme 
man um ein Array, am einfachsten verwaltet als Ringpuffer, nicht 
drumrum.

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> äme
> man um ein Array, am einfachsten verwaltet als Ringpuffer, nicht
> drumrum.

Natürlich nicht. Wieso überhaupt diese panische Angst vor einem Array? 
Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte 
haben.

Georg

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
georg schrieb:
> Natürlich nicht. Wieso überhaupt diese panische Angst vor einem Array?
> Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte
> haben.

sogar für 64/32 Messwerte wo man nur 32/16 sammelt die innerhalb der 
Toleranz für einen Mittelwert liegen um wieder statt teilen shiften 
kann..

Autor: Arduino Fanboy D. (ufuf)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
georg schrieb:
> Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte

Ab wann wird es denn knapp?
Ab 1000 Integers?



georg schrieb:
> Wieso überhaupt diese panische Angst vor einem Array?
Wie immer:
Man wähle ein, der Aufgabe angemessenes, Verfahren.

Was soll das mit Angst zu tun haben?

Autor: Joachim B. (jar)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Ab wann wird es denn knapp?
> Ab 1000 Integers?

bein UNO oder nano 328p ja, der mega2560 kommt etwas weiter, der mighty 
mini 1284p hat SRAM über alles was man brauchen wird, den habe ich noch 
nie überlastet, den nano schon öfter da kratzen meine 
Programmiermöglichkeiten an dessen Grenzen.

Autor: Wolfgang (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Ab wann wird es denn knapp?
> Ab 1000 Integers?

Da wird es dann Zeit, auf einen anderen Arduino mit besserer 
RAM-Ausstattung zurückzugreifen, z.B. einen Arduino Due.
Ob solch eine hohe Zeitauflösung bei einem gleitenden Mittelwert 
sinnvoll erscheint, ist ein anderes Thema. Wenn die Daten derart 
verrauscht sind, das so ein Filter erforderlich ist, kann man meist auch 
erstmal einen kürzeres FIR davor schalten und für den gleitenden 
Mittelwert mit niedrigerer Abtastrate weiterrechnen.

Autor: Name H. (hacky)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Aber sicher nicht fuer einen duemmlichen Mittelwert. Ich wuerde zu einem 
exponentiellen Mittelwert greifen, der genau nur eine einzelne 
Speicherstelle benoetigt. Dazu siehe :
https://www.ibrtses.com/embedded/exponential.html
Da ist die Mittelungskonstante, dh Zeitkonstante, auch nur genau ein 
Wert.

Autor: Carsten R. (kaffeetante)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Eine der für mich wichtigsten Lektionen an der Uni war die 
Unterscheidung zwischen:

"Building the right thing vs. building the thing right"

Es gibt viele schöne Lösungen für verschiedene Probleme.
Aktuell ist noch völlig unklar was er wirklich braucht/will.

Beispielsweise ist völlig unklar ob er einen Mittelwert alle 11 Zyklen 
will (Summe bilden + Division, dann erneut von vorn beginnen) oder ob es 
ein gleitender Mittelwert mit 11 Zyklen rückblickend werden soll (in 
jedem Zyklus immer die aktuell letzten 11 Zyklen auswerten).

Autor: Joachim B. (jar)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Carsten R. schrieb:
> oder ob es
> ein gleitender Mittelwert mit 11 Zyklen rückblickend werden soll (in
> jedem Zyklus immer die aktuell letzten 11 Zyklen auswerten).

sowas hatte ich mal bei einer DFC77 Auswertung gemacht für die 1/0 
Erkennung
je nach Länge vom Kabel waren die Impulse verschliffen und durch 
Erwärmung verschob sich das auch noch.

Also die 1/0 Schwelle(100ms/200ms) sowie die Sekundenpause 800ms/1900ms 
immer über die Zeit nachjustiert, klappte ganz gut.
(war auch nötig um im Interrupt keine µs Störer zur Auswertung zu 
bringen)

: Bearbeitet durch User

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.