Der C18-Compiler


zurück zu C , PIC-Prozessoren , Elektronik , Homepage

Student-Edition
Installation / Allgemeines
Ein neues C18-Projekt mit MPLAB
Hello World
 

zurück zu C-Compiler


Student-Edition

Ich beziehe mich hier ausschließlich auf die Student-Edition von C18. Sie unterscheidet sich von der kommerziellen Version dadurch, dass (nach einer mehrwöchigen Testphase) zwei Features abgeschaltet sind: Der mit der Student-Edition erstellte Code ist also langsamer und größer als der Code der kommerziellen Version. Ansonsten ist die Student-Edition aber voll funktionsfähig.
 
nach oben

Installation / Allgemeines

Um den C18 nutzen zu können, lädt man ihn erst einmal von der Microchip-Homepage. Außerdem benötigt man MPLAB.
Ich empfehle wenigstens MPLAB V 7.3 und C18 V 3.0 einzusetzen.


Zuerst wird MPLAB installiert, und anschließend C18. Danach befindet sich C18 im MPLAB-Unterordner MCC18. Folgende Unterordner  werden angelegt:

Je nach installierter C18-Version können auch noch folgende Files auftauchen: Assembler
Auf den ersten Blick mag es etwas verwundern, dass der C18 einen Assembler mitbringt, aber der wird wirklich benötigt. Der C18 übersetzt nämlich den C-Quelltext zunächst nur in ein Assembler-File, das dann der MPASM-Assembler in ein Object-File und letztendlich der Linker in ein HEX-File wandelt.
Für den Assembler wird dabei automatisch das zum PIC-Typ passende Assembler-Standard-Header-File (z.B. P18F8720.INC) eingebunden. Dadurch können im C-Quelltext alle Bezeichner verwendet werden, die in diesem *.INC-File definiert werden. Das betrifft Bezeichner wie  z.B. PORTA, TRISA oder T0IE, die einem aus der Assemblerprogrammierung bereits geläufig sind.

Header-Files
Allerdings muss auch der C-Compiler wissen, was für ein Datentyp sich hinter diesen Bezeichnern verbirgt. Es ist schließlich ein Unterschied, ob es ein einzelnes Bit, ein Byte oder ein 16-Bit-Wort ist. Deshalb ist der Datentyp für alle diese Bezeichner speziell für den C-Compiler in einem C-Compiler-Header-File noch einmal festgelegt. All diese Files (für jeden PIC-Typ natürlich ein eigenes File) liegen im Ordner ...\MCC18\h\ (z.B. p18f8720.h).

Linker-Skripts
Linker-Skripts beschreiben den Speicheraufbau eines PICs. Sie werden vom Linker benötigt, um aus den Object-Files das HEX-File zu erstellen.

Bibliotheken
C18 bringt eine Reihe hilfreicher Bibliotheken mit. Die dienen dem einfacheren Umgang mit spezieller PIC-Hardware (ADC, PWM, I2C ...), mathematischen Berechnungen oder String-Manipulationen. Eine Beschreibung aller Bibliotheksfunktionen findet sich im Dokument MPLAB-C18-Libraries_51297f.pdf im Ordner  ...\MCC18\doc\ .

nach oben

Ein neues C18-Projekt mit MPLAB

  1. Starten von MPLAB
  2. Nach dem Start von MPLAB, hat man ein recht leeres Programmfenster vor sich. Es ist noch kein Projekt geöffnet

  3. Project - Project Wizard...  Continue
  4. Um ein neues Projekt anzulegen, startet man den Project-Wizard. Mit dem lässt sich ein Projekt interaktiv erstellen. Auf dem Startbildschirm des Wizard klickt man erst einmal weiter.

  5. Step One: Den gewünschten PIC-Typ auswählen
  6. Dann landet man bei der ersten Frage des Wizard. Man muss hier den PIC-Typ auswählen, für den das Programm geschrieben werden soll.

  7. Step Two: active Toolsuite -> Microchip C18 Toolsuite
  8. Nun gilt es, den Compiler oder Assembler für sein Projekt auszuwählen. Im obersten rechten Auswahlmenü entscheidet man sich für Microchip-C18-Toolsuite

  9. Step Three: Name und Directory festlegen
  10. nun braucht das Projekt noch einen griffigen Namen, und man legt das Verzeichnis des Projektes fest. Danach hat man ein (allerdings noch leeres) Projekt.

  11. Dateien in das Projekt aufnehmen
