Die Nutzung des 10-Bit ADC


zurück zu Input/Output , PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage

Allgemeines
ADC einschalten
I/O-Pin Einstellung
Eingangsauswahl
ADC-Geschwindigkeit
Ergebnisformat
ADC starten
Arbeitspause
Messgenauigkeit
Beispiel


Allgemeines

Viele PICs besitzen einen ADC (Analog-Digital-Converter), der eine analoge Eingangsspannung (von 0V...5V) in einen 10-Bit Zahlenwert von 0 bis 1023 umwandelt. Dadurch lassen sich PICs für analoge Messaufgaben einsetzen.

Obwohl der PIC nur einen ADC besitzt, haben


Der ADC wird mit einem internen Schalter jeweils mit genau einem dieser Eingänge verbunden. Durch Umstellen dieses Schalters (per Software) lassen sich die Spannungen an allen Eingängen nacheinander messen.

Auf dieser Seite beziehe ich mich auf die PIC16F87x-Familie. Die ADCs anderer PICs funktionieren ähnlich, allerdings können die Eingangspins sowie die Adressen der ADC-Steuerregister abweichen.
Neben dem hier verwendeten 10-Bit-33kHz-ADC gibt es in anderen PICs auch ADCs anderer Auflösung und Geschwindigkeit.

Prinzipschaltbild des 10-Bit ADC der PIC16F87x

Referenzspannung
Ein ADC benötigt präzise Referenzspannungen für den Minimalwert (Vref-)und den Maximalwert (Vref+) der zu wandelnden Eingangsspannung. Jede Schwankung dieser Referenzspannungen verfälscht das Messergebnis. Für eine 10-Bit-Messung sollten die Referenzspannungen um weniger als 0,1% schwanken. Der PIC benutzt normalerweise Vss und Vdd (also Masse und Betriebsspannung des PIC) als Referenz. Eine Eingangsspannung, die Vss entspricht wird als 0 interpretiert, eine Spannung die Vdd entspricht wird in den Wert 1023 gewandelt. Alle dazwischen liegenden Spannungen werden dementsprechend in einen Zwischenwert gewandelt.
Bei einer Betriebsspannung von 5V hat der ADC also einen Arbeitsbereich von 0V...5V.

Sollte die Betriebsspannung nicht stabil genug sein, kann man externe Referenzspannungen für 0 und 1023 anlegen. Dafür werden die Pins verwendet, die normalerweise als analoge Eingänge AN2 (Vref-) und AN3 (Vref+) verwendet werden. Diese Eingänge stehen dann für Messungen nicht mehr zur Verfügung. Der PIC hat dann nur noch 3 bzw. 6 analoge Eingänge.

Legt man als untere und obere Referenzspannung andere Werte als 0V und 5V an, ändert man damit auch den Wandlerbereich des ADC. Dabei ist aber zu beachten:

Sehr flexibel ist der ADC also was seinen Eingangsspannungsbereich betrifft nicht.

Tests am PIC16F87x ergaben, dass die minimal zulässige Differenz zwischen Vref- und Vref+ stark vom ADC-Takt abhängt. Bei 16 kHz-ADC-Takt (32 kHz / 2) arbeitete er problemlos mit Vref-=0,9V und Vref+=2,5V (Differenz nur 1,6V). Bei 125 kHz-ADC-Takt (4 MHz / 32) lieferte der ADC bei gleichen Referenzspannungen nur noch "Müll". Mehrere PIC16F87x zeigten identisches Verhalten.
 

Steuerregister
Zum ADC gehören 4 Register im PIC. Über die Register ADCON0 (1Fh) und ADCON1 (9Fh) wird der ADC eingestellt und gesteuert. In den Registern ADRESH und ADRESL findet man nach erfolgreicher Wandlung das 10-Bit Messergebnis.

ADCON0: ADC CONTROL REGISTER 0 (ADDRESS 1Fh):


bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Name: ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/DONE - ADON

ADCON1: ADC CONTROL REGISTER 1 (ADDRESS 9Fh):


bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Name: ADFM - - - PCFG3 PCFG2 PCFG1 PCFG0

Außerdem sind die Register TRISA (& TRISE) für die I/O-Pin-Einstellung sowie INTCON , PIR1 und PIE für die Interrupteinstellung (falls Interrupt benutzt werden soll) zu beachten

nach oben


ADC einschalten

