PIC Tutorial

Aus PIC-Projekte
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Allgemeines

Bevor ihr mit dem Programmieren bzw. mit dem Arbeiten mit PIC Mikrocontrollern anfangt, solltet ihr euch unbedingt ein paar Grundlagen zum Aufbau eines PIC aneignen. Das erleichtert die spätere Arbeit mit PICs doch sehr und hilft in der Tat bei so manchem Problem.

Hallo, ich habe mir mal die Mühe gemacht eine kleine Anleitung zu PIC Mikrocontrollern der Firma Microchip zu erstellen. Dieses Toturial ist nur ein kleiner Einstieg und deckt längst nicht alles über PICs ab, sollte aber Einsteigern helfen die ersten Fragen zu bewältigen. Ich habe zunächst erstmal eine Palette an Themen abgearbeitet, welche mir am wichtigsten erschienen. Sollten Sie sich brennend für einen Themenbereich von PICs interessieren und dieser ist hier noch nicht beschrieben, dann machen Sie im Forum einen Themenvorschlag um den dieses Toturial erweitert werden sollte. Ich werde Ihren Vorschlag berücksichtigen, solange ich mich selbst gut genug damit auskenne.

Vorwort

Hallo liebe(r) Leser(in), ich freue mich, dass Sie sich dafür entschieden haben dieses kleine PIC-Tutorial zu lesen. Ich werde Ihnen die notwendigen Grundlagen, welche Sie für den Einstieg in die PIC Programmierung benötigen, näher bringen. Sie dürfen aber nie vergessen, dass Sie durch bloßes Lesen dieses Tutorials nicht zu einem Profi werden. Weit gefehlt! Sie müssen immer wieder selber versuchen das hier gelesene durch eigenes Nachvollziehen in Form von selbst geschriebenen Programmen zu verfestigen! Sollten Sie beim Durchstöbern dieses Tutorials irgendwelche Fragen haben und einfach nicht weiter kommen, dann können Sie sich gerne mit Ihrem Problem im Forum von PIC-Projekte(.de) melden und Ihr Problem schildern. Folgenden Sie dazu einfach diesem Link: Forum

Fehler im Tutorial / Wunsch für ein weiteres Thema?
Wenn ihr einen Fehler findet oder ihr einen Vorschlag für neuen Inhalt für das Tutorial habt dann schreibt mir eine Mail an: NicoME(at)gmx(dot)de


Was ist ein PIC-Mikrocontroller?

Ein PIC-Mikrocontroller (µC) ist im Prinzip ein kleiner Integrierter Schaltkreis (engl. IC), wobei sich die äußere Erscheinung unterscheiden kann. Die von der Firma Microchip hergestellten PIC Mikrocontroller sind in vielen Bereichen einsetzbar, was uns zu dem nächsten Punkt dieses Tutorials bringt.

Wofür braucht man einen Mikrocontroller?

Der Verwendungsbereich für Mikrocontroller ist unglaublich groß. Mikrocontroller sind aus unserer Welt gar nicht mehr weg zu denken! Heut zu Tage ist in fast jedem Elektronischem Gerät ein oder mehrere µC verbaut. Nur um mal ein paar Beispiele zu nennen: Toaster, Mp3-Player, Backofen, Handy, Kamera und noch vieles mehr! Man kann mit µC unglaublich viele Aufgaben erledigen, welche sonst einen sehr großen Aufwand an entsprechenden logischen Bauteilen hätten. Daher verwenden wir µC für Steuerungen jeglicher Art.

Was brauche ich alles?

MPLABX Screen
Um mit Mikrocontrollern, speziell PICs, arbeiten zu können, müssen Sie ein paar Anschaffungen im Vorfeld tätigen:

Entwicklungsumgebung

Als Entwicklungsumgebung bietet sich für Mikrocontroller der Familie PIC besonders das Programm "MPLAB IDE" an. Hier können direkt die Programme geschrieben werden in Assembler sowie in C. Wenn Sie beabsichtigen nur in Assembler (ASM) zu programmieren müssen Sie sich nur MPLAB IDE herunterladen. Die Software ist direkt auf der Homepage von Microchip zu finden. Wenn Sie hingegen die PICs in C programmieren wollen, so empfehle ich Ihnen (a) den Compiler "C18" zu benutzen und (b) nur mit PIC18 zu arbeiten, da der C18-Compiler nur für PIC18 Typen zu verwenden ist. Den Compiler "C18" können Sie auf der Homepage von Microchip ebenfalls kostenlos herunter laden.

Die neue Entwicklungsumgebung MPLAB X IDE
Ich empfehle euch die neue Entwicklungsumgebung von Microchip zu verwenden. Siehe dazu auch den Artikel zu Verwendung der neuen IDE: MPLAB X IDE


Programmiergerät

PICkit3
Wenn sie ein Programm geschrieben haben wird aus dieser Datei eine Datei in Maschinensprache generiert (Dateiendung *.hex). Diese Datei muss nun in den PIC hinein. Diesen Vorgang bezeichnet man als "brennen" oder "flashen". Kurz und knapp: Euer Programm wird in den Speicher des PIC geschrieben. Ich empfehle euch das PICKit3. Es ist ein Brenner und Debugger in einem. Das bedeutet ihr könnt neben der selbstverständlichen Funktion des flashens auch noch euren PIC in der fertigen Schaltung debuggen (Haltepunkte im Programmcode setzten und Variablen auslesen). Das PICKit3 ist das Gerät für Einsteiger und Fortgeschrittene! Ein weiterer nicht zu unterschätzender Vorteil des PICkit3 ist, dass es zu 100% von MPLAB (X) IDE unterstützt wird, sprich Programm schreiben und brennen geschieht alles innerhalb von MPLAB und benötigt keine weitere Software.

Alternativ im Eigenbau: Brenner8 von Sprut

