Dezimalwert aus A/D-Wert ableiten

OP #4874482
Hallo!

Ich benutze das Board STM32F407 und A/D-wandle mit 12-Bit eine 
Potispannung. Aus dem A/D-Wert möchte ich einen Wertebereich von 0…20 
realisieren. Dieser Wert soll dann binär auf 5 in Reihe gelöteten LEDs 
ausgegeben werden und gleichzeitig zum Einstellen eines anderen 
(Kraft-)Wertes dienen. Mein erster Ansatz war einfach den A/D-Wert durch 
200 zu teilen: 0…4095 / 200 = 0…20. Diese Lösung hat sich aber schnell 
als ungenügend bewiesen, da beispielsweise Werte zwischen 399…401 / 200 
aufgrund des Rauschens vom A/D-Wandler ständig toggeln. Dann habe ich 
den Ansatz über eine Mittelwertbildung probiert:
1
uint16_t Calculate_Force(uint16_t adc_value)
2
{
3
    static uint16_t calc_tmp=0, i=0;
4
    static uint16_t val_array[100];
5
    static uint32_t mean_value=0;
6

7
    if(i<=100)
8
    {
9
        val_array[i] = adc_value;
10
        i++;
11

12
        if(i>=100)
13
        {
14
            i = 0;
15
            while(i<=100)
16
            {
17
                mean_value += val_array[i];
18
                i++;
19
            }
20
            calc_tmp = mean_value/100;
21
            calc_tmp /= 200;
22
            i=0;
23
            mean_value=0;
24
        }
25
    }
26
    LED_ext_binary(calc_tmp);
27
    ClearFlag(&TimingFlags, SYSTICK_1000_HZ_PERIOD);
28
    return calc_tmp;
}

Das funktioniert zwar einigermaßen, hat das Problem aber noch nicht 
final gelöst. Es gibt immer noch Potistellungen, wo die berechneten 
Dezimalwerte toggeln. Hat evtl. jemand eine Idee bzw. kennt eine 
Möglichkeit, wie man trotz des A/D-Rauschens klar definierte Zustände 
erzeugen kann? Z.B. das Rauschen in derart „kompensieren“, dass ein 
gewisser Wertebereich über- bzw. unterschritten werden muss, bevor eine 
Dezimalstelle auf- bzw. abgezählt wird?

MfG
thelightener
Gast
Torch M. schrieb:
> Dann habe ich
> den Ansatz über eine Mittelwertbildung probiert:

...

> Das funktioniert zwar einigermaßen, hat das Problem aber noch nicht
> final gelöst.

Eine Mittelwertbildung bringt dir nichts da der Wert ja auch gemittelt 
toggeln kann. Dein "Rauschen" ist ja kein weißes sondern kommt von 
Störstrahlern wie der Netzfrequenz.

Besser geeignet ist m.E. eine Hysterese.
Gast
Wenn es am Netzbrumm liegt, solltest du z.B. 10 AD-Wandlungen
gleichverteilt in 20 ms (also alle 2 ms) durchführen und die
Ergebnisse summieren.
Diese Summe ist recht gut vom Netzbrumm befreit.

Ansonsten: Willst du wirklich 0..20, (21 Zustände),
oder 0..19 (20 Zustände, die üblichere Wahl) haben?

Entsprechend müstest du die 10-fache Summe
durch 1951 teilen - für 0..20, oder
durch 2048 teilen - für 0..19
Gast
Wenn die letzte Stelle toggelt, lässt man die einfach weg. 12 bit für 
ein Poti? Ich stelle ja sogar an den AVRs den 8-bit Modus ein obwohl die 
10bit ADCs haben.

Ein einzelnes Poti kannst du unmöglich so präzise drehen dass du das 
12te Bit alleine geändert bekommst.

Grob+Feinpoti ist was anderes.
Gast
Du könntest auch einen einfachen Filter machen:

z.B. wert_alt*90%+wert_neu*90%

es macht das ganze zwar träger, aber wenn man es schnell macht(z.B. 
200Hz+ abtastrate) merkt man sozusagen nichts, und durch das runden 
sollte es nicht  immmer hin und herspringen, wenn es noch zu viel 
springt, kann man den den alt anteil hochschrauben. Bei 90% alt Anteil 
braucht es rund 50 Rechnenzyklen um von bei einer Änderung von 0 auf 100 
beim Resultat auf 99 zu kommen. Ist nicht die schönste Lösung aber macht 
ihren Job gut, wenn man nichts kompliziertes will
OP
@hp-freund
Eine Hysterese in dieser Form habe ich schon versucht. Das Problem dabei 
war, dass ich meine Funktion jede ms aufrufe und der Differenzbetrag 
somit ca. jede ms neu berechnet wird. Da muss man schon verdammt schnell 
am Poti drehen, damit eine wirkliche Differenz zustande kommt ;-) Evtl. 
gibt es dafür ja einen Workaround, mir ist jedenfalls noch nichts 
eingefallen.

@Domenic
Werde ich mal probieren, danke.
 
MfG
thelightener
Gast
Torch M. schrieb:
> dass ich meine Funktion jede ms aufrufe

Warum ist das so?
Wenn Du diese Geschwindigkeit nicht brauchst, rufe die Funktion alle 20 
oder 50 ms auf.
Vielleicht wäre in diesem Fall sogar ein Drehgeber die bessere Wahl.
Gast
Torch M. schrieb:
> Eine Hysterese in dieser Form habe ich schon versucht. Das Problem dabei
> war, dass ich meine Funktion jede ms aufrufe und der Differenzbetrag
> somit ca. jede ms neu berechnet wird. Da muss man schon verdammt schnell
> am Poti drehen, damit eine wirkliche Differenz zustande kommt ;-) Evtl.
> gibt es dafür ja einen Workaround, mir ist jedenfalls noch nichts
> eingefallen.

Man muß für die Hysterese nicht die Differenz zum vorigen echten 
Messwert betrachten, sondern die Differenz zum aktuellen geglätteten 
Wert. Der bleibt ja die ganze Zeit konstant, bis ein Messwert weit genug 
abweicht, dann erst gibt es eine Änderung, egal wie oft man das 
zwischendurch berechnet.
Ungefähr so:
1
#define SCHWELLE 10
2
int hysterese(int messwert) {
3
   static int glattwert;
4
   if(abs(messwert - glattwert) > SCHWELLE)
5
       glattwert = Messwert;
6
   return glattwert;
7
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.