PIC C Tutorial – Speziell für PIC

Selbstverständlich müssen in C genauso wie in Assembler (ASM) die Konfiguration für den PIC bestimmt bzw. eingestellt werden. Wenn dies vergessen wird, kann der Mikrocontroller / PIC nicht arbeiten. In diesem (letzten) Kapitel konzentrieren wir uns auf Aspekte der Sprache C die in direkte Beziehung zu unseren PIC Mikrocontrollern stehen.

Konfiguration

Nun unterscheidet sich die Einstellung der einzelnen Einheiten etwas. Hier ein beispiel wie Ihr in C, die Konfiguration für einen PIC vornehmen könnt:

#pragma config FOSC=HS   // Taktbereich
#pragma config PWRT=ON   // Power on timer
#pragma config BOR=OFF   // Brown out reset
#pragma config WDT=OFF   // Watchdog timer
#pragma config LVP=OFF   // Low voltage progr.
#pragma config MCLRE=ON  // Master clear reset

Durch die Einleitung #pragma weiß der Compiler, dass es sich um Konfigurationsinformationen für den Prozessor handelt. Natürlich könnt ihr das Konfigurationswort bzw. die Konfigurationsbits auch komfortabel über die IDE einstellen. Auf diese Weise müsst ihr euch mit der genauen Schreibweise nicht auseinandersetzen. So werden die Konfigurationsbits mit MPLABX erstellt (siehe auch  separaten Artikel zur MPLABX IDE):

Eingänge / Ausgänge

Als nächstes ein Beispiel, wie ihr in der Sprache C Zustände von einzelnen GPIOs oder ganzen Ports einlesen und wie ihr Pins/Ports (Ausgang/Ausgänge) setzten oder löschen können:

// GPIO RA4 auf low setzen
LATAbits.LATA4 = 0;

// GPIO RA4 auf high setzen
LATBbits.LATB0 = 1;

// RB7 auf Eingang und den Rest auf Ausgang setzen
TRISB = 0x80;

// RB0 auf Eingang setzen
TRISBbits.RB0 = 1;

// Abfrage des vollständigen Port B
if (PORTB == 0xFF)
{
    //...
}

// Abfrage eines einzelnen GPIOs auf low
if (PORTBbits.RB0 == 0);
{
    //...
}
Merke  Folgende Schreibregeln sind beim Umgang mit Ein-/ und Ausgängen einzuhalten:

LAT<x>bits.L<x><y> = <z>;

x: Hier wird der Port eingetragen (A, B ..).
y: Hier kommt das Bit hinein (07) des Ports.
z: Der Zustand den der Port-Pin annehmen soll.

if (PORT<x>bits.R<x><y> == 0) {...} else {...}

x: Hier wird der Port eingetragen (A, B ..).
y: Pin eintragen der gelesen werden soll (07)

Dabei darf man natürlich nicht vergessen die TRIS Bits dementsprechend einzustellen. Wir erinnern uns, dass eine 1 im TRIS Register den jeweiligen GPIO auf Eingang und eine 0 als Ausgang schaltet. Im obigen Beispiel seht ihr ebenfalls wie ihr die TRIS Register beschreiben könnt.Dies ist ein Beispiel, wie man in Abhängigkeit vom Zustand eines Einganges den Programmablauf steuern kann!

Wann PORT und wann LAT?

Ein weiterer wichtiger Punkt ist zu wissen, wann man mit PORT und wann mit LAT arbeiten muss. Ganz kurz und knapp: LAT bei Ausgängen und PORT bei Eingängen. Wer sich noch etwas mehr mit den Vorteilen der LAT Register beschäften möchte kann mal hier  rein schauen.

Interrupts

PIC-Mikrocontroller unterscheiden zwei Interrupt Prioritäten: High und low. Wenn ihr einen Interrupt programmiert habt und ein entsprechendes Event diesen auslöst, so wird der PIC in die so genannte Interrupt-Service-Routine (ISR) springen. Im Grunde genommen ist die ISR eine spezielle Art Funktion. Diese wird enteggen normaler Funktionen jedoch nicht vom Programmierer selbstständig aufgerufen, sondern vom PIC selber, wenn ein entsprechendes Ereignis eintritt.

void __interrupt() highPrio (void)
{
    // ...
}

void __interrupt(low_priority) lowPrio (void)
{
    // ...
}

Häufige Fehler

Hier entsteht eine Sammlung von Fragen mit Antworten, welche sehr häufig gestellt werden. Außerdem wird eine Liste mit Fehlern erstellt, welche immer wieder vorkommen.

GLEICH = ist nicht gleich GLEICH ==

Ein Fehler der immer wieder gern gemacht wird ist, dass man bei einem Vergleich das falsche Zeichen wählt. Ein einfaches geschriebenes = Zeichen ist dafür da um z.B. Variablen einen Wert zu zuweisen aber nicht als Vergleichsoperator (==), dies würde einen Syntax Fehler nach sich ziehen und das Compilieren beenden. Siehe:

Falsch:

if (A=B) {..} else {..}

Richtig:

if (A==B) {..} else {..}

Funktionen anmelden (Prototypen)

Eine Funktion muss bekannt sein bevor sie aufgerufen werden kann. Wir haben diese Notwendigkeit bereits zuvor im Kaptiel der Funktionen und Prototypen behandelt.

Falsch (Funktionsaufruf vor dem Funktionskopf):

void main (void)
{
    function_a();
}

void function_a (void) {..}

Richtig (Funktionsaufruf nach dem Funktionskopf):

void function_a(void) {..}

void main (void)
{
  function_a();
}

Oder aber man meldet Sie vorher an (Funktionsaufruf vor dem Funktionskopf aber nach dem Prototypen):

void function_a (void);

void main (void)
{
  function_a();
}

void function_a (void) {..}

Schlusswort

Ich hoffe dieser kleine C Kurs hat euch etwas geholfen mit PIC-Mikrocontrollern und der Verwendung der Sprache C umzugehen. Sollten ihr dennoch Fragen haben zögert nicht diese über die Kommentarfunktion zu stellen. Jedenfalls wünsche ich euch nun viel Spaß beim Programmieren. Wenn ihr Fragen oder Probleme habt, kommt gerne im Forum vorbei 😉

Leave a Comment