Bitte beachtet, dass wenn ihr einen Brenner von Sprut aufbauen möchtet, Ihr das Henne/Ei Problem zu lösen habt (Ihr müsst um PICs mit dem Brenner8 brennen zu können die Firmware von Sprut in den Eigen-PIC des Brenner8's laden. Schreibt hierfür evtl. eine Nachricht ins Forum)

Mikrocontroller

Zu guter Letzt benötigen Sie natürlich auch noch den PIC selber. Wie ich schon weiter oben erwähnt habe, würde ich für das Programmieren in C die PIC18F empfehlen. Wenn Sie sich für Assembler entschieden haben können Sie mit den PIC16F anfangen. Als Bezugsquelle kann ich Ihnen das Versandhaus "Reichelt" empfehlen. Hier bekommen Sie die PICs und entsprechendes Zubehör zu moderaten Preisen.


Der schnelle Einstieg

Wer es besonders einfach und schnell haben möchte, kann sich auch ein so genanntes PIC Starterkit kaufen und sofort mit dem Programmieren loslegen. Ich empfehle hierfür dieses PIC Starterkit.

Welcher PIC ist der richtige?

Es gibt eine sehr große Auswahl an PIC Controllern, da ist es zu Beginn erst einmal nicht so einfach den richtigen PIC zu finden. Daher sollten Sie sich zu Beginn Ihrer Programmiererfahrungen erst mal nur auf wenige PIC Typen festlegen und diese studieren. In den Datenblättern finden Sie alles, was Sie zu den PICs wissen müssen. Da die Datenblätter, wie Sie vielleicht schon vermutet haben, auf Englisch sind, werden Sie nicht ums Englisch lernen herum kommen. Aber vieles erklärt sich mit der Zeit auch von allein.

Hier einmal zwei PICs, welche ich zum Beginn empfehlen möchte:

PIC18F1320 (DIP Gehäuse) PIC16F628 (DIP Gehäuse)
Geeignet(er) für programmieren in C Geeignet(er) für programmieren in ASM
Programmspeicher: 8K Programmspeicher: 2K
Pins: 18 Pins: 18
I/O Pins: 16 I/O Pins: 16
ADC Eingänge: 7 ADC Eingänge: 7
Timer (Anzahl): 4 Timer (Anzahl): 4
Preis bei Reichelt: 3,15 € Preis bei Reichelt: 2,40 €


Die Peripherie für einen PIC

Mindest-Beschaltung
Der PIC ist zwar ein hochkomplexes Bauteil, benötigt zum Arbeiten aber natürlich noch die ein oder andere Beschaltung (Peripherie). Die "normalen" PICs von denen ich in diesem Tutorial reden werde, arbeiten mit einer Betriebsspannung von 5 Volt Gleichspannung. Weiterhin benötigt der PIC einen Arbeitstakt, damit er weiß, wann er immer "einen Schritt" machen muss. Während der PIC18F1320 zum Beispiel auch ohne (externen) Takt auskommen würde, denn er hat einen internen Oszillator mit 8Mhz und könnte seinen Arbeitstakt somit selber erstellen, braucht der PIC16F628 in jedem Fall eine Taktquelle, denn dieser PIC kann keinen eigenen Takt erzeugen. Weiterhin ist zu entscheiden, ob man dem PIC eine Resetschaltung gönnt oder man den Pin "MCLRE" (Master Clear Reset) als Eingang benutzt. Würde man sich dafür entscheiden, keinen Reset Schalter benutzen zu wollen, so ist der freie Pin als Eingang nutzbar (s. Datenblatt). In der nebenstehenden Grafik ist einmal die Grundbeschaltung eines PICs angedeutet.

Wie ich bereits oben erwähnt habe könnte man z.B. bei dem 18F1320 die Beschaltung des Taktgebers (Quarz) weg lassen, da dieser PIC einen eigenen Takt intern erzeugen kann. Das heißt es könnte Q1, C2 und C3 wegfallen. Außerdem kann S1 und R1 wegfallen, da wir entscheiden können ob wir einen Resetschalter brauchen oder eben nicht. Man muss hierbei beachten, dass die MCLRE Beschaltung Low aktiv ist. Das heißt, dass der PIC einen Reset durchführt, wenn er an dem Pin RA5 0V sieht. Bei 5V arbeitet er ganz normal seinen Programmcode ab.

PICs mit in größerer Bauform haben oftmals 2 Versorgungsanschlüssen (2xVDD und 2xVSS) in diesem Fall müssen auch jeweils beide angeschlossen werden!

Wenn Sie sich dafür entscheiden eine MCLRE Beschaltung nicht benutzen zu wollen müssen Sie dieses immer im Programm oder in der Konfiguration angeben. Dazu komme ich aber noch, wenn wir bei der Konfiguration angekommen sind!

Die richtige Versorgungsspannung
Ihr müsst darauf achten, dass es auch PIC gibt, welche nur mit 3,3 Volt Betriebsspannung arbeiten. Dies sind dann die "nanoWatt" PIC oder auch "XLP", für Xtreme low power.

Taktquelle

Keramik Resonator
Die Taktquelle eines PIC kommt immer an seine Pins OSC1 und OSC2. Man kann als Taktgeber verschiedene Quellen wählen. Die wichtigsten sind entweder einen normalen Quarz oder einen Keramik Resonator. In der Mindest-Bschaltung ist ein Quarz verwendet worden. Dieser hat im Gegensatz zum Keramik Resonator den Nachteil, dass er an seinen beiden Beinen noch jeweils Lastkondensatoren benötigt. Den Wert für die Kondensatoren können Sie übrigens im Datenblatt des PIC nachlesen! Der Keramikresonator hingegen hat die Kondensatoren bereits im Gehäuse und spart somit Platz. Daher empfehle ich die Verwendung von Keramik Resonatoren. Diese haben dann drei Anschlussbeinchen; Masse (Mitte), OSC1 und OSC2. OSC1 und OSC2 können ruhig vertauscht werden. (Reichelt)


Auszug aus dem PIC18F4550 Datenblatt
Des weiteren kann ein PIC auch mit seinem Internen Takt arbeiten. Diese Funktion steht aber nicht allen PIC zur Verfügung! Ihr könnt es heraus finden indem Ihr ein Blick in das Datenblatt Eures gewählten PIC wählt (s. Graif unten). Wenn Eurer PIC über einen Internen Takt verfügt, so kann vollständig auf externe Beschaltung der Pins OSC verzichtet werden.



Eine weitere Möglichkeit ist die Verwendung eines sog. Quarzoszillators; Dieser Baustein wird an die Versogungsspannung angeschlossen und liefert dann, gemäß der Spezifikation, ein TTL Signal (Rechteck) am Ausgang. Dieses wird in OSC1 des PIC gespeist. Der Taktausgang des PIC kann in diesem Fall frei bleiben. Sofern ihr PIC den EC-Mode includiert hat, kann der Taktausgangs-Pin auch noch als I/O-Pin genutzt werden.


Achtung beim Internen Takt Wenn Ihr den Internen Takt nutzen wollt müsst Ihr dazu die Konfigurations-Bits entsprechend einstellen. Das geht entweder manuel über den Code oder aber über Einstellungen in MPLAB IDE. Letzteses: Öffnet MPLAB IDE [Reiter] Configure [Unterpunkt] Configuration Bits... Nun müsst Ihr den Hacken bei "Configuration Bits set in Code" entfernen. Nun habt Ihr Zugriff auf die Steuerung. In der Kategorie "Oszillator" könnt Ihr nun in der Spalte "Settings" den entsprechenden "INT-OSC" auswählen.


Alternativ Eingabe direkt im Code

__CONFIG _IntRC_OSC


Achtung: Wenn du deine PIC Mikrocontroller in C mit MPLAB X IDE programmieren willst, dann wird das Konfigurationswort anders eingestellt. Wie, das erfährst du hier.

Hier findet ihr die richitgen Einstllungen für den Takt

Wie schreibt man ein Programm für einen PIC?

Nun ein Programm kann man auf verschiedene Weise schreiben. Grundsätzlich lassen sich Programmtexte in einem einfachen Texteditor schreiben wir werden aber die Entwicklungsumgebung MPLAB DIE verwenden, da dies ein paar entscheidende Vorteile mit sich bringt. Zum einem bringt MPLAB direkt einen Simulator mit sich mit dem man das geschriebene Programm direkt testen kann. Außerdem wird das Syntax-Highlighting verwendet was zu einer wesentlich besseren Übersicht führt und somit Fehler schnelle ans Licht bringt (zumindest Syntaxfehler1). Ich empfehle Ihnen das Programmieren der PIC in Assembler zu starten und irgendwann, wenn Sie sich sicher fühlen auf C zu wechseln. Wobei ein Wechsel auf C dann relativ einfach fallen wird, da Sie bereits die Grundkenntnisse des PIC verstanden haben. Und die meisten Probleme nicht im Verständnis der Programmiersprache sondern in der Peripherie des Mikrocontrollers liegen. Ich werde in diesem Tutorial mit den PIC16 in Assembler anfangen und dann zum Abschluss etwas auf die PIC18 in C übergehen. Genauso sollte man es auch handhaben. Die PIC16 in Assembler programmieren und die größeren ab PIC18 in C.

1 Syntax (=Satzlehre)


Grundlagen

PIC Mikrocontroller gibt es in vielen verschiedenen Sorten. Wir beschäftigen uns hier erst einmal nur mit den PIC16F und später mit den PIC18F Typen. Nachfolgend möchte ich Sie etwas in die Grundzüge und die wichtigsten Eigenschaften der PIC Mikrocontroller einführen.


Eingänge und Ausgänge

Das wichtigste an Mikrocontrollern sind die IOs (Input/Output), denn mit ihnen wird gesteuert und kommuniziert. Ein Mikrocontroller hat immer eine bestimmte Anzahl von IO-Pins zur Verfügung, dabei darf man nicht den Trugschluss ziehen, dass die Anzahl der Pins gleich der Anzahl der IO Pins ist. Dies ist nicht der Fall. PIC Mikrocontroller haben grundsätzlich ein 8 Bit breites IO-Register. Diese haben die Bezeichnung PORT_ mit einem folgenden Buchstaben für den Port (Also PORTA - PORTE). Für den PIC ist das Register wie alle anderen. Nun kann ein Pin natürlich nicht Aus- und Eingang gleichzeitig sein sondern muss auf eines der beiden definiert werden. Dieses geschieht in den zugehörigen TRIS_ Registern. Dabei entspricht eine logische "1" (o. High) einem Eingang und eine "0" (o. Low) einem Ausgang! Hierzu eine Grafik zum Veranschaulichen:

              Rx0-Rx7   
 _ _ _ _ _    
|          |-----I-----<   TRISx0=1
|  PORTx   |-----I-----<   TRISx1=1
|          |-----I-----<   TRISx2=1
|          |-----I-----<   TRISx3=1
|          |-----O----->   TRISx4=0
|          |-----O----->   TRISx5=0
|          |-----O----->   TRISx6=0
|_ _ _ _ _ |-----O----->   TRISx7=0


Die Ein- und Ausgänge des PIC sind TTL Pins und haben teilweise noch mehrere Funktionen. So können zum Beispiel bestimmte Eingänge auch als Analogeingang benutzt werden. Es gibt eine Vielzahl von Funktionen, welche sich von PIC zu PIC unterscheiden und beim Programm berücksichtigt werden müssen. Denn vergisst man z.B. bei einem PIC zu Beginn die Eingänge von Analog auf Digital umzuschalten, dann funktioniert unter Umständen der Code nicht wie gewünscht.

Ein Port-Pin kann nur einen kleinen Strom treiben!
Zum Beispiel kann ein PIC16F62x pro IO Pin 25mA treiben allerdings muss man dabei beachten, dass ein PIC auch einen insgesamt maximal-Strom hat. Lesen Sie dazu im Datenblatt: ELECTRICAL SPECIFICATIONS

Warum dürfen LEDs nicht direkt an den Mikrocontroller?

Treiberstufe
Dieser Abschnitt sollte nicht falsch verstanden werden! Man kann "eine LED" schon mit einem Vorwiderstand direkt an einen IO des uC anschließen, man muss dabei aber beachten ob der Strom, welche die LED braucht mit dem Strom, welchen der IO Treiber liefern kann übereinstimmen. Wenn Ihr in Eurem Projekt eine normale grüne/gelbe/rote LED steuern möchtet kann diese natürlich direkt (mit Vorwiderstand) an einen IO. Aber auch hier Vorsicht: Ein PIC hat nicht nur eine Begrenzung für den Strom pro IO sondern auch einen maximalen Gesamtstrom! Dieser darf logischerweise auch nicht überschritten werden. Also immer aufpassen. Die Werte für Euren PIC sind im Datenblatt unter "ELECTRICAL CHARACTERISTICS" nachzulesen. Aus diesem Grund schalte ich fast immer alle "Lasten" mit einem Transistor.

LEDs können unbedenklicher über einfache Treiberstufen angesteuert werden (siehe Abbildung unten). Wenn Sie planen stärkere LEDs zu treiben (z.B. Hochleistungs-LEDs), welche schon mehrere Watt verbrauchen, versteht es sich von selbst, dass der PIC diesen Strom nicht liefern kann und das Augenmerk dann auf den Transistor zu lenken ist ob dieser Typ denn den Strom verkraftet.

In der Abbildung kann man eine klassische Treiberstufe um eine LED von einem Mikrocontroller aus steuern zu können sehen. Sobald der Mikrocontroller seinen Ausgang auf + 5,0V anhebt, also das zugehörige Port Bit auf 1 setzt (Tris Bit auf 0 voraus gesetzt), wird die Basis positiver als die Emitter Spannung und der Transistor somit leiten. Jetzt fließt durch den Vorwiderstand und die LED Strom hindurch durch die CE Strecke gegen Masse und die LED leuchtet. Sobald der Mikrocontroller sein Potential auf Masse zieht (Low) wird die LED ausgeschaltet. Durch den µC fließt somit nur ein minimaler Strom.

Alle PIC Typen in der Übersicht

Wir werden in diesem kleinen Tutorial, wie ich schon erwähnt habe, nur die PIC16F und die PIC18F besprechen es gibt aber noch weitaus mehr Typen. Hier mal eine Tabelle mit den verschiedenen Typen zur Übersicht:

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

Nachfolgend einmal aufgelistet, was einzelne Begrifflichkeiten bedeuten:

Merkmale beim Einkauf

Programm- Speicher

Gibt an wie viel Speicherplatz der PIC für Befehle 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.

Pins

Gibt nur an wie viel Pins der PIC insgesamt hat. Also nur eine reine Größenangabe.

I/O-Pins

Hier wird angegeben wie viele der Pins, als IOs genutzt werden können.

ADC

Gibt an wie viele Eingänge des PICs als Analog Digital Wandler eingesetzt werden können.

USART (SCI)

Serielle Schnittstelle, die sich z.B. als RS232 verwenden lässt.

SSP (MSSP)

Synchrone serielle Schnittstelle, die sich als SPI wie auch als I2C verwenden lässt.

I2C

I2C-Bus Anschluss. Dieser Anschluss ist Bestandteil der (M)SSP.

(E)CCP

Anzahl der Capture/Compare/PWM-Module. Mit diesen Modulen lassen sich Impulse Messen und Erzeugen. 
Außerdem können pulsweitenmodulierte Signale ausgegeben werden.

Timer

Anzahl der Timer. Ist nur 1 Timer vorhanden, handelt es sich um einen 8-Bit-Timer. 
Bei 3 Timern sind 2 davon 16-Bit breit.

nanoWatt

Stromspartechnologie

Hardware

Ich werde in diesem Unterpunkt auf die grundlegendsten Hardwaremodule des PIC eingehen und versuchen diese zu erklären und aufzuzeigen, wie man mit ihnen umgehen kann. Dabei versteht es sich von selbst, dass Sie das hier gelesene nur durch ausprobieren erlenen und verfestigen können. Es gilt: "learning by doing" Die IO Pins werden übergangen (wurden weiter oben schon besprochen).


Die verschiedenen Timer

Ein PIC (Typenabhängig) beinhaltet verschiedene Sorten von Timern. Was kann man mit Timern machen? Nun die Timer bieten eine große Palette an Möglichkeiten. Man kann mit ihnen zum Beispiel die Länge eines Impulses zählen, welcher an einem Pin des PIC anliegt. Timer werden aber auch zum Beispiel verwendet um ein Pulsweiten Moduliertes (PWM) Signal zu erzeugen. Damit lassen sich z.B. LEDs "dimmen". Ausschlag gebend ist, dass die Timer der PIC per Software eingeleitet werden aber dann Hardwaremäßig völlig losgelöst vom PIC arbeiten, also kann man parallel zum Timer weiter Programmcode abarbeiten! Schauen wir uns die einzelnen Timer eines PIC doch mal an:


Timer0

Dieser Timer ist bei allen PIC vorhanden. Es handelt sich hierbei um einen einfachen 8 Bit Timer. Was bedeutet 8 Bit Timer? Das bedeutet, dass dieser Timer von 0 bis 255 zählen kann. Denn ein PIC rechnet im binären Zahlensystem siehe:

Wertigkeit 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
Bit 7 6 5 4 3 2 1 0

Der Timer0 erhält seinen Takt entweder über den Pin RA4 oder aber er arbeitet mit ¼ des PIC Taktes. Wobei er diesen Takt durch einen Vorteiler mit bis zu 1/256, in 8 Stufen, vor teilen kann. 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 1 hoch gezählt wird, wird das Bit T0IF im Register INTCON gesetzt, dies dient, wenn man mit dem Überlauf des Timer0 einen Interupt erzeugen möchte. Der aktuelle Zählstand des Timer0 steht im Register TMR0 und kann gelesen und beschrieben werden. Der Timer0 wird im OPTION Register eingestellt, siehe dazu das Datenblatt des jeweiligen PIC.

Wichtig: Wenn man schreibend auf das Register TMR0 zugreift, werden alle Zählimpulse vergessen und der Timer fängt von vorne an.

Damit der Timer0 Interrupt benutzt werden kann, muss das GIE (Global interrupt enable) Bit gesetzt werden, dies erlaubt generell Interrupts. Ist das GIE Bit 0, so kann kein Interrupt ausgeführt werden!


Der Timer0 wird mit folgenden Bits im OPTION Register eingestellt:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
RBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0

Erklärung der einzelnen Steuerbits:

PS0-2

Mit den Bits PS0 bis PS2 wird der Vorteiler für den Timer0 eingestellt. 
Er lässt s in acht Schritten einstellen. 
Von 1:2 bis 1:256 wobei PS2-PS0 000 einem Vorteiler von 1:2 entspricht.

PSA

Mit dem Bit PSA kann man einstellen für den der Vorteiler gelten soll. 
Man kann den Vorteiler entweder für den Timer0 verwenden oder für den WDT. 
In unserem Fall müssen Sie dieses Bit = 0 setzten, damit der Vorteiler dem Timer0 zugesprochen wird.

T0SE

Diese Option ist nur interessant, wenn Sie den Timer0 mit einem Takt über RA4 versorgen. 
Mit diesem Steuerbit entscheiden Sie wann der PIC den Timer0 um 1 weiterzählen lässt. 
Und zwar wird zwischen dem Inkrementieren bei steigender und bei fallender Taktflanke unterschieden.

T0SC

Hier wird zwischen den beiden Taktquellen unterschieden. Interner Takt (0) oder externer Takt über RA4 (1).

INTEDG

Nicht relevant für Timer0

RBPU

Nicht relevant für Timer0

Timer1

Im Gegensatz zum Timer0 ist der Timer1 ein 16 Bit Timer. Das heißt, dass dieser von 0-65535 zählen kann. Oder in hexadezimaler Schreibweise: 0x000 bis 0xFFFF. Der Time1 kann seinen Zähltakt entweder über den internen Quarztakt beziehen oder aber wie der Timer0 über einen IO [RC0 bzw. RC1] Pin des PIC. Sobald der Timer überläuft, setzt er das Bit TMR1IF gesetzt, welches ein Interrupt auslösen kann. Da der Timer1 ein 16 Bit Timer ist, der PIC aber nur 8 Bit Register hat, werden für das Zählen des Timer1 zwei Register benötigt; Das sind die Register TMR1L und TMR1H. Im Register TMR1L steht dementsprechend der niederwertige Teil und in TMR1H der höherwertige Teil. Man kann den Zählstand jederzeit lesen oder ändern. Wenn Sie beabsichtigen, den Timer1 mit einem externen Takt zu versorgen, dann beachten Sie folgendes:

Der Timer1 kann entweder über RC0 oder RC1 mit einem Zähltakt versorgt werden. Der Unterschied dabei ist, dass über RC1 das Signal erst über einen Verstärker geleitet wird und anschließend auf RC0 kommt. Somit wird RC0 automatisch zum Takt Ausgang.

Der Timer1 wird mit folgenden Bits im Register T1CON eingestellt:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
- - T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON

Erklärung der einzelnen Steuerbits:

TMR1ON

Das Bit schaltet den Timer1 ein (1) oder aus (0).

TMR1CS

Mit diesem Bit wählt man zwischen den Taktquellen für den Timer. Ist dieses Bit = 1, dann wird der Takt über RC0 / RC1 entnommen. 
Ist das Bit = 0, so wird der interne PIC Takt gewählt (¼ der Quarzfrequenz).

T1SYNC

Mit diesem Bit kann eine Synchronisation des externen Taktes mit dem internen Takt durchgeführt werden. 
Dieses Bit hat folglich keine Funktion, wenn TMR1CS = 0 ist.

T1OSCEN

Dieses Bit aktiviert den Verstärker zwischen RC1 und RC0 und ist nur von belangen, wenn man die Takt für den Timer1 extern wählt.

T1CKPS0-1

Ähnlich wie beim Timer0 kann man dem Timer1 einen Vorteiler vorschalten, welcher den Zähltakt teilt. 
Der Vorteiler lässt sich in vier Stufen einstellen wobei T1CKPS0-1 = 00 einen Vorteiler von 1:1 entspricht 
und 11 einen Vorteiler von 1:8 zur Folge hat.

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 Taktquarz an die Taktpins T1OSO und T1OSI des PIC angeschlossen. Dann bekommt der Quarz noch pro Beinchen einen Kondensator (10pF bei dem verlinkten Typ) gegen Masse und fertig. Der Timer1 zählt nun mit einem 32,768 KHz Takt, was genau 0x8000 entspricht. Also brauch der Timer1 für einen Überlauf (-> Intterrupt) von 0x8000 bis zum Überlauf genau 1 Sekunde. Somit hat man zum Beispiel den Takt für eine Uhr. Wenn der Quarz zu schnell oder zu langsam ist, kann man an dem Vorladewert, also den 0x8000 drehen und somit die Zeit bis zum Interrupt beeinflussen.

Vorgehen:

1. Timer1 konfigurieren (Externen Takt auswählen, Syncronisation aus) [T1CON]
2. TMR1 Interrupt konfigurieren [PIE1] , [IPR1]
3. Zähleregister TMR1H mit 0x80 vorladen
4. Zähleregister TMR1L löschen (ggf. anpassen bei Ungenauigkeiten des Uhrenquarzes)
5. In der ISR nur 1 Variable inkrementieren (+ 1 Sekunde)
6. Und danach (in der ISR) die Register (TMR1H und TMR1L) wieder auf 0x80 und 0x00 setzten

Timer 1 / 3 für das CCP Modul des PIC

Nach dem Starten ist der Timer1 standardmäßig der Taktgeber für beide CCP Module (sofern zwei vorhanden sind). Falls Ihr dies ändern möchtet müsst Ihr folgende Einstellungen im T3CON Register vornehmen:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
RD16 T3CCP2 T3CKPS1 T3CKPS0 T3CCP1 T3SYNC TMR3CS TMR3ON

Erklärung der einzelnen Steuerbits:

T3CCP2 - T3CCP1

[1x] = Timer3 ist die Capture/Compare Quelle für beide CCP Module
[01] = Timer3 ist die Capture/Compare Quelle für CCP2 und Timer1 ist die Capture/Compare Quelle für CCP1
[00] = Timer1 ist die Capture/Compare Quelle für beide CCP Module

Die restlichen Bits spielen für die Quellen-Verteilung keine Rolle, daher hier nicht weiter erklärt.

Timer2

Der Timer2 unterscheidet sich etwas zu den vorherigen besprochenen Timer Modulen. Dieser Timer ist wie der Timer0 wieder ein 8 Bit Timer allerdings mit einem Vor- und Nachteiler. Die Besonderheit des Timer2 ist, dass man ihn programmieren kann; Es lässt sich einstellen wann der Timer wieder bei 0 beginnt zu zählen. Im Gegensatz zu den Timern 0 und 1, kann der Timer2 nur über den internen PIC Takt laufen. Der aktuelle Zählstatus des Timer2 steht im TMR2 Register. Genau wie bei den anderen Timern, kann der aktuelle Zählstand ausgelesen oder verändert werden.

Programmieren des Timer2

Ich habe oben schon erwähnt, dass der Timer2 programmiert werden kann, das bedeutet, dass man dem Timer vorgeben kann, ab wann er wieder bei 0 anfangen soll zu zählen. Dies wird realisiert indem man die Abbruch-Zahl in das Register PR2 schreibt. Der aktuelle Zählstand wird nun ständig mit dem Wert in PR2 verglichen. Sind diese beiden Werte identisch, so wird der Timer2 dazu veranlasst, seine "Zählung" wieder bei 0 zu starten.

Pulsweiten Modulation

Der Timer2 lässt sich unter anderem auch zum Erzeugen von PWM Signalen nutzen. Und arbeitet dann mit dem CCP-Modul zusammen. Sobald der Timer2 überläuft, wird an dieses Modul ein Signal gesendet. PWM Nutzung

Der Timer2 wird mit folgenden Bits im Register T2CON eingestellt:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0

T2CKPS0-1

Hier kann der Vorteiler eingestellt werden. Ein Wert von '11' entspricht einem Vorteiler von 1:1. 
Ein Wert von '00' entspricht 1:16. (3 Schritte)

TMR2ON

1 = Timer2 ist eingeschaltet. 0 = Timer2 ist ausgeschaltet

TOUTPS0-3

Einstellung des Nachteilers: '0000' = 1:1 '1111' = 1:16


Timer3

Der Timer3 verhällt sich ähnlich wie der Timer1 und wird im T3CON Register konfiguriert.


Timer4

Der Timer4, welchen manche PIC18 haben, verhällt sich wie der Timer2.


Analog Digital Umsetzer

Analog-Digital-Umsetzer
Digital ist ja schön und gut, doch manchmal brauchen wir doch das Zusammenspiel mit der Analogtechnik. Und genau dafür hat ein PIC Mikrocontroller analoge Eingänge. Wie das funktioniert möchte ich Ihnen erklären. Zunächst erst einmal eine Schaltung:

Nun stellen Sie sich folgendes Beispiel vor: Sie wollen mit einem PIC ein Voltmeter bauen und müssen es daher irgendwie realisieren, dass Sie analoge Spannungen messen können. Diese Aufgabe ist mit einem Analog-Pin zu realisieren. Sie müssen dafür einen Spannungsteiler berechnen (Nur, wenn die zu messende Spannung größer als VDD des PIC ist), welcher die maximal zu messende Spannung auf die TTL Spannung von 5 Volt brechen. Denn ein Mikrocontroller verträgt nur maximal 5V an seinen IOs. Diese herunter geteilte Spannung können Sie nun in einen Digitalwert umwandeln, zurück rechnen (Spannungsteiler Verhältnis) und zum Schluss zum Beispiel auf einem LC Display ausgeben.

Hinweis: Achten Sie bei der PIC-Wahl darauf, dass Ihr PIC auch wirklich Analog Eingänge hat!


Grundlegendes

Der Analog-Digital Umsetzer des PIC hat eine Auflösung von 10 Bit. Ein PIC hat nur 1 ADU. Er kann aber von verschiedenen Pins des µC angesprochen werden (Stichwort: Multiplex). Wenn ein IO Pin eines PIC Zugriff auf den ADU hat, so wird er auch als ANx bezeichnet. Somit kann der PIC die maximale Spannung in 1024 Werte (10 Bit) einteilen. Bei einer maximal zulässigen Messspannung von 5V ergibt dies eine Auflösung von circa 5mV.

Nun kann es ja durchaus vorkommen, dass nur ein kleiner Spannungsbereich sehr genau gemessen werden muss. Zum Beispiel werden nur 0-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 entsprechen, sondern die Referenzspannung an AN2 (VREF -) und AN3 (VREF +) des PIC entnommen werden, so kann man die Auflösung (welche vorher auf den Bereich von 5V lag) nun auf einen kleineren Bereich einstellen und kann somit wesentlich genauer kleine Spannungen messen.

Dank an Stefan, für:

Um die maximale Genauigkeit mit einem 5V-PIC zu erreichen, sind, ja nach Typ, zwischen 2,5V und 3,0V Referenzspannung 
mindestens notwendig (sollte als Parameter AD06 und AD06A in den elektrischen Spezifikationen aufgeführt sein).

Nun schauen wir uns an, wie der Analog Digital Wandler eines PIC konfiguriert wird. Folgende Bits im den Registern ANSEL, ADCON0 und ADCON1 sind dafür nötig:

In der PIC18 Familie gibt es oftmals zusätzlich noch das ADCON0, ADCON1 und ADCON2 Register. In diesen Fällen wird häufig dann auch zwischen Analog/Digital in diesen Registern umgeschaltet. Es kann allerdings vorkommen (z.B.: PIC18F54K20), dass über Analog/Digital trotzdem im ANSEL Register entschieden wird.


ANSEL

Im ANSEL Register werden die gewünschten IOs ausgewählt, welche als analoge Eingänge verwendet werden sollen:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
- ANS6 ANS5 ANS4 ANS3 ANS2 ANS1 ANS0

Eine "1" in der entsprechenden Zelle setzt den IO Pins als analogen Eingang. Wenn ein PIN als analoger Eingang gewählt wird, dann muss das entsprechende TRIS Bit ebenfalls auf "1" gesetzt werden!

ADCON0

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

ADON

Dieses Bit aktiviert (1) den Umsetzer oder deaktiviert (0) ihn.

GO/DONE

Durch das setzen dieses Bits wird eine AD Umsetzung gestartet. Dieses Bit bleibt 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!

CHS0-2

Mit den Bits CHS0 bis CHS2 wird bestimmt, welche ANx gemessen werden soll. 
In der folgenden Tabelle können Sie die Kombinationen ersehen: 
CHS2 CHS1 CHS0
Channel 0 0 0 0
Channel 1 0 0 1
Channel 2 0 1 0
Channel 3 0 1 1
Channel 4 1 0 0
Channel 5 1 0 1
Channel 6 1 1 0

Beispiel von einem PIC16F88

ADCS0-1

Mit den Bits ADCx wird die Geschwindigkeit des ADUs eingestellt. Näheres dazu ist im jeweiligen Datenblatt des PIC nachzulesen!

Acquisition time

Bei der Geschwindigkeit sollte man beachten, dass der PIC genügend Zeit braucht um eine analog Messung durchzuführen, da er hierbei einen internen Kondensator auf die anliegende Spannung auflädt. 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 ja theoretisch 16 Bit lang, da der ADU des PIC aber "nur" eine Auflösung von 10 Bit hat, steht das Ergebnis bündig. Und zwar rechts oder links-bündig! Das hängt ganz davon ab, wie wir das Bit ADFM im Register ADCON1 gesetzt habe. Also schauen wir uns das Register ADCON1 an:

ADCON1

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
ADFM ADCS2 VCFG1 VCFG0 - - - -

VCFG0-1

Mit diesen beiden Bits können Sie die Referenzspannungsquelle auswählen. 
Bitte lesen Sie in Ihrem Datenblatt die Codierung nach. Standardmäßig ist 00 
und somit VDD und Vss des PIC als Referenz eingestellt.

ADCS2

Wenn dieses Bit "1" ist, wird der Takt des AD durch 2 geteilt.

ADFM

Mit diesen Bit wir ausgewählt, ob das Ergebnis in ADRESL & ADRESH rechts- oder links-bündig ausgegeben wird. 
Rechtsbündig (1) Linksbündig (0)


Sonstiges

Wenn Sie mit dem Analog Digital Umsetzer einen Interrupt auslösen wollen, müssen Sie die Register INTCON, PIE1 und PIR1 beachten. Im Forum von PIC-Projekte.de können Sie jederzeit nach Hilfe fragen. Es wird Ihnen dann gerne bei Ihrem Problem geholfen.

Beispiel zum Konfigurieren des Analog-Digital-Umwandlers:

  1. /**********************************************************
  2. Hier wird ein Analog-Digital Umwandler konfiguriert.
  3. Beispiel am PIC18F4550
  4. **********************************************************/
  5.  
  6. void Setup_ADC(void)
  7. {
  8.   ADCON0bits.ADON=0;
  9.   TRISAbits.TRISA0=1;
  10.   ADCON2=0x3C;
  11.   ADCON2bits.ADFM = 1;
  12.   ADCON0bits.ADON=1;
  13. }

Beispiel zur Wandlung:

/**********************************************************
Zunächst werden die nötigen CHS Bits so eingestellt damit
der gewünschte Analog-Pin mit dem ADU des PIC verbunden
wird. Der gewünschte ANx Pin wird der Funktion übergeben
und ist somit in der Variable "Channel" verfügbar.
 
Untern wird dann die Umwandlung durchgeführt und solange
gewartet bis der Analog-Digital Umwandler fertig ist.
 
Anschließend werden die beiden 8 Bit Register (Ergebnis
der Umwandlung) des ADU in eine 16 Bit Variable
umgerechnet und kann somit für weitere Operationen
verwendet werden. Bei Fragen zum Programm melden sie sich
im PIC Forum unter: www.PIC-Projekte.de/phpBB3/
**********************************************************/
 
void Read_ADC(unsigned char Channel)
{
  switch(Channel)
    {
    case 0:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=0;
      break;
    case 1:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=0;
      break;
    case 2:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=0;
      break;
    case 3:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=0;
      break;
    case 4:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=1;
      ADCON0bits.CHS3=0;
      break;
    case 5:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=1;
      ADCON0bits.CHS3=0;
      break;
    case 6:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=1;
      ADCON0bits.CHS3=0;
      break;
    case 7:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=1;
      ADCON0bits.CHS3=0;
      break;
    case 8:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=1;
      break;
    case 9:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=1;
      break;
    case 10:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=1;
      break;
    case 11:
      ADCON0bits.CHS0=1;
      ADCON0bits.CHS1=1;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=1;
      break;
    case 12:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=1;
      ADCON0bits.CHS3=1;
      break;
    default:
      ADCON0bits.CHS0=0;
      ADCON0bits.CHS1=0;
      ADCON0bits.CHS2=0;
      ADCON0bits.CHS3=0;
    }
 
  ADCON0bits.GO = 1;            
  while(ADCON0bits.NOT_DONE);    
  ADWERT=ADRESH;
  ADWERT=ADWERT<<8;
  ADWERT=ADWERT+ADRESL;
}

Bei Problemen können Sie sich jederzeit im PIC-Forum melden.

Capture Compare Modul / PWM

Mit dem Captuer / Compare Modul eines PIC lassen sich verschiedene Aufgaben bewältigen. Durch den Capture Eingang lässt sich der genau Zeitpunkt bestimmen, an dem ein Signal am Pin RC2 (und wenn der PIC zwei CCP Module besitzt am RC1) eintrifft. Der Compare Modus ist quasi das Pferd von hinten aufgezogen; Hier lässt sich am RC2 (und teilweise am RC1) zu einem exakt bestimmten Zeitpunkt ein Signal (o. Flanke) erzeugen. Der PWM Modus hingegen eignet sich zum erstellen eines pulsweiten modulierten Signals (PWM). Während der Capture und Compare Modus den Timer1 oder Timer 3 verwendet arbeitet der PWM Modus mit dem Timer2 zusammen. Daher muss man auch darauf achten, welche Modis man anwendet, da dann die Timer "verbraucht" sind.

Der Unterschied zwischen CCP und ECCP
Viel PIC haben auch mehrere CCP oder ECCP Module an Board. Das ECCP Modul kann PWM Signale an mehreren Ausgängen bereit stellen.

Pulsweitenmodulation (PWM)

PWM Signal
Jeder PIC18 und teilweise auch manche PIC16 besitzen das Capture, Compare, PWM (CCP) Modul mit dem man zusammen mit dem Timer2 ein Pulsweitenmoduliertes Signal (kurz PWM) erzeugen kann. Ich möchte Euch hier kurz erklären wie Ihr mit dem Modul umzugehen habt. Der Timer2 wird mit 1/4 des am PIC angeschlossenen Quarz Taktes gespeist und kann zusätzlich noch über einen Vorteiler des Timer2 in drei Stufen geteilt werden (1, 4, 16). Im Prinzip sind für den PWM Mode nur zwei Register von "Bedeutung": Das Register CCPR1L und PR2. Während der Timer2 immer bei 0 beginnt zu zählen wird der aktuelle Zählerstand (TMR2) immer mit dem Wert in PR2 und CCPR1L verglichen. Wenn der Zählstand des Timers dem Wert in CCPR1L entspricht, dann wird der CCP1 Ausgang (Pin) gelöscht, also auf Low (0V) gesetzt. Wenn der Wert dem in PR2 entspricht, dann wird der Ausgang auf High (=5V) gesetzt und der Timer2 beginnt wieder von 0 an zu zählen. Hier eine kleine Grafik zur Veranschaulichung (siehe rechts).

Da man "10 Bit PWM" sagt aber der Timer2 und das PR2/CCPR1L Register ja eigentlich nur 8 Bit groß sind, bekommt das CCPR1L Register zwei zusätzliche Bits spendiert, welche im CCPCON Register übrig sind. Also lässt sich die Periode trotzdem nur mit 8 Bit einstellen (Timer2 und PR2) aber das Tastverhältnis kann in 10 Bit eingestellt werden.

Vorgehensweise zum Nutzen des CCP Moduls zur PWM Erzeugung

  1. Timer2 einstellen
  2. Periode einstellen
  3. Tastverhältnis einstellen
  4. PWM aktivieren


Beispiel am PIC18F4550

Nicht vergessen das CCP Pin zum Ausgang zu machen (TRISx=0)

void configPWM(void)
{
  PR2=0xFF;             // Größt mögliche Periodendauer
  CCPR1L=0xFF;          // Hier wird das Tastverhältnis eingestellt
  CCP1CON=0x0C;         // PWM Mode ausgewählt
  T2CON=0x79;           // 1:16 Postscale, Timer2 aus, Prescale=4
  T2CONbits.TMR2ON=1;   // Timer2 an
}

Formel zum Errechnen der Periodendauer

PWM Period = [(PR2) + 1] * 4 * TOSC * (TMR2 Prescale Value) 

Formel zum Errechnen von PR2

PR2 = [ PWM_Periode / (4 x Tocs x TM2PS) ] -1

Formel zum Errechnen des Tastverhältnissis

CCPR1L / PR2 
Jetzt könnte man das CCPR1L Register verändern und somit das Tastverhältnis beeinflussen. Sowas ist zum Beispiel sehr nützlich um bei LCD Displays die Hintergrundbeleuchtung weich zu regeln.

Capture Funktion

Mit der Capture Funktion des CCP Moduls eines PIC kann man die exakte Zeit messen bis ein Pegelwechsel am RC2 Pin (Bei PIC mit 2 CCP Modulen kann auch die Zeit am RC1 Pin gemessen ermittelt werden)* eintritt. Für die Funktion wird der Timer1 benötigt. Er zählt die Zeit bis das Ereignis am Pin eintritt. Natürlich muss der Timer1 hierfür auch entsprechend eingestellt werden. Eine weitere Einstellmöglichkeit ist die Art auf die das Modul reagiert (High to Low Flanke, ...) dazu später mehr. Folgend ist aufgezeigt wie das CCP1 Modul eines PIC18F4550 genutzt werden kann:

  • Beispiel am PIC18F4550, viele PIC haben noch mehr (E)CCP Module
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
P1M1 P1M0 DC1B1 DC1B0 CCP1M3 CCP1M2 CCP1M1 CCP1M0

CCP1M0-3

Mit diesen Bits wird eingestellt in welchem Modus sich das CCP Modul befinden soll 
und ihr könnt einstellen auf welche Ereignisse das Modul reagieren soll:
[0100] Jede fallende Flanke 
[0101] Jede steigende Flanke 
[0110] Jede 4te steigende Flanke 
[0111] Jede 16te steigende Flanke 

DC1B0-1

Sind im Capture-Mode ungenutzt

P1M0-1

Sind im Capture-Mode ungenutzt

Das Ergebnis der Zeitmessung steht in den Registern CCPR1L / CCPR1H bzw. CCPR2L / CCPR2H.

Interrupt - Der Captuer Modus kann auch einen Interrupt auslösen. Jedes mal, wenn eine Flanke erkannt wurde und somit der Zählstatus gesichert ist, wird das CCP1IF im PIR1 gesetzt. Dieses muss in der Interrupt Service Routine unbedingt wieder gelöscht werden, da der PIC sonst in einer Endlosschleife fest steckt. Damit der Interrupt genutzt werden kann müssen zusätzlich die GIE/GIEH(3) und PEIE/GIEL(3) Bits im INTCON Register gesetzt werden.

Beachten beim Arbeiten mit dem CCP
Damit das Capture Modul arbeiten kann muss unbedingt der Timer1 oder der Timer3 richtig konfiguriert werden.

(3) Wenn durch das Setzten vom IPEN Bit im RCON Register die Interrupt Priorität erlaubt ist, heißen die Bits GIEH und GIEL. Können jedoch weiterhin mit GIE und PEIE angesprochen werden.

Eine mögliche Anwendung für das Modul währe ein Drehzahlmesssystem.

Grafik zum Capture Mode:

Capture Mode PAP.png

Siehe auch: Diagramm zum Capture Mode

Compare Funktion

Das Compare-Modul ermöglicht es einem ein Signal bzw. einen Flankenwechsel am Pin RC2 (Bei PIC mit 2 CCP Modulen kann auch man Pin RC1 ein Signal erzeugt werden)* zu einem exakt bestimmten Zeitpunkt zu erzeugen. Das Modul arbeitet mit dem Timer1 oder dem Timer3. Es wird in dem 16 Bit Register (2x8) ein Wert vorgegeben, wenn der Zählwert des Timer1 diesen Wert erreicht hat wird der Flankenwechsel am Pin durchgeführt. Hier sind die Einstellungen zum Compare Modus einzustellen:

  • Beispiel am PIC18F4550, viele PIC haben noch mehr (E)CCP Module
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
P1M1 P1M0 DC1B1 DC1B0 CCP1M3 CCP1M2 CCP1M1 CCP1M0

CCP1M0-3

Mit diesen Bits wird eingestellt in welchem Modus sich das CCP Modul befinden soll 
und ihr könnt einstellen auf welche Ereignisse das Modul reagieren soll:
- [1000] Pin geht nach eintreten von Low auf High (+CCP1IF)
- [1001] Pin geht nach eintreten von High auf Low (+CCP1IF)
- [1010] Ausgang wird nicht verändert (+CCP1IF)
- [1011] Ausgang wird nicht verändert (+CCP1IF + Timer1 auf 0) 

DC1B0-1

Sind im Compare-Mode ungenutzt


P1M0-1

Sind im Compare-Mode ungenutzt

Interrupt - Der Captuer Modus erzeugt natürlich auch einen Interrupt und setzte das CCP1IF im PIR1 Register (bzw. das CCP2IF, wenn ein zweites CCP Modul im PIC vorhanden und genutzt ist). Wie auch im Capture Modus und generell bei jedem Interrupt muss das Flag (CCP1IF) in der ISR unbedingt wieder gelöscht werden. Damit der Interrupt genutzt werden kann müssen zusätzlich die GIE/GIEH(1) und PEIE/GIEL(1) Bits im INTCON Register gesetzt werden.

(1) Wenn durch das Setzten vom IPEN Bit im RCON Register die Interrupt Priorität erlaubt ist, heißen die Bits GIEH und GIEL. Können jedoch weiterhin mit GIE und PEIE angesprochen werden.

Grafik zum Compare Mode:

Compare Mode PAP.png

Siehe auch: Diagramm zum Compare-Mode

Hinweis: Ihr müsst den Timer Zählstand (TMRxL und TMRxH) selbstständig wieder resetten!

Stack

Die PIC18 Familie besitzt einen 32 Level großen Hardware Stack (im Vergleich haben die PIC16 lediglich einen 8 Level Stack). Der Stack ist ein sogenannter Stapelspeicher, welche das "hopping" im Programm ermöglicht. Im Stack wird bei einem Sprung zu einer Funktion/Unterprogramm die Adresse gesichert von der aus los gesprungen wurde, damit bei vollständiger Abarbeitung des Uterprogramms oder der Funktion wieder an diese Adresse zurück gesprungen werden kann. Dabei ist auch die Sichtbarkeit von Variablen zu beachten: Angenommen Ihr habt eine globale Variable namens "x" und ihr springt nun in eine Funktion und definiert hier eine neue Variable, welche ebenfalls "x" heißt, dann ist dir globale Variable für die Zeit in der Funktion unsichtbar bleibt aber erhalten und ist bei Rückkehr in die obere Ebene des Stack wieder sichtbar.

I2C

Siehe auch hier für I2C Routinen für PIC (am Beispiel eines PIC18LF45K22): Klick

Allgemeines

I2C Bus Muster
Sobald euer PIC ein master synchronous serial port (kurz MSSP) Modul besitzt könnt ihr damit einen I2C Bus aufbauen um damit dann ein gewünschtes Bauteil, welches selbstverständlich seinerseits auch den I2C Bus verwendet, ansprechen könnt. Der I2C Bus ist eine Bus bestehend aus zwei Leitungen: Serial clock (SCL) und Serial data (SDA). Damit der Bus unabhängig von allen Teilnehmern benutzt werden kann werden die beiden Busleitungen mit Pullup Widerständen (~1k8) gegen +5V gezogen. Die Namen der Leitungen sind Programm; Auf der SCL Leitung wird der Takt des Bus übertragen, welcher ausschließlich vom Master erzeugt wird. Der Slave hat lediglich die Möglichkeit den Slave seinerseits gegen Masse zu ziehen um zum Beispiel zu signalisieren, dass er mehr Zeit benötigt. Auf der SDA Leitung werden entsprechend die Datenpakete zum Slave (schreibend) oder vom Slave (lesend) übertragen. Die einzelnen Bit eines Byte die auf dem Bus, egal ob lesend oder schreibend, übertragen werden fangen immer mit dem MSB an. Während die SCL Leitung High-Zustand hat, darf auf der SDA Leitung nichts mehr geändert werden (dies würde sonst als Befehl interpretiert). Ein Bit wird mit einem Impuls auf SCL übertragen, dazu später mehr. Sie müssen dem PIC mitteilen mit welcher Taktgeschwindigkeit sie den IC2 Bus betreiben möchten, dazu ist es notwendig das Register SSPADD mit einem passenden Teilerwert zu beschreiben. Dieser errechnet sich wie folgt:
SSPAD = ( FOSC / 4*SCL ) - 1

Beispiel anhand eines SCL Taktes von 50kHz und einem PIC Quarz von 8MHz:

SSPAD = ( 8MHz / 4*50kHz ) - 1 = 39
Die Pullup Widerstände (~1k8) an SDA und SCL dürfen nicht vergessen werden. Es kann sonst keine Kommunikation stattfinden!

Start/Stop

I2C Start/Stop
Der I2C Bus wird im wesentlichen in drei verschiedenen Geschwindigkeiten betrieben: 3,4 Mbit/s (Highspeed), 400 kHz (Fast) und mit 100 kHz (Standard). Dabei gilt es auch immer im Datenblatt der verwendeten Slaves zu beachten, welche Taktgeschwindigkeiten diese unterstützen. Zum Beispiel ist es bei einem DS1307 nicht empfehlenswert den Takt oberhalb von 100 kHz zu betreiben, da dies die absolute Grenze bei diesem Baustein ist.

Jede Aktion auf dem Bus wird vom Master gestartet über die I2C-Start Sequenz. Dazu muss sich der Master vergewissern, dass der Bus derzeit frei (SCL und SDA sind high) ist (eigentlich nur bei Multi-Master-Systemen notwendig) und beginnt dann mit seiner Arbeit. Für eine Start Sequenz zieht der Master das Potential von SDA auf low während SCL noch auf high ist. In Umgekehrter Reihenfolge ist dies eine Stop Sequenze.

Adressierung

Hat ein Master erst einmal eine Start Sequenz auf dem Bus eingeleitet werden alle am Bus angeschlossenen Slaves hellhörig und wollen nun wissen an wen sich der Master richtet. Dafür überträgt der Master nun eine 7 Bit lange Adresse, welche eindeutig einen der am Bus angeschlossenen Slaves entspricht. Alle anderen interessieren sich nun nicht mehr für die Daten. Das 8. Bit des Adressbytes ist das Richtungsbit. Dieses sagt aus ob der Master Daten zum Slave schicken möchte (0) oder ob er Daten vom Slave haben möchte (1).

ACK

I2C Kommunikation
Wenn sich nun ein Slave durch Übereinstimmung der Adresse angesprochen fühlt quittiert er dieses mit einer ACK Sequenz (Acknowledge). Die Datenpakete (Bytes [Bits]), welche dem Adressierungsbyte folgen müssen ebenfalls mit einem ACK vom Slave bestätigt werden. Folgt auf ein gesendetes Byte ein NACK ist die Übertragung fehlgeschlagen und der Master muss die Übertragung des Bytes wiederholen. Ein ACK sieht auf dem Bus so aus: Der Maste überträgt mit 8 Impulsen auf SCL die einzelnen Bit des Byte auf SDA (angefangen mit MSB) und erzeugt im Anschluss einen 9. Impuls auf SCL. Wenn der Zustand beim 9. Takt einen Low Zustand auf SDA aufweist (vom Slave auf Low gezogen, nicht vom Master!), dann ist es ein ACK. Ist der Zustand hingegen High, so ist es ein NACK.

Anwendung

Ich würde euch hier empfehlen die Libraries des C18 Compilers zu verwenden um das MSSP Modul als I2C Interface zu nutzen. Ich zeige euch nun eine kleine Beispiel Routine, welche einen DS1307 anspricht und ein Datenbyte an diesen Überträgt (nicht wichtig für das Verständnis des I2C Bus aber interessant: Der DS1307 wird angesprochen, dann wird der Pointer des DS1307 auf 0x07 gesetzt damit der DS1307 weiß wohin er das Byte schreiben soll. Im Anschluss übertrage ich 0x90, was den DS1307 dazu veranlasst einen Takt von 1 Hz an seinem Pin SQW auszugeben):

  1. #include <i2c.h>
  2.  
  3. // ...
  4.  
  5. /*I2C Bus Einstellungen*/
  6. CloseI2C();
  7. OpenI2C(MASTER,SLEW_OFF);       // I2C einstellen
  8. SSPADD=39;                      // 50kHz=8MHz/(4*(SSPADD+1))
  9.  
  10. // ...
  11.  
  12. data = SSPBUF;                  // Buffer leeren
  13. IdleI2C();                      // Verweilen bis der Bus frei ist
  14. StartI2C();                     // Start I2C
  15. while ( SSPCON2bits.SEN );      // Warten bis I2C Start zu Ende ist
  16.  
  17. do
  18. {
  19.     error=WriteI2C(0xD0);       // DS1307 Adresse (8.Bit ist Null -> senden)
  20.     if(error)                   // Ist ein Fehler aufgetreten?
  21.     {
  22.         data = SSPBUF;          // Buffer leeren
  23.         SSPCON1bits.WCOL=0;     // Bus Kollisions-Statusbit löschen
  24.     }
  25. }while(error);                  // Solange bis die Kommunikation klappt
  26.  
  27. IdleI2C();
  28. WriteI2C(0x07);                 // DS1307 Pointer setzten
  29. IdleI2C();
  30. WriteI2C(0x90);                 // Controll Register füllen
  31. IdleI2C();
  32. StopI2C();                      // Stop I2C
  33. while ( SSPCON2bits.PEN );      // Warten bis I2C Stop zu Ende ist

Oder so am Beispiel eines PIC18LF45K22:

  1. uint8_t sendI2C(uint8_t byte, bool rw)
  2. {
  3.     uint8_t incomming = 0;
  4.  
  5.     if(!rw)
  6.     {
  7.         /*Byte senden*/
  8.         SSP2BUF = byte;
  9.         /*Auf ACK warten*/
  10.         while(!PIR3bits.SSP2IF);
  11.         PIR3bits.SSP2IF = 0;
  12.     }
  13.     else
  14.     {
  15.         /*Byte empfangen*/
  16.         SSP2CON2bits.RCEN = 1;
  17.         while(!PIR3bits.SSP2IF);
  18.         PIR3bits.SSP2IF = 0;
  19.         incomming = SSP2BUF;
  20.     }
  21.  
  22.     /*Nur empfangen wenn rw true*/
  23.     return incomming;
  24. }
  25.  
  26. void startI2C(void)
  27. {
  28.     PIR3bits.SSP2IF = 0;
  29.  
  30.     /*Start condition erzeugen*/
  31.     SSP2CON2bits.SEN = 1;
  32.     while(!PIR3bits.SSP2IF);
  33.     PIR3bits.SSP2IF = 0;    
  34. }
  35.  
  36. void stopI2C(void)
  37. {
  38.     /*Stop condition*/
  39.     SSP2CON2bits.PEN = 1;
  40.     while(!PIR3bits.SSP2IF);
  41.     PIR3bits.SSP2IF = 0;
  42. }

So sieht Beispielsweise eine gängige Übertragung aus (hier wird in die Speicheradresse 0x00 einer RTC PCF8583 geschrieben):

  1. /*I2C Makros*/
  2. #define PCF8583_ADDR    0xA0
  3. #define IIC_READ        1
  4. #define IIC_WRITE       0
  5.  
  6. //...
  7.  
  8. void initPCF8583(void)
  9. {
  10.     startI2C();
  11.     sendI2C(PCF8583_ADDR,IIC_WRITE);
  12.     sendI2C(0x00,IIC_WRITE);
  13.     sendI2C(0xC8,IIC_WRITE);
  14.     stopI2C();
  15. }

Diese Initialisierungs-Sequence sieht auf SDL und SCL so aus: I2c pcf8583 init.png

SPI

Schaut euch ergänzend auch das Einsteiger PDF zum SPI Bus von Microchip an.

Das Serial Peripheral Interface (kurz SPI) ist ein von Motorola entwickeltes Bus-System mit einem sehr lockeren Standard für einen synchronen seriellen Datenbus, mit dem digitale Schaltungen nach dem Master-Slave-Prinzip miteinander verbunden werden können. Ein ähnliches Bus-System existiert von National Semiconductor und nennt sich Microwire.

Für den Bus sind die nachfolgend aufgeführte Leitungen notwendig an denen alle Busteilnehmer angeschlossen sind:

  • SDO (zu Englisch Serial Data Out) bzw. MISO oder SOMI (zu Englisch Master in, Slave out)
  • SDI (zu Englisch Serial Data In) bzw. MOSI oder SIMO (zu Englisch Master out, Slave in)
  • SCK (zu Englisch Serial Clock) bzw. SCLK, wird vom Master ausgegeben

Zusätzlich wird für jeden am Bus angeschlossenen Slave eine weitere Leitung benötigt. Diese Leitung wird ¬Slave select (kurz ¬SS) genannt und ist in den meisten Fällen low aktiv. Das bedeutet, dass wenn der Master eine ¬SS-Leitung auf low zieht, dann ist dieser Slave angesprochen und reagiert auf folgende Daten. Die SS Leitung kann durch jeden beliebigen I/O des PIC realisiert werden. Da der SPI Bus, wie zu Beginn dieses Abschnitts bereits erwähnt, sehr locker definiert ist, sind viele Parameter frei konfigurierbar. Das war auch einer der Gründe weshalb sich dieses Bussystem so weit verbreitet hat.

Der SPI Bus beim PIC

Viele PIC unterstützen die Verwendung des SPI Bus. Dafür werden entsprechende Module zur Verfügung gestellt. Es kann entweder das SSP oder das MSSP Modul verwendet werden. Eine Datenübertragung findet logischerweise nur statt, wenn der Clock aktiv ist. Wobei wir auch bei einem weiteren wichtigem Punkt sind: Der Takt auf der SCK Leitung wird ausschließlich vom Master generiert. Um das SPI bzw. das SSP/MSSP Modul nutzen zu können ist es vorweg nötig das Modul entsprechend zu konfigurieren. Das zuständige Register ist das SSPCON Register:

  • SSPOV: Wird gesetzt wenn es einen Überlauf gab und muss vom Programmierer zurück gesetzt werden.
  • SSPEN: Ein-/ Ausschalten (Strom sparen) des SSP-Moduls.
  • CKP: Einstellen der Takt Polarität.
  • SSPM3:SSPM0 (4 Bits):

SSPOV
Das SSPOV Bit ist der Indikator für ein eventuell aufgetretenes Überlaufen des Puffers. Nachdem ein Byte empfangen wurde muss dieses aus dem Puffer (Register SSPBUF) ausgelesen werden. Wenn das nicht erfolgt, wird SSPOV gesetzt. Außerdem wird der Inhalt des Puffers nicht mehr aktualisiert, solange das Bit gesetzt ist! Das Bit muss eigenhändig wieder gelöscht werden!

SSPEN
Wie es der Name des Bits schon vermuten lässt, wird durch das setzten dieses das SSP Modul aktiviert bzw. wird es deaktiviert wenn das Bit gelöscht ist. Ein löschen des Bits und somit das deaktivieren ist empfehlenswert bei low power Anwendungen um Stro zu sparen. Es versteht sich von selbst, dass das Bit nicht gelöscht werden darf, solange das SSP Modul in Benutzung ist. CKP
Dieses Bit konfiguriert die Polarität des Taktes...

SSPM#
Die vier Bits von SSPM0 bis SSPM3 sind zuständig um den SPI Mode einzustellen. Wenn der Master Mode eingestellt ist, wird mit diesen Bits zusätzlich die Clock Frequenz geregelt. Näheres steht dann im Datenblatt eures PIC.

Ein weiteres Register, welches direkt mit dem SPI Bus bzw. mit dem SPI Bus in Bezug auf den PIC zu tun hat ist das SSPSTAT Register (Synchronous Serial Port STATus), welches den aktuellen Status des Moduls wieder spiegelt:

  • SMP: Bitte Detailbeschreibung lesen.
  • CKE: Bitte Detailbeschreibung lesen.
  • BF: Buffer full sagt, wenn eine Übertragung abgeschlossen ist.

SMP

SPI Mode Waveform
Das Bit SaMPle timing (kurz SMP) kontrolliert die Daten Absatzrate. Wenn der PIC als Slave betrieben wird muss dieses Bit durch den Programmierer gelöscht werden. Wenn ihr dieses Bit setzt, dann werden die Daten auf SDI am Ende der Ausgabe erfasst. Ist das Bit hingegen gelöscht, so werden die Daten in der Mitte erfasst. Seht euch einfach mal die Grafik (rechts) dazu an.

CKE
Das CKE Bit muss in Zusammenhang mit dem CKP Bit gesehen werden. Wenn das CKE Bit gesetzt wird, dann werden die Daten beim Wechsel des Potentials auf der SCKx Leitung von Aktive zu Leerlauf (idle) versendet. Ist das CKE Bit gelöscht, dann beim Wechsel von Leerlauf zu Aktiv! Dies muss dann wie gesagt immer im Zusammenhang mit dem CKP Bit betrachtet werden. Es ergeben sich somit vier verschiedene Clock Modes, welche sehr schön aus der Grafik (rechts) ersichtlich sind.

Der SPI Bus kann somit also in vier verschiedenen Modi betrieben werden:

SPI Mode CKP CKE
0,0 0 1
0,1 0 0
1,0 1 1
1,1 1 0
Beispiel einer Übertragung
Die grün hinterlegten Parameter bzw. der grün hinterlegte SPI Mode ist der am häufigsten verwendete Mode.

BF
Dieses Bit sagt aus ob eine Konversation abgeschlossen ist oder eben noch läuft. Sobald dieses Bit logisch 1 ist, muss der Puffer SSPBUF ausgelesen werden. Das Bit wird automatisch gelöscht, sobald der Puffer gelesen wurde. Nochmal: Der Puffer muss nach empfangenen Daten gelesen werden! Ist das BF Bit 1 und das SSPBUF Register wird nicht ausgelesen, wird automatisch SSPOV gesetzt.


Q: Aber wie sagt man dem PIC denn nun, was gesendet werden soll? Oder wo kann ich die empfangenen Daten her holen?
A: Das zu übertragende Byte wird in das SSPBUF Register gelegt und automatisch versendet.

Codebeispiel

Bitte beachten, dass dies das simpelste Beispiel ist um den SPI Bus zu benutzen. Der Code ist nicht optimal, da ein Error-Handling nicht implementiert ist! Dabei ist zu beachten, dass die IOs richtig konfiguriert sind (Tris Bits)! Initialisierung des SPI Interfaces anhand eines Beispiels am PIC18LF45K22:

void initSPI(void)
{
    // SPI Mode 1,0
    SSP1CON1 = 0b00010010;  // Clock = FOSC/4 und CKP = 1
    SSP1STATbits.CKE = 0;   // CKE = 1
    SSP1CON1bits.SSPEN = 1; // SPI Modul ein
}

Übertragung eines Bytes über den SPI Bus. Der Rückgabewert kann muss aber nicht verarbeitet werden.

//...
#define CS1B    LATAbits.LA0    // Low aktiv!
//...
 
unint8_t sendSPI (unint8_t byte)
{
    unint8_t tmp;
 
    CS1B = 0;
    SSPBUF = byte;
    while(!SSP1STATbits.BF);
    tmp = SSPBUF;
    CS1B = 1;
    return tmp;
}

Interrupts

Oftmals kommt es vor, dass wir, bzw. der PIC, auf ein bestimmtes Ereignis reagieren soll. Nun verwendet man hierfür als Anfänger gerne mal das so genannte "Polling". Zum Beispiel: Der Mikrocontroller soll, sobald am PORTB,x eine Zustandsänderung eintrifft eine LED schalten. Nun gibt es hierfür zwei Lösungsmöglichkeiten:


Polling

Beim "Polling" würden wir nun in einer Schleife solange den Zustand von dem Pin abfragen, bis er den gewünschten Zustand erreicht hat und würden anschließend mit dem Schalten der LED fortfahren. Nun, dies ist sicherlich eine Möglichkeit. Allerdings ist sie wenig Sinnvoll, da der Mikrocontroller sich ausschließlich damit beschäftigen kann den Zustand vom Port-Pin abzufragen.


Interrupt

Mit einem Interrupt (on change) wäre dieses Problem deutlich eleganter gelöst. Wir setzten gewisse Steuerbits, welche bewirken, dass sobald sich der Zustand am Port-Pin ändert, der PIC seinen aktuellen Befehl noch ausführt und im Anschluss sofort zu einer bestimmten Adresse springt und den Code abarbeitet den er dort findet. Es wird also im Prinzip ein Unterprogramm automatisch aufgerufen. Der große Vorteil daran ist, dass wir während wir auf die Zustandsänderung am Port-Pin "warten" trotzdem parallel noch weiter arbeiten können!

Grafik zur Interrupt Logic bei PIC18F (Klick auf die Grafik für volle Auflösung):

INT Logic.PNG


Interrupt Quellen

Nun kann der PIC natürlich nicht nur auf das Ändern eines Zustandes einen Interrupt auslösen. Nein! Es gibt diverse Möglichkeiten, welche einen Interrupt auslösen können. Sie können die Interrupt Quellen Ihres PIC im Kapitel "DEVICE OVERVIEW" vom Datenblatt lesen. Dieses Kapitel ist für gewöhnlich unter Punkt 1.0 zu finden.


Beispiele

Interrupt on change

Dieser Interrupt wurde oben schon angesprochen. Er löst aus, sobald an einem Pin ein Zustandswechsel auftritt, dabei unterscheidet man zwischen fallender und steigender Flanke des Signales.

Timer0 Interrupt

Dieser Interrupt wird ausgelöst, sobald der Timer0 überläuft. Spricht sobald der Zähler von 255 um 1 inkrementiert und somit wieder bei 0 anfängt zu zählen wird dieser Interrupt ausgelöst.


Konfigurationen von Interrupts

Natürlich funktionieren die Interrupts nicht einfach so ohne jegliches Zutun. Nein. Interrupts sind im Normalzustand deaktiviert bzw. verboten. Damit man einen Interrupt benutzen kann, muss man das entsprechende Bit setzten, welches den Interrupt zulässt. Außerdem muss man (PIC16F) das GIE Bit setzten. Dieses Bit ist das "Global Interrupt Enable" Bit und kann beim Zustand "0" alle Interrupts verbieten. Was nicht bedeutet, dass alle INT erlaubt sind, sobald GIE=1 ist. Dafür hat jeder einzelne INT sein eigenes E-Bit (enable Bit).

Außerdem hat jeder Interrupt ein eigenes Flag, welches das Auftreten eines INT signalisiert. Zum Beispiel wird bei einem Timer0 überlauf das Bit T0IF Bit gesetzt, somit weiß der PIC, dass der Timer0 einen Interrupt auslösen möchte, dieses wird aber nur passieren, wenn das zugehörige Enable Bit T0IE (Timer0 Interrupt Enable) Bit ebenfalls "1" ist und zusätzlich das GIE Bit die Interrupts überhaupt zulässt.


Besonderheit bei PIC18F

Bei den PIC18F Typen werden verschiedene Interrupt Prioritäten unterschieden (Low & High). Diese haben auch zwei unterschiedliche Interrupt-Vektoren. Daher gibt es bei den PIC18F Typen auch zwei globale Enable Bits. Einmal das GIEL und das GIEH Bit. Ist das GIEL Bit auf disable, so können keine Interrupts, welche als "Low priority" deklariert sind ausgeführt werden - "high priority" Interrupts hingegen schon, wenn das GIEH Bit auf enable steht. Ist hingegen das GIEH Bit aus disable, können weder Low noch High- priorisierte Interrupts ausgeführt werden. Wir stellen also fest, dass das GIEH Bit übergreifend auch die Low INT sperren kann aber nicht umgekehrt! Hinweis: Wenn Sie verschiedene Interrupt Prioritäten verwenden möchten, dann müssen Sie das Bit IPEN im Register RCON setzten.

Einstellen der Interruptpriorität
Die Einstellungen zur Priorität eines Interrupts werden im Register IPR (PERIPHERAL INTERRUPT PRIORITY REGISTER) eingstellt. Jeder Interrupt hat hier ein Bit für 1=High und 0=Low

Achtung

Da aber der Stack eine endliche Größe besitzt, von nur einem Registersatz (W, STATUS und BSR), kann es bei der Aktivierung von
Interruptprioritäten passieren, dass diese Register überschrieben werden. Denn wenn ein Interrupt mit höherer Priorität 
auftritt, während sich das Programm in einer Interrupt-Routine eines niedrigen Priorität befindet, wird der Stack mit
dem neuen Registersatz des höheren Interrupts überschrieben. Deshalb sollte man ein Interrupt mit niedriger Priorität 
mit dem Befehl "RETFIE 0" beenden, falls ein Interrupt mit höherer Priorität zugelassen ist.
RETFIE 0 --> W, STATUS und BSR bleiben unverändert
RETFIE 1 --> W, STATUS und BSR werden zurück geladen

Vorgehen beim Programmieren eines Interrupts

Ich möchte in diesem Punkt kurz erläutern, wie Sie vorgehen können um einen Interrupt zu konfigurieren. Ich werde dies am Beispiel des Timer0 Interrupts erklären. Bei Interrupts gibt es einmal die Erkennungs-Flags und die Enablebits. Zusätzlich gibt es bei den PIC18F Typen noch Prioritätsbits. Wenn wir uns nun dafür entschieden haben, mit dem Timer0 einen Interrupt auszulösen, so müssen wir uns darüber Gedanken mache, was denn alles Notwendig ist, damit der INT auch ausgelöst werden kann. Da muss einem sofort das GIE Bit einfallen, denn dieses muss gesetzt sein, damit überhaupt INT erlaubt sind (dabei spielt es keine Rolle um welchen INT es sich handelt! Ist das GIE Bit auf disable, so kann kein INT ausgelöst werden!). Bei den PIC18F muss man sich hier mit zwei GIE Bits auseinander setzten: Das GIEL und das GIEH Bit (für verschiedene Prioritäten… unten mehr dazu). Also wir haben in unseren Beispiel einen PIC16F628 gewählt und wollen den Timer0 Überlauf zu einem INT führen lassen. Also haben wir das GIE Bit entsprechend eingestellt, damit dies funktionieren kann. Jetzt gehen wir weiter und kümmern uns darum, dass der Timer0 INT ebenfalls erlaubt ist. Dafür suchen wir das entsprechende Enable Bit, in unserem Fall das T0IE (für: Timer0 Interrupt Enable). Hierzu erst mal ein Programmcode:

;==============================================
;Konfiguration für den Timer0
;==============================================
 
   bsf INTCON,T0IE   ; Timer0 Interrupt erlaubt
   bsf INTCON,GIE    ; Interrupts generell erlaubt

Achtung: Dieser Programmcode setzt natürlich einen eingestellten Timer0 voraus!

Wenn Sie den Timer0 (s. Kapitel) richtig eingestellt und mit diesem Code den Interrupt soweit erlaubt haben, dann können Sie sich Gedanken machen, was der Interrupt eigentlich bewirken soll. Wir nehmen einfach an, dass in dem INT eine LED geschaltet werden soll. Damit würde dies wie folgt aussehen:

;==================================================
;Interruptroutine (ISR - Interrupt Service Routine)
;==================================================  
  ORG   0x04           ; Hier beginnt die ISR
 
  movwf w_temp         ; Die Register sichern
  swapf STATUS,w
  bcf   STSTUS,RP0
  movwf STATUS_temp
 
;Hier die LED schalten z.B. so:
  bsf   LED
 
  swapf status_temp,w  ; Register wieder herrstellen
  movwf STATUS
  swapf w_temp,f
  swapf w_temp,w
 
;Löschen des Flag, welches den Interrupt auslöste
 
  Retfie               ; Ende der ISR (GIE=1)

Der Interruptvektor eines PIC16F liegt bei 0x04 (PIC18F High INT = 0x0008 und Low INT = 0x0018). Wenn der PIC in die ISR kommt wird als erstes das GIE Bit gelöscht (automatisch), damit während des INT kein neuer INT ausgelöst werden kann. Außerdem muss das Bit, welches den INT ausgelöst hat gelöscht werden (T0IE), da sonst beim Verlassen der ISR, sofort wieder ein INT ausgelöst werden würde, denn durch den Befehl "RETFIE" zum Schluss der ISR, wird das GIE Bit automatisch wieder auf "1" gesetzt! In der ISR nicht vergessen die Register zu sichern (s. Code)!


PIC16F Besonderheit

Wenn Sie bei einem PIC16F einen Interrupt programmieren möchten müssen Sie neben den generellen Dingen noch eine Besonderheit beachten. Beim Eintritt in die ISR, müssen Sie das Arbeitsregister, das Statusregister und wenn vorhanden das PCLATCH Register aus folgendem Grunde sichern. Nehmen wir einmal an, dass Sie ein Hauptprogramm durchlaufen, indem in Abhängigkeit des Zero-Flags Operationen durchgeführt werden. Nun wird gerade vor dem Abfragen des Z-Flags ein INT aufgerufen und hat eine Abarbeitung, welcher den Zustand des Z-Flags durchaus verändern/verfälschen kann. Beim Wiedereintritt in das Hauptprogramm kann es nun durch die Veränderung des Z-Flags zu Fehlern kommen! Dem wird mit folgendem Code in der ISR vorgebeugt

;==================================================
;Interruptroutine (ISR - Interrupt Service Routine)
;==================================================  
  ORG   0x04           ; Hier beginnt die ISR
 
  movwf w_temp         ; Die Register sichern
  swapf STATUS,w
  bcf   STSTUS,RP0
  movwf STATUS_temp
 
;Hier den Code für die Interrupt service routine
 
  swapf status_temp,w  ; Register wieder herrstellen
  movwf STATUS
  swapf w_temp,f
  swapf w_temp,w
 
;Löschen des Flag, welches den Interrupt auslöste
 
  Retfie               ; Ende der ISR (GIE=1)

Beispiel für den PIC16F84 In der leeren Zeile können Sie Ihre Routine hinein schreiben. Hinweis: Das Retten der Register ist bei den PIC18F beim hohch priorisiertem Interrupt nicht notwendig!


PIC18F Besonderheit

Wie ich weiter oben schon erwähnt habe, gibt es bei den PIC18F Typen mehr als nur einen INT Vektor, dass bedeutet, dass der PIC nicht bei jedem INT an dieselbe Stelle springt. Man unterscheidet bei PIC18F Typen zwischen Low und High priorisierten Interrupts. Die Wertigkeit kann dabei vom Programmierer frei gewählt werden. Außerdem kann gewählt werden keine Unterscheidung der Priorität vor zunehmen, somit sind die Prioritätsbits wirkungslos!


Interrupt Checkliste

Folgendes müssen Sie beim Benutzen von Interrupts berücksichtigen:

  • Globale Interrupt Enable Bits (GIE,...) sind konfiguriert?
  • Zugehörige Interrupt Enable Bits (T0IF,...) sind konfiguriert?
  • PIC16F: Die ISR sieht Zustandssicherung vor (W-Reg,...)?
  • Wird das INT-Auslösende Bit in der ISR gelöscht?
  • Sind ggfs. Peripherie-INTs erlaubt (TMR1,...)


Das Konfigurationswort

Das "Konfigurationswort" eines PIC gibt spezielle Einstellungen an, welche für den PIC zum Arbeiten unabdingbar sind! Das entscheidende hierbei ist, dass der PIC dieses Wort (auch als Fuses bezeichnet) nicht selber verändern kann! Wenn die Fuses einmal beim Brennen gesetzt sind, bleiben sie so! Man legt durch die Fuses grundlegende Hardware Einstellungen fest, welche angegeben werden müssen. Man kann das Konfigurationswort entweder manuell in den Programmcode eingeben, oder aber setzt die gewünschten Option im Brennprogramm, was allerdings nicht jede Brennsoftware unterstützt. Die Brennsoftware zu den Brennern von Sprut "usburn" unterstützt diese Funktion, wenn Sie mit original Microchip Hardware arbeiten, dann brennen Sie sowieso mit MPLAB und haben diese Funktion ebenfalls inkludiert.


Erklärungen des Codes

Hier sind einmal die für den Einstieg in die PIC µC Welt wichtigsten Einstellungsmöglichkeiten in einer Tabelle aufgelistet:

Funktion Kurzbeschreibung
Taktgenerator Gibt an mit welcher Frequenzkategorie der PIC arbeitet
Power up Timer Kann einen verzögerten Start des PIC hervorrufen (sinnvoll)
Watchdog Timer Kann einen Reset auslösen, wenn der PIC abstürzt
Code protection Wer seinen Code vor Spionage schützen möchte
MCLR Hier kann die Reset Funktion deaktiviert werden (bringt einen I (Input) Pin mehr
LV Programming Kann eine Programmierung mit 5V ermöglichen (kostet einen IO-Pin)
Brown out Reset Kann einen Reset auslösen, wenn die Betriebsspannung einbricht

Taktgenerator Bei dieser Option müssen Sie den richtigen Taktbereich auswählen, damit der PIC weiß, mit welcher Frequenz gearbeitet wird. Sie finden die Entsprechende Einstellung im Datenblatt. Hier ein Überblick:

LP 32 kHz - 200 kHz Quarz, Keramikresonator, Extern
XT 100 kHz - 4 MHz Quarz, Keramikresonator, Extern
HS 4 MHz - 20 MHz Quarz, Keramikresonator, Extern
RC 30 kHz - 4 MHz Widerstand - Kondensator Kombi

Bitte lesen Sie im Datenblatt nach weiteren Taktmöglichkeiten (Intern,...)

Power up Timer

Durch das aktivieren dieser Funktion startet der µC mit 72ms Verspätung. Diese Option ist eigentlich immer Sinnvoll!

Watchdog Timer

Der Watchdog Timer ist ein weiterer Hardwaretimer, welcher den PIC resetet sobald der Timer überläuft. 
Ist diese Funktion aktiviert, muss der Timer in regelmäßigen Abständen gelöscht werden!

Code protection

Diese Funktion schützt Ihren Programmcode vor Diebstahl. Wenn Sie ein Programm geschrieben haben, 
welches Sie nicht veröffentlichen möchten, können Sie mit dieser Funktion Ihren Code schützen.

MCLR (Master clear reset)

Oftmals ist es ja überhaupt nicht notwendig, dass ein PIC per Tastendruck resetet werden kann. 
Daher kann der MCLR Pin (RA5) auch als Eingang (nur Eingang) benutzt werden.

LV Programming

Diese Funktion ist für Einsteiger weniger Interessant. Sie ermöglicht das Brennen mit 5 anstatt 12V 
Programmierspannung. Geht aber auf Kosten von einem IO Pin!

Brown out Reset

Der Brown out Reset schützt den PIC davor fehlerhaft zu arbeiten, wenn ein Spannungseinbruch passiert ist. 
Der Brown out Reset überprüft ständig die Betriebsspannung des PIC. Sobald diese für mindestens 0,1ms unter 4V fällt, 
wird ein Reset ausgelöst sobald die Spannung wieder im sicheren Bereich ist und 72ms vergangen sind. 
Bei PIC18F ist die Schwelle einstellbar!


Gut zu wissen

Hier entsteht eine kleine Sammlung mit Dingen die immer wieder falsch gemacht werden bzw. zu Problemen führen. Für Hinweise bin ich immer dankbar.

Was ist Fosc, Tosc, ..

Fosc ist die Taktfrequenz der Signalquelle, welchen wir an unseren PIC anschließen (zum Beispiel ein Quarz). Tosc ist dementsprechend die Periodendauer der Fosc. Man errechnet Tosc mit 1/Fosc. Da ein PIC zum Bearbeiten eines Befehls 4 Taktzyklen (ein Befehlstakt = Tosc) benötigt errechnet sich Tosc durch Fosc/4. Wieder kann man die Zeit berechnen die ein PIC mit entsprechender Taktquelle benötigt 1/Tosc.

Beispiel

An einem PIC ist ein 4 MHz Quarz angeschlossen somit beträgt Fosc = 4MHz. Der Befehlstakt ist dann Tosc = Fosc/4 = 4 MHz / 4 = 1 MHz und somit benötigt der PIC für das abarbeiten eines Befehls 1/1 MHz = 1*10^-6s = 1µs Zeit.

Offene Pins am Controller

Wenn es vorkommt, dass Ihr nicht alle Pins des Mikrocontrollers braucht, dann habt ihr zwei Möglichkeiten dies zu handeln: a) Ihr schaltet die Pins in der Software auf Ausgang oder b) Sie schalten die nicht verwendeten Pins auf VSS oder VDD, damit diese ein festes Potential annehmen. Somit schützt ihr euren PIC!

