PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bascom Softwarehysterese bei ADC Messungen



Searcher
25.01.2013, 10:12
Vielleicht ist diese Routine trivial. Ich stell sie trotzdem mal als Miniprogramm hier rein, da sie mir eine echte Erleichterung beim Erfassen des Einstellwertes eines normalen Drehpotentiometers mit dem ADC gebracht hat.

Ziel des Programms ist es, den ADC (Analog Digital Converter) Meßwert eines AVR für die weitere Verwendung im Programm zu "beruhigen".

Wird eine Spannung, die am ADC Eingang anliegt, ständig im Loop oder per Interrupt gemessen, können die ausgelesenen Werte schwanken obwohl eigentlich keine Spannungsänderung stattgefunden hat. Selbst unter guten Bedingungen wie saubere Versorgungsspannung, saubere ADC Referenzspannung, saubere stabile zu messende Spannung, usw. treten solche Schwankungen auf. Grund dafür ist, daß der Wert der zu messenden Spannung genau zwischen zwei digitalen Werten liegen kann und der ADC sich unschlüssig ist, welchen digitalen Wert Wert er nun zuordenen soll. Ergebnis sind Meßwerte, die sich von einer Messung zur anderen im niederwertigsten Bit unterscheiden.

Es hilft nicht, das LSB (Least Significant Bit) des ausgelesenen ADC Wertes einfach abzuschneiden, da es auch da wieder eine analoge Spannung gibt, die wiederum zwischen zwei benachbarten digitalen Werten liegt und vom ADC nicht eindeutig zugeordnet werden kann bzw. zugeordnet wird.

Als Lösung hab ich im folgenden Code die Meßwerte nicht gemittelt sondern eine "Softwarehysterese" verwirklicht. Ein 10Bit ADC Meßwert (in der Variablen Adc_messwert) wird mit einem Referenzwert (Variable Alt_wert) verglichen. Nur wenn er sich um drei Einheiten von der Referenz unterscheidet wird er zur weiteren Verwendung im Programm übernommen (in der Variablen Neu_wert). Der Adc_messwert wird dann als neue Referenz benutzt. Dies bedeutet im Resultat aber auch eine Verringerung der Meßwertauflösung des ADC von 10 Bit auf 8 Bit; nun aber befreit von systembedingten Schwankungen.

Das Programm wurde auf einem ATMega88A getestet. Die zu messende Spannung wurde mit dem Schleifer eines 10k Drehpotentiometers am ADC Eingang eingestellt - die beiden anderen Anschlüsse des Potis an GND und VCC, AREF = VCC.
Die Hysterese ist natürlich für verschiedene Anwendungen anpaßbar. Ein Wert von 3 Einheiten hat sich bei dem 270° Drehwinkel Poti als praktisch erwiesen und unterdrückt in gewissen Grenzen auch noch Schwankungen, die von anderen Störeinflüssen wie zB Netzeinstreuungen herrühren. Die resultierende Auflösung von 8 Bit (256 Werte) über den Drehbereich des Potis ist noch gut handhabbar.

Auslöser zur Realisierung der "Softwarehysterese" waren meine Versuche mit einem Schrittmotor, dessen Drehzahleinstellung über Poti nicht sauber war. Auch empfehlenswert für zB. Servotester und ähnliche Anwendungen bei denen auf eine Mittelwertbildung verzichtet werden kann oder soll; kann natürlich auch noch nachgeschaltet werden.


'Softwarehysterese
'Schwankungsfreies Messen eines Potentiometers mit dem ADC
'mit ATMega88A aber leicht anpassbar auf andere µC

'IDE: BASCOM-DEMO Version 2.0.7.0
'10k potentiometer an VCC und GND, Schleifer an PC0 (ADC0)

$regfile = "m88Adef.dat"
$framesize = 32
$swstack = 32
$hwstack = 36
$crystal = 8000000 'CKDIV8 Fuse disabled
$baud = 9600 'Meßwertausgabe über UART (PD1/TXD) mit 9600 Baud

Dim Adc_messwert As Word 'Wird bei jeder Messung mit dem aktuellen 10 Bit ADC Messwert belegt
Dim Neu_wert As Word 'Enthält "entschwankten" Potentiometer Auslesewert (0..255)
Dim Alt_wert As Word 'Enthaelt Adc Messwert aus dem der Neu_wert erzeugt wurde
Dim Differenz As Integer 'Hilfsvariable

'Ports initialisieren - Alle Ports sind nach Einschalten auf Input.
Portd = Bits(pd7 , Pd6 , Pd5 , Pd4 , Pd3 , Pd2 , Pd1 , Pd0) 'PortD Pullups einschalten
Portc = Bits(pc5 , Pc4 , Pc3 , Pc2 , Pc1) 'PortC Pullups einschalten ohne PC0 weil ADC0
Portb = Bits(pb5 , Pb4 , Pb3 , Pb2 , Pb1 , Pb0) 'PortB Pullups einschalten

Config Adc = Single , Prescaler = Auto , Reference = Avcc

Do 'Anfang Hauptschleife
Adc_messwert = Getadc(0) 'Single Messung an ADC0 durchführen - liefert 10 Bit Wert von dezimal 0..1023
Differenz = Adc_messwert - Alt_wert 'Differenz zwischen aktuellem Messwert und verwendetem alten feststellen
If Abs(differenz) > 3 Then 'Hysterese hier von drei Einheiten = maximal Wert der beiden niederwertigsten Bits
Alt_wert = Adc_messwert 'Adc_messwert als neue Referenz für weitere Vergleiche sichern
Shift Adc_messwert , Right , 2 'Rausschieben der beiden unsicheren niederwertigsten Bits ergibt Zahl von 0..255
Neu_wert = Adc_messwert 'setzen der Ergebnisvariablen mit dem "entschwankten" Wert.
Print Neu_wert '"entschwankter" Wert liegt in Neu_wert vor und wird zur Kontrolle über UART ausgegeben
End If
Loop 'Ende Hauptschleife
End 'Programmende

Gruß
Searcher

oberallgeier
25.01.2013, 10:49
... im Resultat ... Verringerung der Meßwertauflösung des ADC von 10 Bit auf 8 Bit ...Und worin liegt der Vorteil gegenüber dem Auslesen des 8bittigen Wertes durch

• Bit 5 – ADLAR: ADC Left Adjust Result

ADLAR = 1 ??

Searcher
25.01.2013, 11:17
Und worin liegt der Vorteil gegenüber dem Auslesen des 8bittigen Wertes durch
• Bit 5 – ADLAR: ADC Left Adjust Result
ADLAR = 1 ??


Eine Messung wird mit 10Bit durchgeführt, nur das Ergebnis wird links justiert und die höchstwertigen 8 Bit können aus ADCH ausgelesen werden. Also nur ein einfaches Abschneiden der beiden LSBs

Mal angenommen, eine Messung ergibt
einen 10 Bit Wert von "00 0000 0011" (dezimal 3), dann würde mit ADLAR die "0000 0000" im ADCH stehen.
Ergibt die nächste Messung "00 0000 0100" (dezimal 4), würde mit ADLAR die "0000 0001" im ADCH stehen.

Im ADCH ergibt sich also eine Schwankung von "0000 0001", obwohl sich die 10 Bit Messung nur um das LSB geändert hat.

Mit Hysterese würde der Unterschied in der 10Bit Messung von 1 zu klein sein -> Schwankung im Resultat unterdrückt

Gruß
Searcher