Dezimalwert aus A/D-Wert ableiten

OP #4874482
Lesenswert?

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 #4874510
Lesenswert?

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 #4874655
Lesenswert?

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 #4874932
Lesenswert?

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 #4874993
Lesenswert?

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 #4875430
Lesenswert?

@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 #4876465
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren