Das Wichtigste an Mikrocontrollern sind die Ein- und Ausgänge (kurz engl. IOs). Mit ihnen wird gesteuert, geregelt – kurz: Mit der Außenwelt kommuniziert. Ein Mikrocontroller hat immer natürlich immer eine begrenzte Anzahl an IO-Pins zur Verfügung. Dabei darf man nicht den Trugschluss ziehen, dass die Anzahl der Pins des Gehäuses gleich der Anzahl der IO-Pins entspricht. Dies ist nicht der Fall: PIC-Mikrocontroller haben grundsätzlich ein 8 Bit breites IO-Register. Das bedeutet pro Register sind (maximal) acht Ein- und/oder Ausgänge vorhanden.
Diese Register haben die Bezeichnung PORT mit einem nachfolgenden Buchstaben für die eindeutige Identifizierung des Ports (z.B. PORTA oder PORTE). Der PIC betrachtet die PORT-Register wie jedes andere Register auch. Nun kann ein Pin natürlich nicht Aus- und Eingang gleichzeitig sein, sondern muss auf eines der beiden definiert bzw. eingestellt werden. Dieses geschieht in den zugehörigen TRIS-Registern. Jedes PORT-Register hat also ein zugehöriges TRIS-Register. Dabei entspricht eine logische 1
(also High) einem Eingang und eine 0
(Low) einem Ausgang. Das lässt sich relativ einfach merken: Die 1
sieht ähnlich aus wie ein groß geschriebenes I
und steht folglich für Input
. Anders herum ist eine 0
ähnlich einem großem O
und steht demnach für Output
. Nachfolgend eine Grafik zum Veranschaulichen der Zusammenhänge:
Die Ein- und Ausgänge des PIC arbeiten i.d.R. mit TTL-Pegeln (Low = 0V, High = 5V bzw. 3,3V). Teilweise werden mehrere Funktionen auf ein und den selben Pin gelegt. So können zum Beispiel bestimmte Eingänge auch als Analogeingang benutzt werden, während man andere Pins wiederum zum Ausgeben eines PWM-Signals verwenden kann. Es gibt eine Vielzahl an Funktionen, die sich von PIC zu PIC unterscheiden und beim Programmieren bzw. beim Entwerfen des Schaltplans zur Schaltung berücksichtigt werden müssen. Hier unterscheiden sich die vergleichsweise kleinen 8-Bit Mikrocontroller stark von z.B. 32-Bit Controllern mit ARM-Kernen, die dann oftmals viele der verfügbaren Funktionen an einen beliebigen GPIO routen können. Das ist natürlich sehr komfortabel und eröffnet einem viele Freiheiten beim Layout. Auf der anderen Seite führt das zu wesentlich komplexeren internen Strukturen, die dementsprechend auch im Programmcode konfiguriert werden müssen 😉
Bei PIC-Mikrocontrollern ist dies dagegen relativ simpel und man hat mit wenigen Registern in der Regel “alles” im Griff. Dennoch gibt es immer wieder auch hier Fallstricke, die einem gerne auch mal 1..2 Stunden Arbeit kosten können. Vergisst man zum Beispiel bei einem PIC zu Beginn Eingänge von Analog auf Digital umzuschalten, dann funktioniert unter Umständen das Programm nicht wie man es erwarten würde. Genau dieses Problem kommt sehr häufig vor, daher sei es hier einmal stellvertretend erwähnt 🙂
Des Weiteren ist es wichtig zu beachten, dass ein Pin eines Mikrocontrollers nur einen begrenzt hohen Strom liefern kann. Am Beispiel des PIC16F62x liegt dieser Wert bei maximal
25mA
. Weiter gibt es einen Gesamt-Maximalstrom, der für den gesamtem PIC gilt (Summe aller Teilströme). Die Infos dazu findet ihr im Datenblatt unter Electrical Specification. Und genau aus diesen Gründen dürfen zu große Lasten nicht direkt an den Mikrocontroller angeschlossen werden. Dieser Abschnitt sollte nicht falsch verstanden werden: Man kann eine Last schon mit einem Vorwiderstand direkt an einen IO des uC anschließen, man muss dabei aber beachten das der Strom, den die Last benötigt den maximalen Wert des Pins nicht überschreitet. Wenn Ihr in eurem Projekt zum Beispiel eine normale grüne/gelbe/rote LED ansteuern möchtet kann diese natürlich direkt (mit Vorwiderstand) an einen IO angeschlossen werden – gar kein Problem. Jedoch sollte man bei größeren Lasten ggf. eine Treiberstufe einsetzen um den GPIO des Controller nicht zu überlasten. Hier wird die Last über einen Transistor oder wahlweise FET geschaltet. Der Strom wird somit direkt von der Spannungsversorgung bereit gestellt.
In der Abbildung ist eine klassische Treiberstufe mit einem NPN-Transistor zu sehen. Sobald der Mikrocontroller seinen Ausgang auf High
anhebt, wird das Potential an der Basis des Transistors positiver als das am Emitter, somit fließt ein geringer Basisstrom aus dem Controller in den Transistor hinein, woraufhin der Transistor zu leiten beginnt (Collector-Emitter Strecke). Sobald der Mikrocontroller den Ausgang auf Low
schaltet wird die LED ausgeschaltet, da die Collector-Emitter-Strecke des Transistors sperrt. Durch den µC fließt somit nur ein minimaler Basistrom statt des eigentlichen Laststroms. Wenn ihr besonders sparsam arbeiten möchtet, könnt Ihr statt des normalen Transistors auch einen FET verwenden. Dieser wird nicht mit Strom, sondern mit Spannung gesteuert.
Alle PIC Typen in der Übersicht
Wie es der Name zu diesem Tutorial auch schon vermuten lässt, werden wir uns hier um die PIC18F Famielie der Microchip Microcontroller kümmern. Nichts desto trotz möchte ich euch die weiteren Familien nicht vorenthalten. Um einen Überblick über die Typen-Vielfalt zu erhalten, dient die nachfolgende Tabelle:
DATENBREITE | KERN | SPANNUNG | DSP | |
---|---|---|---|---|
PIC10F | 8 Bit | 12 Bit | 2,0 – 5,5V | Nein |
PIC12F | 8 Bit | 14 Bit | 2,0 – 5,5V | Nein |
PIC16F | 8 Bit | 14 Bit | 2,0 – 5,5V | Nein |
PIC18F | 8 Bit | 16 Bit | 1,8 – 5,5V | Nein |
PIC24F | 16 Bit | 24 Bit | 2,2 – 3,6V | Nein |
dsPIC30F | 16 Bit | 24 Bit | 2,5 – 5,5V | Ja |
dsPIC33F | 16 Bit | 24 Bit | 3,0 – 3,6V | Ja |
PIC32M | 32 Bit | 32 Bit | 2,3 – 3,6V | Nein |
Im Folgenden wollen wir etwas Licht ins dunkel bringen und klären, was die in der Tabelle verwendeten Begrifflichkeiten bedeuten und worauf man bei der Wahl eines PIC achten sollte.
Programm- Speicher
Gibt an wie viel Speicherplatz der PIC für Befehle, also euer eigentliches Programm, zur Verfügung hat. Hat ein PIC die Bezeichnung 4k, dann hat er 4096 Speicherplätze für Befehle mit der Größe seines Kernes. Bei der Auswahl des Controllers sollte man generell nie zu knapp planen. Lieber einen Typen mit etwas mehr Speicher auswählen und bei Bedarf die entsprechenden Reserven haben.
Pins
Gibt an wie viele Pins das Gehäuse des PIC insgesamt hat. Dieser Wert steht nur bedingt im Zusammenhang mit der zur Verfügung stehenden Anzahl an Ein- und Ausgängen. Diese Größe liefert also lediglich eine Auskunft über das Gehäuse (alle Pins des Gehäuses nicht nur die Anzahl der verfügbaren GPIOs).
I/O-Pins
Dies ist die Tatsächliche Angabe über die Anzahl an Ein- und Ausgängen (GPIOs) die dem Anwender zur Verfügung stehen. Hier sollte man jedoch zusätzlich beachten, dass es vorkommen kann, dass ein oder auch mehrere GPIOs nur als sogenannte open collector
Variante ausgeführt sind und dann nur mit Hilfe eines Pull-up-Widerstandes als vollwertiger Ausgänge arbeiten können.
ADC
In der Regel besitzt ein PIC eine Einheit um analoge Spannungen in einen digitalen Wert umzusetzen. Die Angabe über die ADCs dient zur Orientierung an wie viel verschiedenen GPIO-Pins diese analoge Spannung dafür angelegt werden kann. Der Controller bzw. der Umsetzer greift sich die Spannung dann von diesem Pin ab.
USART (SCI)
Der Begriff USART (Universal Asynchronous Receiver Transmitter) beschreibt eine serielle Schnittstelle. Diese kann zum Beispiel als RS232 verwenden werden um mit anderen Modulen zu kommunizieren. Als Beispiel wird diese Schnittstelle gerne zum Einsatz eines Bootloaders genutzt.
SSP (MSSP)
Die synchrone serielle Schnittstelle (kurz SSP) bietet einem die Möglichkeit eine SPI (Seriel Peripheral Interface) oder I2C (Inter-Integrated Circuit) zu realisieren. Viele externe Module wie Displays, Sensoren und Aktoren nutzen diese standardisierten Schnittstellen um eine möglichst einfache Ansteuerung zu ermöglichen, die von nahezu jedem Controller unterstützt wird. Mit der Zeit werden ihr standardisierte Schnittstellen zu schätzen lernen 🙂
(E)CCP
Anzahl der Capture/Compare/PWM-Module. Mit diesen Modulen lassen sich Impulse messen (Länge) und erzeugen. Außerdem können PWM-Signale (Signale mit variabler Pulsweite) ausgegeben werden. PWM Signale werden z.B. gerne eingesetzt um Leuchtquellen in ihrer Helligkeit zu regulieren.
Timer
Timer sind so ziemlich das wichtigste Instrument bei der Softwareentwicklung auf Mikrocontrollern. Hier wird angegeben über wie viele Hardware-Timer der jeweilige PIC verfügt. Dabei wird zwischen verschiedenen Größen (8 oder 16 Bit) unterschieden.
nanoWatt XLP
Eine Bezeichnung für eine Stromspartechnologie. Diese PIC-Typen arbeiten üblicherweise mit einer Versorgungsspannung von deutlich unterhalb von 5V
(zum Beispiel 3,3V
oder noch weniger). Die meisten XLP-Typen können jedoch auch nach wie vor mit 5V
betrieben werden.
Hardware und Module
In diesem Kapitel gehe ich auf die grundlegendsten Hardwaremodule eines PIC ein und versuche diese zu grob zu erläutern. Dabei versteht es sich von selbst, dass Ihr das hier gelesene nur durch ausprobieren erlernen und verfestigen könnt. Es gilt: Learning by doing. Auf der folgenden Grafik seht Ihr zum Beispiel was ein PIC18F13K22
so alles an Hardware zu bieten hat.
Quelle: Datenblatt des PIC18F13K22
Hier kann man zum Beispiel auch sehen, dass auch wenn ein PIC über mehrere Ports verfügt (hier A
, B
und C
), diese nicht zwangsweise auch immer volle acht GPIOs zur Verfügung stellen, siehe PORTB
, bei dem die GPIOs 0 bis 3 nicht vorhanden sind.
Die Timer
Ein PIC beinhaltet verschiedene Ausführungen von Timern. Was kann man mit Timern machen? Timer sind vermutlich die wichtigste Peripherie die ein Mikrocontroller überhaupt besitzt. Man kann mit ihnen zum Beispiel die Länge eines Impulses zählen, Impulse exakter Länge ausgeben, Zeitbasen erzeugen, Programmfunktionen ansteuern und so weiter und so fort. Das entscheidende an Hardware-Timern ist, dass sie völlig autark, unabhängig von der CPU arbeiten. Wird ein Timer einmal vom PIC gestartet läuft er ununterbrochen fort (es sei denn der PIC geht in den SLEEP
Modus und der Timer unterstützt kein Fortlaufen in diesem). Der PIC kann während der Timer im Hintergrund läut, andere Aufgaben parallel bearbeiten. Und genau das ist der große Vorteil von Hardware-Timern. Im Folgenden wollen wir die einzelnen Timer einmal etwas detaillierter betrachten.
TIMER0
Der TIMER0 ist ausnahmslos bei allen PIC vorhanden. Es handelt sich hierbei um einen einfachen 8 Bit Timer. Bei vielen PIC-Typen kann der Timer0 auch im 16-Bit-Modus betrieben werden. Was bedeutet 8 Bit Timer? Das bedeutet, dass dieser Timer von 0
bis 255
zählen kann – das Zählerregister ist also 8 Bit breit, siehe.
Wertigkeit = ![]() |
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
Bitnummer (x) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Ein Bit kann ausschließlich die Werte 0
oder 1
annehmen. Wenn alle Bits mit einer 0
gefüllt sind, so ist der Zählerstand ebenfalls 0
. Sind hingegen alle Bits gesetzt (=1
), ergibt das einen Wert von 255
und dieser ergibt sich rechnerisch wie folgt:
Wer an dieser Stelle Schwierigkeiten hat das binäre Zahlensystem nachzuvollziehen, dem sei folgender Artikel ans Herz gelegt, der die verschiedenen Zahlensysteme sehr anschaulich erklärt. Das Verständnis zu den Zahlensystemen (vorrangig Binär, Dezimal und Hexadezimal) ist unabdingbar in der Mikrocontroller-Programmierung.
Der TIMER0 kann teilweise auch als 16
Bit Timer verwendet werden. Außerdem hat man die Wahl zwischen Timer und Counter. Der TIMER0 erhält seinen Takt entweder über den Pin RA4
oder er arbeitet mit ¼ des PIC Taktes. Wobei er diesen Takt durch einen Vorteiler in 8 Stufen teilen kann. Der Vorteiler lässt sich zwischen den Teiler mit bis zu 1/2
und 1/256
wählen. Der TIMER0 beginnt bei 0
zu zählen und zählt bis 255
rauf. Bei einem Überlauf, also wenn nach dem Zählerstand 255
wieder um eins hoch gezählt wird, wird das Bit T0IF
im Register INTCON
gesetzt. Durch das Setzen dieses Flags kann ein Interrupt vom Controller ausgelöst werden. Der aktuelle Zählerstand des TIMER0 steht im Register TMR0
und kann gelesen sowie beschrieben werden. Der TIMER0 wird im T0CON
Register konfiguriert, siehe dazu das Datenblatt des jeweiligen PIC.
Quelle: Datenblatt des PIC18F13K22
Damit der Interrupt des TIMER0 benutzt werden kann, muss das GIE
Bit (global interrupt enable) gesetzt werden. Dieses Bit ist vorhanden um alle Interrupts zu erlauben oder zu verbieten. Wenn das GIE
Bit gelöscht ist, kann kein Interrupt ausgeführt werden! Ausnahmen bestätigen die Regel: Wird im Programm das unterscheiden verschiedener Interrupt-Prioritäten erlaubt, so gibt es zwei globale Enable-Bits: Eines für niedrig priorisierte und eines für hoch priorisierte Interrupts. Dabei ist jedoch das Enable-Bit für die High-Prio Interrupts dem der Low-Prio Interrupts übergeordnet. Sprich, sind High-Prio Interrupts disabled (also GIE
= GIEH
gelöscht), können weder High- noch Low-Prio Interrupts genutzt werden. Beim Löschen des GIEL
(=PEIE
) Bits sind hingegen nur die Low-Prio Interrupts explizit gesperrt und die High-Prio Interrupts weiterhin möglich. Der TIMER0 wird mit folgenden Bits im T0CON
Register eingestellt:
BIT 7 | BIT 2 | BIT 1 | BIT 0 | ||||
---|---|---|---|---|---|---|---|
TMR0ON | T08BIT | T0CS | T0SE | PSA | T0PS<2:0> |
T0PS<2:0> (Prescaler Select bits)
Mit den Bits PS0
bis PS2
wird der Vorteiler für den TIMER0 eingestellt. Er lässt sich in acht Schritten von bis hin zu
einstellen, wobei
PS<2:0> = ‘000’
einem Vorteiler von und
‘111’
einem Vorteiler von entspricht. Die Zwischenstufen sind immer der halbe bzw. doppelte Teiler.
PSA (Prescaler Assignment bit)
Mit diesem Bit kann man den Vorteiler für den TIMER0 einschalten PSA = ‘0’
oder ausschalten PSA = ‘1’
. Wenn der Vorteiler ausgeschaltet ist, arbeitet der TIMER0 direkt mit ¼ des PIC Taktes (also mit ¼ des internen oder externen Oszillators).
T0SE (Source Edge Select bit)
Diese Option ist nur interessant, wenn ihr den TIMER0 mit einem Takt über den Pin RA4
versorgt. Mit diesem Steuerbit entscheidet ihr wann der PIC den TIMER0 um eins weiterzählen lässt. Und zwar wird zwischen dem Inkrementieren bei steigender (0)
oder fallender Taktflanke (1)
unterschieden.
T0CS (Clock Source Select bit)
Hier wird zwischen den beiden Taktquellen unterschieden: Mit gesetzten Bit (1)
wird der Interner Takt ( also ¼ des PIC Taktes) genutzt. Wird das Bit hingegen gelöscht (0)
wirdder externe Takt über RA4
genutzt.
T08BIT (8-bit/16-bit Control bit)
Wird dieses Bit gesetzt, arbeitet der TIMER0 im 8-Bit-Modus. Wird es hingegen gelöscht arbeitet der TIMER0 einem 16 Bit breiten Zählerregister, kann also statt von 0
bis 255
von 0
bis 65535
zählen und dementsprechend längere Perioden ermöglichen. Im 16 Bit Modus steht der Zählerstand in den Registern TMR0L
und der höherwertige Teil in TMR0H
. Zusammen ergibt sich somit der 16 Bit Zählerstand des Timers.
TMR0ON (on/off Control bit)
Der Name verrät es schon, mit diesem Bit kann der Timer gestartet (1)
oder angehalten (0)
werden.
TIMER0 Blockschaltbild – Quelle: Datenblatt des PIC18F13K22
TIMER1/3/5
Die TIMER1, 3 und 5 sind 16 Bit Timer. Das heißt, dass diese von 0
bis 65535
zählen können. Oder in hexadezimaler Schreibweise von 0x0000
bis 0xFFFF
. Die Timer können ihren Takt mit dem sie zählen, entweder über den internen Quarztakt beziehen oder wie der TIMER0 über von extern über GPIOs (TxCKI oder SOSCI/SOSCO) des PIC. Sobald der Timer überläuft, setzt er das Bit TMRxIF
im PIR1/2/5
Register, welches einen Interrupt auslösen kann. Damit die Timer überhaupt einen Interrupt auslösen können, müssen die entsprechenden Enable-Bits TMRxIE
im PIE1/2/5
Register gesetzt werden. Des Weiteren haben die Bits PEIE/GIEL
sowie GIE/GIEH
im INTCON
Register einen Einfluss auf den Interrupt. Da die Timer 16-Bit-Timer sind, der PIC aber nur 8-Bit-Register hat, werden für das Zählen zwei Register benötigt. Das sind die Register TMRxL
und TMRxH
. Im Register TMRxL
steht dementsprechend der niederwertige Teil und in TMRxH
der höherwertige. Man kann den Zählerstand jederzeit auslesen oder mit einem gewünschten Wert beschreiben.
Die Timer werden mit folgenden Bits im Register TxCON
eingestellt. Das Beschreibung zum Register findet ihr im Datenblatt unter TxCON
, da die Steuerung für die TIMER1, 3 und 5 identisch ist.
BIT 7 | BIT 0 | ||||
---|---|---|---|---|---|
TMRxCS<1:0> | TxCKPS<1:0> | TxSOSCEN | ![]() |
TxRD16 | TMRxON |
TMRxON
Das Bit schaltet den Timer ein (1)
oder aus (0)
.
TxRD16
Hier könnt ihr zwischen Lesen/Schreiben in einer 16 Bit Operation (1)
oder in zwei 8 Bit Operationen (0)
umschalten.
TxSYNC
Mit diesem Bit kann eine Synchronisation des externen Taktes mit dem internen durchgeführt werden. Dieses Bit hat folglich keine Funktion, wenn der Takt nicht von extern kommt. Dieses Bit ist also nur relevant, wenn TMRxCS<1:0>
auf ‘1X’
steht, wobei das X
für beliebig steht.
T1xSOSCEN
Wenn TMRxCS<1:0>
auf ’10’
gesetzt ist, könnt ihr zwischen Taktspeisung am Pin TxCKI
mit (0)
oder an SOSCI/SOSCO
Pins mit (1)
wählen.
TxCKPS<1:0>
Ähnlich wie beim TIMER0 kann man dem TIMER1/3/5 einen Vorteiler vorschalten, der den Takt zum Zählen entsprechend teilt. Der Vorteiler lässt sich in vier Stufen einstellen wobei T1CKPS0/1 = ’00’
einem Vorteiler von entspricht und
’11’
hingegen .
TMRxCS<1:0>
Mit diesen beiden Bits wählt Ihr die Quelle des Taktes für den TimerX. Mit ’00’
arbeitet der jeweilige Timer mit ¼ des PIC Taktes, mit ’01’ bezieht er den direkten Takt des Systems ohne Teilung, mit ’10’
kommt der Takt vom Pin oder Oszillator (siehe TxSOSCEN
) und die Einstellung ’11’
wird nicht verwendet bzw. ist reserviert.
Die Timer können verwendet werden um den PIC aus dem Sleep-Zustand zu wecken. Damit der TIMER1/3/5 den PIC aufwecken kann muss er im asynchronen Modus arbeiten, sprich er bekommt seinen Takt von extern. Der PIC wird dann geweckt, wenn der Timer überläuft / einen Interrupt auslöst.
Sekunden Basis mit TIMER1 erstellen
Da man dem TIMER1 einen externen Takt anschließen kann, hat man mit einem Uhrenquarz die Möglichkeit eine 1 Sekunden Basis zu schaffen. Ein Uhrenquarz wird wie der normale Quarz (für die Taktversorgung des PIC) an die Pins T1OSO
und T1OSI
angeschlossen. Dann bekommt der Quarz noch pro Beinchen einen Kondensator (10pF bei dem verlinkten Typ) gegen Masse spendiert. Der TIMER1 zählt nun mit einem 32.768 Hz
Takt, was als Zahl genau 0x8000
entspricht. Also brauch der TIMER1 für einen Überlauf (Intterrupt) von 0x8000
bis zum Überlauf (genau) eine Sekunde. Somit hat man zum Beispiel die Zeitbasis für eine Uhr geschaffen. Der Timer muss bei Überlauf immer mit dem Wert 0x8000
+/- vorgeladen werden. Dabei kann der Wert angepasst werden, falls die Zeit vor oder nachläuft.
Das Vorgehen nochmal zusammengefasst:
- TIMER1 konfigurieren (externen Takt auswählen, Syncronisation aus) (
T1CON
) - Den Interrupt des
TMR1
konfigurieren (PIE1
undIPR1
) - Im Interrupt lediglich ein Flag setzten (+1 Sekunde-Merker)*
- Zählerregister wieder auf
0x80
und0x00
setzten (auch im Interrupt) - Schritte
3
und4
wiederholen sich automatisch durch den Interrupt
* Die Interrupt-Service-Routine (kurz ISR: So nennt man die Funktion, die aufgerufen wird, wenn ein Interrupt ausgelöst wurde) sollte immer so kurz wie möglich gestaltet werden. Keinesfalls werden Funktionsaufrufe ausgeführt! Wir setzten hier lediglich ein Flag, setzen die Zählregister wieder auf ihre Startwerte und löschen das Flag, das den Interrupt ausgelöst hat. Durch das Flag, welches wir gesetzt haben können wir im normalen Programm sehen, das eine Sekunde vergangen ist und entsprechend fortfahren.
TIMER2/4/6
Die TIMER2/4 und 6 sind drei identische 8 Bit Timer. Diese Timer sind wie der TIMER0 wieder als 8 Bit
Timer ausgeführt. Allerdings unterscheiden sie sich in einem entscheidenden Punkt. Die TIMER2/4 und 6 verfügen neben einem Vorteiler (Prescaler) zusätzlich über einen Nachteiler (Postscaler). Die folgende Grafik zeigt das entsprechende Blockdiagramm.
Quelle: Datenblatt des PIC18F13K22
Im Gegensatz zu dem Timern 0
, 1/3
und 5
, können die Timer 2/4
und 6
nur mit dem internen PIC Takt arbeiten. Genauer gesagt mit ¼ der Frequenz des extern angeschlossenen Quarz (Fosc
siehe auch hier). Der aktuelle Zählerwert steht im TMRx
Register. Genau wie bei den anderen Timern, kann der aktuelle Zählerstand sowohl ausgelesen als auch verändert werden. Eine Besonderheit bei den Timern 2,4
und 6
ist, dass sich der Zählerwert dynamisch begrenzen lässt. Über das Register PRx
kann ein Wert vorgegeben werden. Der aktuelle Zählerstand des TMRx
Registers wird über einen Komparator mit dem Inhalt des PRx
Registers verglichen. Wenn die Registerinhalte übereinstimmen startet der Timer von vorn. Die Timer 2/4/6
lassen sich so zum Erzeugen von PWM-Signalen nutzen. Dabei arbeiten sie mit dem ECCP-Modul zusammen. Sobald der Timer überläuft, wird an das Modul ein Signal gesendet.
Die Timer werden mit folgenden Bits im Register TxCON
eingestellt. Hierbei steht das x
für den gewünschten Timer (2/4
oder 6
).
BIT 7 | BIT 0 | ||||||
---|---|---|---|---|---|---|---|
– | TxOUTPS<3:0> | TMRxON | TxCKPS<1:0> |
TxCKPS<1:0>
Hier kann der Vorteiler eingestellt werden. Ein Wert von ’00’
entspricht einem Vorteiler von und
’10’
einem Vorteiler von .
TMRxON
Mit dem Setzen dieses Bits wird der Timer gestartet. Ein löschen (Bit auf 0
setzen) bewirkt, dass der Timer angehalten wird bzw. mit dem Zählen aufhört.
TxOUTPS<3:0>
Hier stellt Ihr den Nachteiler (Postscaler) ein, dieser reicht von mit einer Bitkombination von
‘0000’
bis hin zu mit
‘1111’
.
Analog Digital Converter (ADC)
Digital ist ja schön und gut, doch manchmal brauchen wir doch das Zusammenspiel mit der Analogtechnik. Und genau hierfür hat ein PIC Mikrocontroller analoge Eingänge. Wie das funktioniert möchte ich euch im folgenden etwas näher erläutern. Die unten stehende Abbildung zeigt in grau dargestellt eine analoge Spannung, welche zu äquidistanten (gleichbleibender Abstand) Zeitpunkten abgetastet wird. Diese Abtastwerte werden mit einem ADC digitalisiert und stehen dann zur weiteren Verarbeitung bereit. Aufgrund der begrenzten Anzahl an Unterscheidungsmöglichkeiten im digitalen, gibt es nicht für jeden analogen Wert einen digitalen. Somit ergibt sich das dargestellte Raster in der Abbildung.
Quelle: Wikipedia
Stellt euch einmal vor ihr möchtet mit dem PIC eine Spannung messen um diese auf einem LC-Display anzuzeigen. Die zu messende Spannung kann zum Beispiel von einem analogen Sensor stammen und im Verhältnis zu einer physikalischen Größe stehen (z.B. zur Temperatur). Möglicherweise plant ihr auch den Bau eines einfachen Voltmeters. Für solche Zwecke könnt ihr die zu messende Spannung an einen anlogen Eingang des PIC anschließen. Diese haben die Bezeichnung ANx
wobei das x
durch eine Zahl ersetzt wird, die den Pin erkenntlich macht.
Nun kann es ja auch durchaus mal vorkommen, dass ihr Spannungen messen möchtet, die über den üblichen Bereich der Betriebsspannung des Controllers hinaus reichen. In dem Fall dient im einfachsten Fall der altbekannte Spannungsteiler. Dieser sollte so dimensioniert sein, dass die Spannung, die letztendlich am Pin anliegt, nicht größer werden kann als die Betriebsspannung des PIC selber.
Ein Beispiel seht ihr im Bild links. Der Spannungsteiler teilt die Messspannung durch 2
. Somit wäre bei einer Betriebsspannung von 5V
eine maximale Messspannung von 10V
möglich. Die gemessene Spannung (digitaler Wert) kann im PIC wieder mit 2
multipliziert werden (entspricht einer Bitschiebe-Operation nach links um eine Stelle).
Grundlegendes
Der Analog-Digital-Konverter des PIC hat eine Auflösung von 10 Bit. Ein PIC hat nur einen ADC Modul. Er kann aber von verschiedenen Pins des µC angesprochen werden. Wenn ein Eingangspin Zugriff auf den ADC hat, so wird er auch als ANx
bezeichnet. Somit kann der PIC die maximale Spannung in 1024
Werte (10 Bit
) einteilen – er quantisiert. Bei einer maximal zulässigen Messspannung von 5V
ergibt dies eine Auflösung von circa 5mV pro Bit (ULSB = 5mV
). Nun kann es ja durchaus vorkommen, dass nur ein kleiner Spannungsbereich sehr genau gemessen werden soll. Ein Beispiel: Es werden 0
bis 2V
als Messspannung benötigt. Man kann dem PIC mitteilen, dass die Referenzspannung für die AD-Umsetzung nicht mehr dem Standard von VDD
(und Vss
) entspricht, sondern die Referenzspannung an AN2
(VREF-
) und AN3
(VREF+
) des PIC entnehmen. So kann man die Auflösung (welche vorher auf den gesamten Bereich von 5V
aufgespannt wurde) nun auf einen kleineren Bereich einstellen und somit die Voltzahl pro Bit verringern (das ULSB
). Im Folgenden wollen wir uns ansehen, wie der Analog-Digital-Umsetzer (ADU/ADC) eines PIC konfiguriert wird. Folgende Bits im den Registern ANSEL
, ADCON0
und ADCON1
sind dafür nötig:
ANSEL (Analog Select Register)
Im ANSEL
Register werden die gewünschten IOs ausgewählt, die als analoge Eingänge verwendet werden sollen. Wenn ein PIC mehrere Eingänge besitzt, die analog verwendet werden können, so hat er dementsprechend auch mehrere ANSEL-Register. Diese werden alphabetisch geführt (ANSELA
, ANSELB
usw.). Dabei sind die abschließenden Buchstaben korrespondierend mit den Ports in denen die Eingänge liegen. Somit ist die folgende Konfiguration eher exemplarisch zu verstehen und hängt mehr vom verwendeten PIC ab.
BIT 7 | BIT 0 | ||||
---|---|---|---|---|---|
ANS7 | ![]() |
![]() |
ANS0 |
Eine 1
im entsprechenden Bit setzt den GPIO Pins als analogen Eingang. Wenn ein Pin als analoger Eingang gewählt wird, dann muss das entsprechende TRIS Bit ebenfalls auf 1
gesetzt werden. Wird das Bit im ANSEL-Register hingegen gelöscht (auf 0
gesetzt), so ist der Eingang auf digital geschaltet. Ein analoger Eingang kann nicht mehr auf logische Pegel abgefragt werden, sprich folgendes macht bei einem analogen Eingang keinen Sinn:
if( PORTAbits.RA0 == 1 ) { // do something }
ADCON0 (A/D Control Register 0)
Im ADCON0
Register kann das ADC-Modul des PIC generell ein- oder ausgeschaltet werden. Außerdem beinhaltet das Register das Statusflag des ADC. Zusätzlich werden übrige Bits zum selektieren einzelner Kanäle (Auswahl eines ANx
zum messen) verwendet.
BIT 7 | BIT 6…2 | BIT 1 | BIT 0 | ||||
---|---|---|---|---|---|---|---|
– | CHS<4:0> | ![]() |
ADON |
ADON (ADC Enable bit)
Dieses Bit aktiviert mit 1
oder deaktiviert mit 0
den Analog-Digital-Umsetzer.
GO/DONE ( A/D Conversion Status bit)
Durch das Setzen dieses Bits wird eine AD-Umsetzung gestartet. Das Bit bleibt dann solange High
bis der PIC mit der Messung/Umsetzung fertig ist. Man muss dieses Bit also immer auf 0
prüfen, wenn man eine neue Messung starten oder die aktuelle auswerten möchte. Der ADC kann auch einen Interrupt auslösen. Wenn der ADC entsprechend konfiguriert ist setzt er nach beendeter Umsetzung das ADIF
Bit im PIR1
Register.
CHS<4:0> (Analog Channel Select bits)
Mit diesen Bits wird der ANx
selektiert, an dem die nächste Analog-Digital-Umsetzung stattfinden soll.
ADCON1 (A/D Control Register 1)
In diesem Register lassen sich weitere Einstellungen für den ADC vornehmen. So lässt sich zum Beispiel eine alternative Referenz (Spannung) auswählen. Standardmäßig sind und
als Referenz voreingestellt.
BIT 7 | BIT 6 | BIT 7 | BIT 6 | BIT 3…2 | BIT 1…0 | ||
---|---|---|---|---|---|---|---|
TRIGSEL | – | – | – | PVCFG<1:0> | NVCFG<1:0> |
NVCFG<1:0> (Negative Voltage Reference Configuration bits)
Mit diesen beiden Bits wird die negative Referenzspannung eingestellt bzw. gewählt. Mit ’00’
wird die interne Spannung AVss
gewählt. Mit ’01’
wird die Spannung vom externen Pin entnommen. Durch setzen auf
’10’
oder ’11’
(also ’1X’
) wird beides mal AVss
gewählt, da diese beiden Einstellungen nicht belegt bzw. reserviert sind.
PVCFG0/1 (Positive Voltage Reference Configuration bits)
Mit diesen beiden Bits wird die positive Referenzspannung eingestellt bzw. gewählt. Mit ’00’
wird die interne Spannung gewählt. Mit
’01’
wird die Spannung vom externen Pin entnommen. Durch setzen auf
’10’
wird die positive Referenz mit dem internen Signal FVR
verbunden. Mit ’11’
wird gewählt, da diese Einstellungen nicht belegt bzw. reserviert ist.
TRIGSEL (Special Trigger Select bit)
. . .
Acquisition time
Bei der Geschwindigkeit der Umsetzung sollte man beachten, dass der PIC genügend Zeit braucht um eine Umsetzung durchzuführen. Er muss hierzu während des Verfahrens einen im PIC befindlichen Kondensator, auf die am Eingang anliegende Spannung aufladen. So liegt es nahe, dass wenn man hier zu schnell zu Werke geht, eine fehlerhafte Messung durchgeführt wird. Im Datenblatt des PIC gibt es eine genaue Formel zur Berechnung dieser Zeit. Laut Sprut ist eine Zeit von ca. 40 µS ausreichend.
Das Ergebnis einer AD-Umsetzung
Das 10 Bit große Ergebnis einer Analog-Digital-Umsetzung steht in den beiden Registern ADRESL
und ADRESH
. Diese beiden Register wären theoretisch 16 Bit lang, da der ADC des PIC aber “nur” eine Auflösung von 10 Bit hat, steht das Ergebnis lediglich in 10 der 16 Bit und zwar entweder rechts- oder linksbündig. Das hängt ganz davon ab, wie wir das Bit ADFM
im Register ADCON2
gesetzt haben.
ADCON2 (A/D Control Register 1)
BIT 7 | BIT 6 | BIT 5…3 | BIT 2…0 | ||||
---|---|---|---|---|---|---|---|
ADFM | – | ACQT<2:0> | ADCS<2:0> |
ADCS<2:0> (A/D Conversion Clock Select bits)
Es findet die Wahl des AD-Taktes statt:
000
Fosc/2
001
Fosc/8
010
Fosc/32
011
Frc
100
Fosc/4
101
Fosc/16
110
Fosc/64
111
Frc
ACQT<2:0> (A/D Acquisition time select bits)
Mit diesen drei Bits wird die Wandlungszeit eingestellt. Dabei führt eine zu kurze gewählte Zeit zu verfälschten Messwerten!
000
0
TAD001
2
TAD010
4
TAD011
6
TAD100
8
TAD101
12
TAD110
16
TAD111
20
TAD
ADFM (A/D Conversion Result Format Select bit)
Mit diesen Bit wird ausgewählt, ob das Ergebnis in ADRESL & ADRESH rechts- (1) oder linksbündig (0) ausgegeben wird.
ADC-Interrupt
Wenn Ihr mit dem Analog-Digital-Converter einen Interrupt auslösen mächtet, müsst Ihr das ADIE
Bit im PIE1
Register setzen. Die Priorität des Interrupt kann mit dem Bit ADIP
im Register IPR1
gewählt werden. Das Bit ADIF
ist das Interrupt-Flag und muss wie alle Interrupt-Flags, per Software zurück gesetzt werden. Das Bit wird vom PIC gesetzt, sobald eine Messung abgeschlossen wurde. Dieser Interrupt ist übrigens auch in der Lage den PIC aus dem Sleep Modus aufzuwecken.
Ausblick
In den nächsten Kapiteln dieses PIC-Tutorials beschäftigen wir uns mit den ersten weiteren interessanten Komponenten eines Mikrocontrollers. Wir schauen uns unter anderem die beliebten und sehr weit verbreiteten Interfaces SPI, I2C und UART an. Wenn dich der Ehrgeiz gepackt hat, dann lies doch einfach direkt im nächsten Kapitel weiter: PIC18 Tutorial – PWM, I2C, SPI und UART
Hallo Nicolas Pannwitz,
ich habe grade erst heute deine Webseite entdeckt, und finde sie bisher am aller ansprechendsten für meine Zwecke (ich bin einfacher Facharbeiter in Elektronik und würde mir gerne die Beherschung der PIC-programmierung aneignen um mir einfache Prüfgeräte und ähnliches bauen zu können), nur musste ich leider lesen, dass ab morgen diese Webseite nicht mehr existiert… stimmt das? Gibt es eine Ausweichadresse für diesen wertvollen Wissensschatz? Vielen Dank für deine bisheriges Werk im Bereich Aufklärung zu PICs…
mit freundlichen Grüßen aus Wien
Johnny Cech
Hallo,
ja das stimmt.
Ich habe einfach nicht mehr die Zeit mich um die Webseite zu kümmern. Und leider kam auch nicht die Resonanz wie erhofft. Zudem kostet es ja auch etwas Geld die Seite zu hosten.
Ich würde dir vorschlagen die Seite herunterladen und ggf. als PDFs zu speichern.
Viele Grüße
Nico