Der ADC des PIC lässt sich generell aus- und einschalten. Das ist als Stromsparfunktion zu verstehen. Ein eingeschalteter, aber nicht benötigter ADC verbraucht Strom, was sich durch Ausschalten vermeiden lässt. Will man den ADC benutzen, muss er natürlich eingeschaltet sein. Das erreicht man durch setzen des Bits 0 im Register ADCON0.

; ADC einschalten
    BSF      ADCON0, 0        ; ADON=1

Nach power-on oder Reset ist der ADC ausgeschaltet. Das Einschalten ist also zwingend nötig.

nach oben


I/O-Pin Einstellung

Natürlich war es nicht möglich Pins am, PIC-Gehäuse exklusive für den ADC zu reservieren. Die ADC-Eingänge sind Pins der Ports A und E. Diese können entweder als digitale I/O-Pins oder als analoge Eingänge verwendet werden. Will man Spannungen messen, muss man die zu verwendenden Pins zunächst auf 'analog' umschalten. Dies geschieht mit den Bits 0 bis 3 des ADCON1 -Registers. Nach einem Reset (oder nach dem Einschalten) sind diese Bits auf 0 gesetzt, wodurch automatisch alle vorhandenen Eingange als analoge Eingänge eingestellt sind.

ADCON1: ADC CONTROL REGISTER 1 (ADDRESS 9Fh):


bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Name: ADFM - - - PCFG3 PCFG2 PCFG1
PCFG0
Wert:
       
0 oder 1
0 oder 1
0 oder 1
0 oder 1

Die folgende Tabelle zeigt in Abhängigkeit der Bits 3..0, welche Eingänge dem ADC zur Verfügung stehen, und welche Referenzspannungen benutzt werden.
 

PCFG3-
  PCFG0
AN7-
RE2
AN6-
RE1
AN5-
RE0
AN4-
RA5
AN3-
RA3
AN2-
RA2
AN1-
RA1
AN0-
RA0
Vref+ Vref-
0000
A
A
A
A
A
A
A
A
Vdd
Vss
0001
A
A
A
A
 
A
A
A
RA3
Vss
0010
     
A
A
A
A
A
Vdd
Vss
0011
     
A
 
A
A
A
RA3
Vss
0100
       
A
 
A
A
Vdd
Vss
0101
           
A
A
RA3
Vss
011x
               
Vdd
Vss
1000
A
A
A
A
   
A
A
RA3
RA2
1001
   
A
A
A
A
A
A
Vdd
Vss
1010
   
A
A
 
A
A
A
RA3
Vss
1011
   
A
A
   
A
A
RA3
RA2
1100
     
A
   
A
A
RA3
RA2
1101
           
A
A
RA3
RA2
1110
             
A
Vdd
Vss
1111
             
A
RA3
RA2

Im TRISA / TRISE-Register sind die verwendeten analogen Eingänge als input einzustellen. Also müssen die den Pins zugeordneten TRIS-Bits auf 1 gesetzt werden. Ist ein analoger Eingang versehentlich als Ausgang programmiert, so misst der ADC den an diesem Pin erzeugten logischen Pegel (high/low), was ziemlich sinnlos wäre. Nach Reset und power-on sind alle TRIS-Bits auf 1 gesetzt, so dass man sich hier eventuell Arbeit sparen kann.

nach oben


Eingangsauswahl

Vor der Messung muss der ADC mit dem richtigen Eingang verbunden werden. Das geschieht mit den Bits 5 ..3 des Registers ADCON0.

ADCON0: ADC CONTROL REGISTER 0 (ADDRESS 1Fh):

 
bit 7
bit 6
bit 5
bit 4
bit 3
bit 2
bit 1
bit 0
Name:
ADCS1
ADCS0
CHS2
CHS1
CHS0
GO/DONE
-
ADON
Wert
   
0 oder 1
0 oder 1
0 oder 1
     

Die folgende Tabelle zeigt in Abhängigkeit der Bits 5..3, welcher Eingang dem ADC zugeschaltet ist:
 

Eingang / Pin
CHS2 (ADCON0,5)
CHS1 (ADCON0,4)
CHS0 (ADCON0,3)
Bemerkung
AN0 / RA0
0
0
0
 
AN1 / RA1
0
0
1
 
AN2 / RA2
0
1
0
 
AN3 / RA3
0
1
1
 
AN4 / RA5
1
0
0
 
AN5 / RE0
1
0
1
nur 16F871/4/7
AN6 / RE1
1
1
0
nur 16F871/4/7
AN7 / RE2
1
1
1
nur 16F871/4/7