Nicht verwendete Eingänge am Mikcrocontroller niemals offen lassen! Hier ist ein festes Potential notwendig!

Achtung bei RA4

Immer wenn Ihr den PIN RA4 eines PIC als Ausgang benutzen wollt müssen bei Euch die Alarmglocken angehen (dies bezieht sich lediglich auf PIC16F), denn dieser Pin ist bei vielen PIC16F Typen nur ein "Open Drain" Pin und ist somit nicht in der Lage, ohne einen extra Pull up Widerstand, sein Potential allein auf 5V zu ziehen!


In circuit seriel programming

Wer kennt das nicht: Für die Entwicklung einer Software muss der PIC mehrmals geflasht und anschließend die Software in der Schaltung getestet werden. Es ist nervtötend andauernd den PIC immer wieder aus der Fassung der Schaltung zu entnehmen, dann in die Fassung des Brenners zu stecken und dann wieder anders herum. Es gibt hierfür eine Lösung und die nennt sich In Cuircuit Seriell Programming oder kurz ICSP. Das bedeutet der PIC wird in seiner fertigen Schaltung gebrannt ohne ihn entnehmen zu müssen. Damit die ICSP Funktion benutzt werden kann müssen ein paar Vorkerungen getroffen werden:

Es werden folgende Leitungen benötigt:

  • VPP, Leitung mit der Programmierspannung
  • VDD, Leitung mit der Versorgungsspannung für PIC
  • VSS, Leitung für Masse
  • PGD, die Datenleitung zum Programmieren
  • PGC, die Taktleitung zum Programmieren

Die Leitungen werden wie folgt angeschlossen:

ICSP Leitung Anschluss am PIC
Programmierspannung [Vpp] an den PIN MCLRE
Versorgungsspannung [Vdd] an den/die Pin(s) Vdd
Masseleitung [Vss] an den/die Pin(s) Vss
Taktleitung [PGC] an den Pin RB6
Datenleitung [PGD] an den Pin RB7

Beispiel zum Anschluss am Microchip ICD2 und PICkit3:


Wenn Sie einen Brenner von Sprut verwenden, dann können sie hier nachschauen wie sie die ICSP Funktion nutzen können: ICSP - Sprut

Der ICSP Stecker von Sprut ist genau Spiegel verkehrt zum Microchip Stecker!

Siehe auch

Autoren

Nico 16:46, 19. Aug. 2011 (CEST)

Meine Werkzeuge
Namensräume

Varianten
Aktionen
Navigation
Mikrocontroller
Elektrotechnik
Projekte
Displays
Bauteile
Werkzeuge