Jedes C-Projekt hat ein Quelltext-File mit dem Namen main.c.  Das sollte man nun mit MPLAB erstellen (File - New) und im Projektordner unter dem Namen main.c speichern. Nun kann man es als Source-File in das Projekt aufnehmen (rechter Mausklick auf Source Files). In dieses File schreibt man sein C-Programm.

Außerdem ist ein zum PIC passendes Linker Skript nötig (rechter Mausklick auf Linker Scripts). Im Verzeichnis .../mcc18/lkr/ sucht  man das richtige aus.
 

nach oben

Hello World

Ein kleines Beispiel verdeutlicht das Schreiben eines Programms  mit C18. Es ist mit diesem  Lern-Beispiel weitgehend identisch.

Folgendes kleine Progrämmchen lässt eine LED am Pin RB0 blinken. Echter Code ist grün. Alle Kommentare habe ich grau eingefärbt.
 
/** I N C L U D E S **********************************************************/
#include <p18cxxx.h>
#include "delays.h"                        // für die Warteschleife
 

/** Configuration ********************************************************/
#pragma config OSC = HS   //CPU=20 MHz
#pragma config PWRT = ON
#pragma config BOR = OFF
#pragma config WDT = OFF  //Watchdog Timer
#pragma config LVP = OFF  //Low Voltage ICSP
 

/** D E C L A R A T I O N S **************************************************/
#pragma code
void main(void)
{
  LATB = 0x00; 
  TRISB = 0xFE;

  while(1)
  {
    LATB = 1;
    Delay10KTCYx(100);
    LATB = 0;
    Delay10KTCYx(100);
  }//end while
}//end main
 

Nehmen wir das Programm einmal auseinander. Als erstes stehen dort zwei #include-Direktiven:
 
...
/** I N C L U D E S **********************************************************/
#include <p18cxxx.h>
#include "delays.h"                        // für die Warteschleife
...

Die erste ist nötig, damit wir die aus dem Assembler üblichen Bezeichner (PORTA, TRISA...) verwenden können. Eigentlich müsste ich dazu das zum jeweiligen PIC-Typ gehörende C-Header-File einbinden. Für den PIC18F8720 wäre das z.B. p18f8720.h. Die Datei p18cxxx.h erledigt das automatisch. Sie prüft, welcher Prozessortyp im Projekt ausgewählt wurde, und bindet dann selbständig das dazu passende C-Header-File ein. Ich hätte aber auch schreiben können:
#include <p18f8720.h>
Ob man spitze Klammern oder Anführungszeichen benutzt ist hier übrigens egal. Spitze Klammer bezeichnen eine Standard-Include-Datei (z.B. Bibliothek des Compilers). Sie wird in allen Include-Verzeichnissen gesucht. Anführungszeichen dagegen sind für Include-Dateien gedacht, die man selbst geschrieben hat. Sie wird zunächst im aktuellen Verzeichnis des Projektes gesucht. Erst wenn Sie dort nicht gefunden wird, sucht der Compiler in den Include-Verzeichnissen weiter.

Mit der zweiten #include-Direktive binde ich eine Bibliothek (delays.h) ein, aus der ich später eine Funktion verwenden möchte.
 

Es folgt die Einstellung der Configuration des PIC.
Die #pragma-Direktive sagt dem Compiler, wohin im PIC das Folgende geschrieben werden soll. In diesem Fall handelt es sich also um Configurations-Einstellungen. Microchip hat die Vorgehensweise beim Einfügen von Configurationsdaten in den Quelltext überarbeitet.  Das alte Verfahren sollte für die PIC18-Typen nicht mehr benutzt werden. Dafür gibt es jetzt für jeden PIC eine Reihe von Configurationseinstellungen, die im Dokument PIC18-Config-Settings-Addendum_51537d.pdf aufgelistet sind. Dieses Dokument wird bei der Installation von C18 in das doc-Unterverzeichnis geschrieben.