Soll z.B. der analoge Eingang AN0 verwendet werden, ist in alle drei Bits der Wert 0 einzutragen.

; ADC-Eingang AN0 auswählen
    BCF      ADCON0, 5         ; ADCHS2=0
    BCF      ADCON0, 4         ; ADCHS1=0
    BCF      ADCON0, 3         ; ADCHS0=0

Wichtig, und oft vergessen: die "acqisition time"
Nach der Wahl des Eingangs wird der interne Kondensator am ADC-Eingang mit der am analogen Pin anliegenden Spannung geladen. Gemessen wird später die Spannung in diesem Kondensator. Deshalb muss man dem PIC nun genügend Zeit einräumen, den Kondensator komplett auf die neue Spannung aufzuladen, bevor man die eigentliche Messung auslöst. Wie lange diese 'acquisition time' dauern sollte, hängt von mehreren Parametern ab (z.B. vom Innenwiderstand der zu messenden Spannungsquelle). Typischerweise reichen 40 µs Pause aus. Wer es genau wissen will, findet in der Dokumentation zum PIC-Typ eine Formel zur Berechnung dieser Wartezeit.

Wird der Eingang zwischen zwei Messungen nicht gewechselt, dann ist auch eine Acquisition Time nötig, damit der Kondensator sich auf die geänderte Eingangsspannung aufladen kann. Da die Spannungsänderung zwischen zwei Messungen dabei aber vergleichsweise gering ausfallen wird, kann eine kürzere Acquisition Time (z.b. 10 µs) ausreichen.
 

nach oben

ADC-Geschwindigkeit

Der ADC benötigt für die Wandlung einen Arbeitstakt, der mit einem Frequenzteiler aus dem Takt des PIC abgeleitet wird. Der PIC-Takt kann aber zwischen wenigen kHz und 20 MHz liegen. Deshalb muss man je nach verwendetem PIC-Takt ein Frequenzverhältnis zwischen ADC-Takt und PIC-Takt einstellen. Das erfolgt mit den Bits 7 & 6 des Registers ADCON0. Die folgende Tabelle gibt an, welche Einstellung bis zu welcher Maximalfrequenz möglich ist. Die Einstellung '10' funktioniert z.B. bis zu einem PIC-Takt von 20MHz. Wird sie aber z.B. bei 1MHz verwendet, arbeitet der ADC 20 mal langsamer als bei 20 MHz. Deshalb sollte dann auf '00' umgeschaltet werden, was den ADC 16 mal schneller arbeiten lässt. Damit ist der ADC bei 1 MHz etwa gleich schnell wie bei 20 MHz.

Verwendet man aber '00' in einem mit 20 MHz getakteten PIC, wird der ADC mit einem Takt betrieben, bei dem der Wandler nicht mehr funktioniert.
 

PIC Takt ADCS1 ADCS0
0 ... 1,25 MHz
0
0
1,25 MHz ... 5 MHz
0
1
5 MHz ... 20 MHz
1
0
interner RC-Oszillator
1
1

Wird jeweils der schnellstmögliche PIC-Takt verwendet  (also z.B. 5 MHz bei Einstellung '01' oder 20 MHz bei Einstellung '10') dann benötigt der ADC 19,2 µs (12 ADC-Takte) für die Wandlung, und anschließend 3,2 µs Pause (2 ADC-Takte).

Soll sofort eine neue Messung der Spannung erfolgen, dann folgt aber zuerst etwas Zeit (Acquisition Time 10 .. 40 µs, je nach Typ und Eingangsbeschaltung), in der der interne Kondensator auf die inzwischen geänderte Eingangsspannung geladen wird. Erst danach kann der ADC wieder gestartet werden. Das ergibt eine maximale Samplefrequenz von immerhin 33 kHz bis 16 kHz (je nach acqisition time). Bei einem langsamerem Takt wird der ADC proportional langsamer.

; ADC speed für 20 MHz einstellen
    BSF      ADCON0, 7         ; ADCS1=1
    BCF      ADCON0, 6         ; ADCS0=0
 

Andere Typen als der 16F876
Der technische Fortschritt geht auch am ADC nicht vorbei. Neue PICs haben oft einen kürzere Acquisition Time oder einen höheren zulässigen ADC Takt als der 16F876. Dafür hier einige Beispiele:

nach oben

Ergebnisformat

