Forum: Mikrocontroller und Digitale Elektronik Dezimalwert aus A/D-Wert ableiten


von Torch M. (thelightener)


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

von Karl M. (Gast)


Lesenswert?

Yep,

baue eine CRC vor den ADC-Eingang.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Torch M. schrieb:
> if(i<=100)
>     {
>         val_array[i] = adc_value;

Das geht übrigens in die Hose. i kann hier den Wert 100 annehmen, das 
Array hat aber nur Platz für 100 Elemente.

von X4U (Gast)


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.

von Torch M. (thelightener)


Lesenswert?

Hallo,

danke für eure Rückmeldungen.

@Karl M.
Sprichst du von einer Hardware-Lösung?

@X4U
Kannst du mir evtl. ansatzweise erläutern, wie in meinem Fall eine 
Software-Hysterese aussehen soll?

MfG
thelightener

von hp-freund (Gast)


Lesenswert?

Torch M. schrieb:
> Software-Hysterese

diff = neuer_wert - alter_wert
wenn abs(diff) < diff_erlaubt
  dann neuer_wert = alter_wert

von Jacko (Gast)


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

von THOR (Gast)


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.

von H.Joachim S. (crazyhorse)


Lesenswert?

THOR schrieb:
> Wenn die letzte Stelle toggelt, lässt man die einfach weg.

Ändert nichts prinzipielles, es wird nur seltener.
Hysterese ist ne gute Lösung.

von Domenic (Gast)


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

von Torch M. (thelightener)


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

von hp-freund (Gast)


Lesenswert?

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.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Domenic schrieb:
> z.B. wert_alt*90%+wert_neu*90%

Du meintest vermutlich sowas wie:

alpha=0.9

wert = alpha*wert+(1.0-alpha)*adcwert

: Bearbeitet durch User
von Nosnibor (Gast)


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
}

von Torch M. (thelightener)


Lesenswert?

@Nosnibor
Funktioniert bestens, vielen Dank!

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.