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
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