Das 10-Bit-Messergebnis wird in den Registern ADRESH & ADRESL abgelegt, die zusammen aber 16 Bit lang sind. Mit dem Bit 7 des Registers ADCON1 lässt sich auswählen, ob die 10 Bit in den 16 Bit linksbündig oder rechtsbündig abgelegt werden. Nachfolgende Tabelle illustriert beide Möglichkeiten:
 
ADRESH
ADRESL
7
6
5
4
3
2
1
0
0
0
0
0
0
0
Bit 9
Bit 8
Bit 9
Bit 8
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
7
6
5
4
3
2
1
0
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
Bit 1
Bit 0
0
0
0
0
0
0

; Daten linksbündig
    BSF      STATUS,RP0        ; Bank1
    BCF      ADCON1, 7         ; ADFM=0
    BCF      STATUS,RP0        ; Bank0
 
Die unbenutzten Stellen werden in der Regel mit Nullen gefüllt.Es gibt aber Ausnahmen. Beim 16F684 haben die "freien" Bits bei rechtsbündiger Ausgabe den Wert des Bits 9. Man sollte sie also mit einem AND-Befehl ausblenden.

nach oben

ADC starten

Ist alles vorbereitet, kann der ADC  gestartet werden. Dafür setzt man das Bit 2 des Registers ADCON0 auf 1. Ist der ADC mit der Wandlung fertig, löscht er dieses Bit wieder. Durch zyklisches Abfragen dieses Bits kann man also herausbekommen, wann der ADC fertig ist.

;Eingangsspannung wandeln
    BSF    ADCON0, 2          ; ADC starten
loop
    BTFSC   ADCON0, 2          ; ist der ADC fertig?
    GOTO    loop               ; nein, weiter warten
 

nach oben


Arbeitspause

Nach getaner Arbeit braucht der ADC eine kleine Verschnaufpause, bevor er wieder benutzt werden kann. Wie lange, das hängt von der eingestellten ADC-Geschwindigkeit ab. Folgende Tabelle gibt die nötige Mindestpause in PIC-Takten an: (Tosc ist eine Schwingung des PIC-Taktes am Pin OSC1)
 

ADCS1
ADCS0
Wartetakte
0
0
4 Tosc
0
1
16 Tosc
1
0
64 Tosc
1
1
12 µs

Da ein typischer PIC-Befehl in 4 Tosc abgearbeitet wird, entspricht diese Wartezeit je nach Einstellung 1 ... 16 Befehlen. Oft wird deshalb diese Verzögerung im Programm sowieso auftreten. Nur wenn in der 20-MHz-Einstellung ('10') der ADC pausenlos abgefragt wird, könnte es zu einer Unterschreitung der Wartezeit kommen, und der ADC würde ungenaue Messwerte liefern. In diesem Fall ist eine kleine Warteschleife einzufügen.

nach oben


Messgenauigkeit

Eine Messung ist sinnlos, wenn man nichts über ihre Genauigkeit weiß. Ein 10-Bit-ADC kennt 1024 Abstufungen zwischen Minimum und Maximum, was seine Messgenauigkeit auf 0,1% limitiert. Da kein Bauteil perfekt ist, muss man noch mit 4..5 Stufen Linearitäts- und Offset-Fehler rechnen (näheres im Datenblatt). Damit kann der ADC aber immer noch 0,5% Genauigkeit im gesamten Messbereich garantieren.

Die Messung kann nicht genauer sein, als die Referenzspannung, auf deren Erzeugung entsprechend Aufmerksamkeit verwendet werden sollte. Wer die Referenzspannung aus der Betriebsspannung des PIC ableitet, sollte diese also gut stabilisieren. Ein 7805-Regulator kann 1% Genauigkeit erreichen.

Oft ist die zu messende Spannung selbst mit einer Schwingung verunreinigt. Dass passiert, wenn sie z.B. mit einem Schaltregler oder aus dem 50-Hz-Stromnetz (Trafo & Gleichrichter) erzeugt wurde. In diesen Fällen kann es von Vorteil sein, die Messung mit der  Schwingung zu synchronisieren.

Eine unsaubere Eingangsspannung lässt sich durch Mittelwertbildung aus vielen Messungen "glätten". Wenn man die Eingangsspannung 64 mal misst, und alle 10-Bit-Messergebnisse zusammenaddiert, bekommt man ein 16-Bit-Ergebnis. Die oberen 10-Bit davon sind die "gesiebte" Eingangsspannung.