Da mein PIC mit 20 MHz laufen soll, stelle ich den Oszillator auf HS.
Den Power-up-Timer schalte ich ein. Das ist nicht gerade wichtig, schadet aber auch nicht.
Brown-out-Reset (Unterspannungs-Reset) schalte ich ab. Ich brauche es nicht.
Nun kommt das Wichtigste: Der Watchdog-Timer muss abgeschaltet werden, sonst läuft das Programm nicht.
Zum Schluss schalte ich noch low-voltage-programming ab, um Probleme beim nächsten Brennen zu vermeiden.

All diese Einstellungen könnte man auch später im Brennprogramm P18  oder US-Burn vornehmen, so ist es aber bequemer.
 
...
/** Configuration ********************************************************/
#pragma config OSC = HS    //CPU=20 MHz
#pragma config PWRT = ON
#pragma config BOR = OFF
#pragma config WDT = OFF  //Watchdog Timer
#pragma config LVP = OFF  //Low Voltage ICSP
...

Nun kommt das eigentliche Programm.
Da das in den Programmspeicher geschrieben werden soll, muss zuerst die #pragma code - Direktive stehen.
Wie in C üblich, heißt das Hauptprogramm main und ist eine Funktion. An eine Funktion kann man Parameter übergeben, und man kann ein Ergebnis zurück bekommen. Beides wird im Funktionskopf festgelegt
Ergebnis Funktionsname(Parameter)

Unsere Funktion main verzichtet auf beides. Deshalb schreibt man jeweils void (leer). Die eigentlichen Befehle der Funktion werden dann in geschweiften Klammern eingeschlossen. Den Inhalt der Funktion habe ich im nachfolgenden Code-Abschnitt der Übersichtlichkeit halber entfernt.
 
...
/** D E C L A R A T I O N S **************************************************/
#pragma code
void main(void)
{
.
.
.
.
}//end main

 Betrachten wir nun den Inhalt der Funktion main. Zuerst stehen dort zwei Befehle, die beim Start der Funktion (also beim Start des PIC) genau einmal durchlaufen werden. Sie dienen der Initialisierung des Ports B.

Mit dem Befehl LATB = 0x00 schreibt man 0 in das PortB. (Man hätte genauso gut PORTB = 0x00 schreiben können. )
Anschließend mache ich RB0 zu einem output-Pin, indem ich das Bit 0 des Registers TRISB  auf 0 setze.
 
...
  LATB = 0x00; 
  TRISB = 0xFE;
...

Nun kommt die Blink-Schleife (while), die endlos durchlaufen wird.
In der Schleife passiert immer wieder folgendes:

LATB und PORTB sind beim Schreiben gleichwertig.

Die Routine Delay10KTCYx() stammt aus der delay-Library. Da wir am Programmanfang die Header-Datei dieser Library eingebunden haben, kennt der Compiler diese Routine, und ihren Übergabeparameter. Die delay-Library ist eine fertig compilierte Lib-Datei im lib-Unterordner.
Die Funktion Delay10KTCYx() ist eine Warteschleife, ihre Laufzeit ist 10000 Zyklen x übergebenem Wert. Da wir 100 als Wert übergeben, ergibt sich eine Laufzeit von 100x10000=1000000 Zyklen. 1 Million Zyklen sind 4 Millionen Takte. Bei 20 MHz Takt ergibt sich 1/5 Sekunde Wartezeit.
 
...
 while(1)
  {
    LATB = 1;
    Delay10KTCYx(100);
    LATB = 0;
    Delay10KTCYx(100);
  }//end while
...

Das war's auch schon. Die LED blinkt.

nach oben

zurück zu C , PIC-Prozessoren , Elektronik , Homepage



Autor: sprut
erstellt: 23.03.2006
letzte Änderung: 24.03.2006