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


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.
von Torch M. (thelightener)


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


Bewertung
-1 lesenswert
nicht lesenswert
Yep,

baue eine CRC vor den ADC-Eingang.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


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


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


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


Bewertung
0 lesenswert
nicht lesenswert
Torch M. schrieb:
> Software-Hysterese

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

von Jacko (Gast)


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


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


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


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


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


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


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


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
@Nosnibor
Funktioniert bestens, vielen Dank!

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]
  • [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.