Wer die Genauigkeit des ADC maximal ausnutzen will, sollte den PIC während der Messung nicht weiterarbeiten lassen, da sein schwankender Stromverbrauch den ADC stören könnte. Besser ist es den PIC nach dem Start des ADC sofort mit einem SLEEP-Befehl schlafen zu legen. Der ADC muss dann so konfiguriert werden, dass er am Ende der Messung sein Interrupt-Flag ADIF setzt, um den PIC wieder zu wecken. Damit das Aufwachen klappt müssen außerdem ADIE (im Register PIE1) und PEIE (im Register INTCON) auf 1 gesetzt sein (aber nicht GIE). Da im SLEEP-Modus der Takt nicht mehr zur Verfügung steht, muss als ADC-Taktquelle der interne RC-Oszillator gewählt werden!

Reichen die 10-Bit des ADC nicht aus, kann man auf 2 Wegen eine höhere Genauigkeit erreichen.

nach oben

Beispiel (identisch mit diesem Lernbeispiel)

Das folgende Beispielprogramm für einen mit 20 MHz getakteten PIC16F876 wandelt die am AN0/RA0 liegende Spannung in einen 10-Bit-Wert um, und zeigt die oberen 8 Bit des Ergebnisses an PortB an (LEDs). Als Referenz wird Vdd und Vss verwendet.

;**************************************************************
;*
;* Pinbelegung
;*    ---------------------------------- 
;*    PORTA:     0 analoger Eingang
;*        1 
;*        2 
;*        3 
;*        4 
;*    PORTB:    0 LED 
;*        1 LED 
;*        2 LED 
;*        3 LED 
;*        4 LED 
;*        5 LED 
;*        6 LED 
;*        7 LED 
;*    PORTC:    0 
;*        1 
;*        2 
;*        3 
;*        4 
;*        5 
;*        6 
;*        7 
;*
;**************************************************************
;
; sprut (zero) Bredendiek 04/2002
;
; ADC-Lernbeispiel:
;
; 16F876 wandelt die an RA0 anliegende Spannung in einen
; 10-Bit-Wert um
; die oberen 8 Bit des Wertes werden an PortB angezeigt
;
; Prozessortakt:  20 MHz
; Eingangsspannung: 0V ... 5V (Vss ... Vdd)
;
;**************************************************************
; Includedatei für den 16F876 einbinden

    list p=16f876
    #include <P16f876.INC>

    ERRORLEVEL      -302        ;SUPPRESS BANK SELECTION MESSAGES

;**********************************************************

; Variablen
wait    EQU    0x20

; Anfangsinitialisierung

init
; PortB vorbereiten
    bsf    STATUS, RP0  ; auf Bank 1 umschalten
    movlw  B'00000000'  ; PortB alle output
    movwf  TRISB
    bcf    STATUS, RP0  ; auf Bank 0 zurückschalten
    clrf   PORTB        ; alle LEDs ausschalten

; ADC einschalten
    BSF    ADCON0, 0    ; ADON=1

; ADC-Eingang AN0 auswählen
    BCF    ADCON0, 5    ; ADCHS2=0
    BCF    ADCON0, 4    ; ADCHS1=0
    BCF    ADCON0, 3    ; ADCHS0=0

; ADC speed für 20 MHz einstellen
    BSF    ADCON0, 7    ; ADCS1=1
    BCF    ADCON0, 6    ; ADCS0=0

; Daten linksbündig
    BSF    STATUS,RP0   ; Bank1
    BCF    ADCON1, 7    ; ADFM=0
    BCF    STATUS,RP0   ; Bank0
 

;**********************************************************
; Hauptprogrammschleife

Main
;Eingangsspannung wandeln
    BSF     ADCON0, 2     ; ADC starten
loop
    BTFSC    ADCON0, 2    ; ist der ADC fertig?
    GOTO     loop         ; nein, weiter warten

; Wert nach PortB schreiben
    movfw    ADRESH       ; obere 8 Bit auslesen
    movwf    PORTB        ; obere 8-Bit nach PortB

; Warten, damit der ADC sich erholen kann
    clrf     wait
warten
    DECFSZ   wait, f
    goto     warten

    goto     Main

    end
;**********************************************************

nach oben

zurück zu Input/Output , PIC-Grundlagen , PIC-Prozessoren , Elektronik , Homepage

Autor: sprut
erstellt: 10.04.2002
letzte Änderung: 07.08.2012