Programmierkurs für PIC-Mikrocontroller in C (CC5X Compiler)
mit Beispielen und Schaltplänen. In diesem Kurs sind auch einige Unterprogramme detailliert erklärt.

Compiler installieren, das erste Programm, Timer1, Pipston erzeugen, Zählerprogramm, Verkürzungen bei C Teil1
Bit-Operationen, Schiebeoperationen, Bits Maskieren, Lauflicht, Interrupt Teil2
Fehlersuche, Hilfen bei der Fehlersuche, Strategien bei Fehlersuche, Serielle Kommunikation mit dem PC. Teil3
Präprozessorbefehle des CC5X Compilers Teil4
Ansteuerung des LCD-Displays (LCD-MODUL 16X2) mit PIC16F84 und PIC16F871 LCD
Ein bequemes Programm zum Kommunizieren über serielle Schnittstelle (für PC) COM Terminal
C - Texte bequem bearbeiten, in Farbe anzeigen, Bootloader Quelltexteditor
Eine Excel-Tabelle mit einem Skript der die Daten automatisch in Warenkorb von Reichelt überträgt Reichelt-
Bestellprogramm

Webkatalog für elektronische Schaltungen für Hobby-Elektroniker

Webkatalog
für Hobby-Elektroniker
1K -Grenze bei CC5X 1K Beschränkung ohne Crack bei CC5X umgehen
I2C-Bus I2C-Bus, Seriellen EEPROM (24LC32), 8-Bit Port (PCF8574), Temperatursensor (TCN75)
Flüssigkristallanzeige
DSM-0822A
von Pollin
8 Stellen alphanumerisch
kostet 1,95 EUR bei Pollin !!!
( I2C-Controller PCF8576)
64MB MMC und
PIC-Microcontroller
MMC -Speicherkarte mit PIC16F877 Schreiben /Lesen , Theorie über SPI Schnittstelle, Theorie über MMC, Signaldiagramme, Zugriff auf FAT16-Dateisystem
ADC AD-Wandler, Visualisierungsprogramm in VB
EEPROM, FLASH EEPROM und FLASH- Programmspeicher beschreiben und auslesen bei PIC16F87x
USB mit PIC18F2550 USB -Schnittstelle ganz einfach nutzen dank den Mischaka-Bootloader
Funksteckdosen per PC 433 MHz Funksteckdosen über PC Schalten
Verschiedenes Schaltung für Laderhaltung, Drehimpulsgeber mit dem PIC , Ideen
Links Links zum anderen Mikrocontrollerseiten

 

Was ist ein Mikrocontroller?

Ein Mikrocontroller ist: Ein Mikrocontroller hat: Ein Mikrocontroller kann: Ein Mikrocontroller braucht:
-Ein IC, kleinstes mit 8 Beinchen, größtes mit über 40 Beinchen;
-Ein vereinfachter Computer oder
-Mini-SPS.
-CPU,
-Programmspeicher FLASH,
-Datenspeicher RAM,
-Steuerregister,
-Input-/Output-Ports,
Optional :
-Timer,
-AD- Wandler,
-EEPROM für Daten.
___________________________

-Logische Pegel ( 0Voder 5V) an Pins ausgeben und einlesen;
-Fast jede digitale Schaltung ersetzen;
-Beliebige Logik realisieren;
-Zählen ;
-Rechnen (addieren, subtrahieren, multiplizieren, dividieren);
-Impulse mit bestimmter Dauer erzeugen, von 1ms bis unendlich;
-Zeit messen, von 1ms bis unendlich;
-Datenübertragung nach einem Protokoll erzeugen, zum Beispiel: seriell, parallel, I2C, RC5;
-Werte in ausgeschaltetem Zustand beibehalten;einige können Spannungen messen;
-Spannungsversorgung;
-Einen Taktgeber - Quarz (0...20MHz);
-Und ein sinnvolles Programm im Programmspeicher .

Vorteile des CC5X Compilers.

Dieser Compiler erzeugt einen kompakten Code, ist sparsam im RAM-Verbrauch und ist einfach zu installieren. Zudem unterstützt er viele PIC-Typen. Die erzeugte Assemblerdatei kann mit dem C-Text als Kommentar ausgegeben werden.

Besonders für Hobby-Programmierer ist der CC5X-Compiler interessant, denn die Freie Version unterstützt alle PIC16, PIC12 - Typen und übersetzt bis zu 1024 Instruktionen.
Wenn Ihr Programm so groß wird, dass es 1024 Instruktionen überschreitet, gibt es einen kleinen Trick, um dieses Programm trotzdem zu kompilieren: Das Programm so umschreiben, dass man es in 2 Teilen speichern kann, dann die Assemblerdateien zusammenfügen und in MPLAB kompilieren. Allerdings sind 1024 Instruktionen eine ganze Menge, so haben einige PICs nur 1k Speicher (16F84, 12F675).
Der Nachteil ist, dass die freie Version Variablen nur bis 16 Bit unterstützt, aber die 16 Bit-Variablen (0...65535) sind auch für Hobby-Programmierer ausreichend, man will ja mit dem PIC steuern und regeln und keine Mathe-Aufgaben rechnen.

Der Übergang von Assembler zum CC5X Compiler ist sehr einfach. Man kann sich prüfen, in dem man die Assemblerdatei anschaut. Die Assemblerdatei lässt sich auch in MPLAB simulieren, was die Fehlersuche vereinfacht. Beim CC5X-Compiler kann im C-Programm Assemblercode eingefügt werden. Dies ist besonders wichtig beim Bau von Zeitschleifen oder wenn schnelles Schalten der Ausgänge erforderlich ist.

Der CC5X-Compiler hat keine integrierten Hardwaretreiber. Zum Benutzen der seriellen Schnittstelle oder der AD-Wandler oder des I2C-Busses muss man eigene Unterprogramme schreiben. Wobei ich das als Vorteil sehe, denn dann kann man genau die Ausführungszeit bestimmen, hat größere Einstellungsmöglichkeiten, und die Fehlersuche ist einfacher, weil man weiß, was da in den Treibern passiert.

Compiler installieren, das erste Programm

Als erstes wird beschrieben, wie ein einfaches Programm für PIC16F84 gemacht wird.
Dazu braucht man Compiler CC5X (freie Version / ist nicht eingeschränkt) erhältlich bei http://www.bknd.com/cc5x/index.shtml.
Nachdem Sie die Datei cc5xfree.zip herunter geladen haben, entpacken Sie alles in einen Ordner. In den folgenden Tips heisst dieser Ordner "cc5".
Das erste Programm nennen wir "Versuch1".
Erzeugen Sie einen Ordner mit dem Namen "Versuch1".
In dieser Mappe erzeugen Sie eine txt-Datei zum Beispiel mit Name "Versuch1.c"
Erzeugen sie eine bat-Datei mit Name "Versuch1.bat" mit folgendem Text :
C:\cc5\cc5x Versuch1.c -IC:\cc5\cc5x -aVersuch1.ASM -u
(Pfad zu cc5x.exe muss angegeben und ggf. angepasst werden)
Die Datei "Versuch1.c" kann man mit einem beliebigen Texteditor bearbeiten.
Nachdem ein Programmtext eingegeben wurde und in "Versuch1.c" gespeichert wurde, wird "Versuch1.bat" gestartet. Wenn alles richtig war, dann wird in DOS-Fenster unter anderem
File 'Versuch1.ASM'
File 'Versuch1.HEX'
stehen.
Diese Dateien sind dann ebenfalls im Ordner "Versuch1" zu finden.
Die erzeugte Hex-Datei kann dann direkt in das IC programmiert werden.
Diejenigen, die bereits in Assembler für PIC's programmiert haben, können sich die Datei "Versuch1.ASM" ansehen oder mit MPLAB öffnen und simulieren (sehr gute Hilfe bei Fehlersuche ).

Jetzt zum Inhalt von "Versuch1.c".

// Ab dieser Zeile kopieren , erste Versuch mit CC5X zu programmieren.
//-Kommentar fängt hier an , und endet an Zeilenende

#include <C:\cc5\16F84.h>		// Prozessor-Typ definieren
void main(void)				// Start des Hauptprogramms
{
TRISB = 0b.0000.0000;		// Alle Pins  des Ports B sind als Ausgänge geschaltet
PORTB = 0b.1010.1010;		//Pins 6,8,10,12- 0V   Pins 7,9,11,13 - 5V
}						// Ende des Hauptprogramms

Wenn alles richtig gemacht wurde, dann sollten an dem Port des Mikrocontrollers unterschiedliche Spannungspegeln sein.
PORTB , TRISA - das sind Registernamen, die man aus der Beschreibung für den jeweiligen Controller entnehmen kann. Auch in der Datei "16F84.h" sind die Prozessortyp-spezifischen Registernamen und Registeradressen zu finden.

Das Programm innerhalb der "main()"-Funktion wird nach dem Einschalten ausgeführt.

Wenn jemand trotzdem einige Teile des Programms in Assembler schreiben möchte oder seine alte Unterprogramme zusammen mit C benutzen will, gibt es die Möglichkeit, Assemblercode in C einzubringen.


#include <C:\cc5\16F84.h>			// Prozessor-Typ definieren

void main(void)						// Start des Hauptprogramms
{
	#asm
	MOVLW	b'00000000'
	BSF	STATUS,RP0		// Register  in Bank 1
	MOVWF	TRISB			// Alle Pins  des Ports B sind als Ausgänge geschaltet

	MOVLW	b'10101010'
	BCF	STATUS,RP0		// Register in Bank 0
	MOVWF	PORTB			// Pins 6,8,10,12- 0V   Pins 7,9,11,13 - 5V
	#endasm					// Ende des Hauptprogramms
}

Diese Option ist auch nützlich bei zeitkritischen Programmteilen.

Um weiter zu experimentieren, brauchen wir eine Test-Platine mit angeschlossenen Leuchtdioden an Port B (natürlich mit Vorwiderstand) und Schalter oder Taster an Port A .

Im nächsten Beispiel definieren wir Variablen und führen eine Addition durch.


#include <C:\cc5\16F84.h>			// Prozessor-Typ definieren

void main(void)					// Start des Hauptprogramms
{

char a;					// Variable a irgend ein freie Byte in RAM
char b;					// Variable b irgend ein freie Byte in RAM
char c @ 0xD;				// Variable c ist  Byte 14(D hex) in RAM

TRISB = 0b.0000.0000;			// Alle Pins des Ports B sind Ausgänge 
a=7;					// "a" wird Wert 7 zugewiesen
b=5;					// "b" wird Wert 5 zugewiesen
Sprungmarke:

c=a*b;					// Multiplikation mit 5, Ergebnis ins "c"
PORTB=c;				// Ergebnis in PortB übertragen

goto Sprungmarke;			// Endlosschleife
}					// Ende des Hauptprogramms

Beim Brennen des PIC's muss man jedes Mal die Konfiguration einstellen :
Taktgeneratoreinstellung , Watchdog, Power up Timer, Codeprotektion u.s.w.
Dies kann man schon in C machen, mit Hilfe dieses Befehls
#pragma config |= 0b.1111.1111.0010

Bit 1,0 : 11-RC, 10-HS, 01-XT, 00-LP
Bit 2 : 1 - Watchdog Ein, 0 - Watchdog Aus
Bit 3 : 0- Power up Timer Ein, 1- Power up Timer Aus
Bit's 13...4 : 0-Leseschutz Ein, 1-Leseschutz Aus

Das folgende Beispiel hat ein Unterprogramm und benutzt den Timer0 des PIC's.
Es wird eine Piepston erzeugt an RP0 Pin 6


// Taktfrequenz 4MHz

#include <C:\cc5\16F84.h>			// Prozessor-Typ definieren
#pragma config |= 0b.1111.1111.0010		// Konfigurationswort

void pause(void)				// Unterprogramm zum Abwarten einer Millisekunde
{
OPTION = 2;				// Vorteiler auf 8 einstellen
TMR0 = 131;				// 125 * 8 = 1000 (= 1 ms)
while (TMR0);				// Schleife, solange bis TMR0=0 wird
}

void main (void)				// Start des Hauptprogramms
{
TRISB = 0b.1111.1110;			// Pin 6 -Ausgang (Bit 0)
bit beep @ PORTB.0 ;			// Pin 6 erhält Name "beep"
char i;					// 8-Bit Variable (0...255)
Sprungmarke:
//******* Erzeugung des Piepstones mit 500Hz, Dauer 0,5sek ********************

i=250;					// Variable "i" wird mit Zahl 250 geladen
while (i)				// Schleife läuft solange, wie "i" nicht 0 ist.
	{				// Das heißt, Schleife wiederholt sich 250-mal
	beep=1;				// Pin 6 = 5V , Hier wird ein Rechteckimpuls erzeugt
	pause();			// 1ms warten
	beep=0;				// Pin 6 = 0V
	pause();			// 1ms warten, Periodendauer T=2ms, f=1/2ms=500Hz
	i--;				// von "i" wird 1 abgezogen und das Ergebnis wieder in "i" gespeichert
	} 				// Diese Schleife dauert 2ms*250 = 500ms = 0,5sekunde

//******* Erzeugung einer Pause zwischen Pipstonen mit Dauer 1sek ********************

i=250;					// Variable "i" wird mit Zahl 250 geladen
while (i)				// Schleife läuft so lange "i" nicht 0 ist
	{				// Das heißt, Schleife wiederholt sich 250-mal
	pause();
	pause();			// Pause von 4ms
	pause();
	pause();
	i--;				// "i" runterzählen
}					// Diese Schleife dauert 4ms*250=1000ms=1sekunde

goto Sprungmarke;			// Alles wiederholen
}						// Ende des Hauptprogramms

Funktionsweise des Unterprogramms "pause"
Im OPTION - Register wird der Vorteiler auf Faktor 8 eingestellt. Der Vorteiler erhält bei Verwendung eines Quarzes mit 4 MHz jede Mikrosekunde einen Impuls (Taktfrequenz/4). Das Zähler-Register TMR0 wird dann alle 8 ms erhöht. Wenn ein 8-Bit-Register überläuft (das passiert, wenn auf den Zustand 255 der nächste Impuls folgt), dann wird es 0 . In unserem Fall wird er mit 131 geladen und zählt bis 256: 256-131=125 . Also wird TMR0 alle 8 ms 125-mal erhöht. Danach wird die Schleife verlassen und das Hauptprogramm wird fortgesetzt.

Wichtig ist, dass das Unterprogramm im Quelltext steht, bevor es aufgerufen wird. Wenn Unterprogramm "pause" nach dem Hauptprogramm steht, dann meldet der Compiler einen Fehler. Eine zweite Möglichkeit ist, Unterprogramme und Funktionen zu definieren.


#include <C:\cc5\16F84.h>			// Prozessor-Typ definieren
#pragma config |= 0b.1111.1111.0010    		// Konfigurationswort

void pause(void);                      // Unterprogramm Definieren (Bekanntmachen für andere Unterprogramme)

void main(void)					// Start des Hauptprogramms
{
pause();				// 1ms warten
}						// Ende des Hauptprogramms

void pause(void)				// Unterprogramm zum Abwarten 1 ms
{
OPTION = 2;				// Vorteiler auf 8 einstellen
TMR0 = 131;				// 125 * 8 = 1000 (= 1 ms)
while (TMR0);				// Schleife, bis TMR0=0 wird
}						// Ende des Unterprogramms

Jetzt machen wir einen Zähler. Mit einer Taste wird der Zählerstand erhöht und mit einer anderen erniedrigt. An RB0...RB7 angeschlossene LED's zeigen den Zählerstand in binärer Form. Plus-Taste ist RA0 ; Minus-Taste ist RA1 . Die nötige Tastenentprellung nehmen wir im Programm vor.


// Taktfrequenz 4MHz

#include <C:\cc5\16F84.h>              // Prozessor-Typ definieren
#pragma config |= 0b.1111.1111.0010		// Konfigurationswort

void pause(void)			// Unterprogramm zum Abwarten 1 ms
{
OPTION = 2;				// Vorteiler auf 8 einstellen
TMR0 = 131;				// 125 * 8 = 1000 (= 1 ms)
while (TMR0);				// Schleife, bis TMR0=0 wird
}					// Ende des Unterprogramms

void main(void)					// Start des Hauptprogramms
{
TRISB = 0b.0000.0000;			// Pins RB0...RB7 -Ausgänge
bit Plus @ PORTA.0 ;			// Pin RA0 erhält Name "Plus"
bit Minus @ PORTA.1 ;			// Pin RA1 erhält Name "Minus"
char Zaeler, i;				// 8-Bit Variable (0...255)
Zaeler=0;				// Zählerstand auf 0 setzen

Sprungmarke:

if (Plus)				// Wenn "Plus"-Taster gedrückt ist (RA0)=1, dann
	{
	Zaeler++ ;			//  Zählerstand erhöhen
	PORTB=Zaeler;			// Zählerstand mit LED's anzeigen

	for (i=0;i<100;i++)		// (Variable i von 0 bis 100 mit jedem Durchlauf um 1 erhöhen)
		{			// Schleife 100 mal ausführen
		pause();		// warte 1ms*100 = 0,1s
		}			// Hier wird 0,1 s zum Entprellen gewartet

	while(Plus);			// Programm bleibt an dieser Stelle in Schleife 
					// stecken, solange "Plus" gedrückt (RA0=1) bleibt
	}

//                     Das gleiche für Minus-Taste

if (Minus)				// Wenn "Minus"-Taster gedrückt ist, dann
	{
	Zaeler-- ;			// Zählerstand verringern
	PORTB=Zaeler;			// Zählerstand mit LED's anzeigen

	for (i=0;i<100;i++)		// (Variable "i" von 0 bis 100; mit jedem Durchlauf um 1 erhöhen)
		{			// Schleife 100 mal ausführen
		pause();		// warte 1ms*100= 0,1s
		}			// Hier wird 0,1 s zum Entprellen gewartet

	while(Minus);			// Programm bleibt an dieser Stelle in Schleife 
					// stecken, solange "Minus" gedrückt (RA1=1) bleibt
	}
goto Sprungmarke;			// Alles wiederholen
}						// Ende des Hauptprogramms

Zuerst wird abgefragt, ob die Plus-Taste gedrückt ist. Danach wird abgefragt, ob die Minus-Taste gedrückt ist.
Diese Abfrage wiederholt sich in einer Endlosschleife.

Wenn die Plus-Taste gedrückt wird, dann wird hochgezählt und das Ergebnis an den LED's angezeigt. Danach wird 0,1s zum "Entprellen" gewartet, und dann wird gewartet, bis die Plus-Taste losgelassen wird.
Zum "Entprellen" sei folgendes gesagt : Beim Schliessen der Kontakte eines mechanischen Tasters passiert folgendes: die Kontakte prallen gegeneinander - Signal "1", die Kontakte springen wieder auseinander - Signal "0", dann berühren sie sich wieder, und wieder auseinander, bis sie sich endlich beruhigen und sicheren Kontakt zueinander herstellen. Erst dann ist ein stabiles Signal "1" vorhanden.
Beim ersten Erkennen des Signals "1" wird gezählt , dann 0,1s gewartet, bis eine sichere "1" da ist. Um einen Tastendruck von einer nicht losgelassenen Taste zu unterscheiden, wird ein "0"-Signal erwartet. Wenn die Minus-Taste gedrückt wird, dann passiert das gleiche: nur es wird rückwärts gezählt.

Wer mit C noch nicht bekannt ist, findet wahrscheinlich einige Befehle seltsam.

Hier gibt's einige Erklärungen:

" i++; " ist " i +=1; " ist " i=i+1; " Variable "i" um Eins erhöhen
while (i); --------verkürzte Schreibweise für:

while(i>0)
{

}

Das bedeutet: solange "i" größer als 0 ist, wird eine leere Schleife wiederholt. Das Programm bleibt an diese Stelle stehen und läuft erst weiter, wenn "i" gleich 0 wird.


if (Plus) t = 5;

Abkürzung für
if ( Plus > 0 )
{
t = 5;
}
Klammern müssen benutzt werden, wenn mehrere Befehle bedingt ausgeführt werden.


i |= 0b.0000.0010;
das heisst
i= i | 2 ; Variable "i" wird mit Zahl 2 ODER-verknüpft und das Ergebnis wird in "i" gespeichert.

void pause(void)
"nix Funktionsname (nix)" , erste "nix" steht für Definition des Rückgabewertes, zweites "nix" für Definition des Wertes der einer Funktion übergeben wird.

Eine Addierfunktion sieht so aus:
int ADD (int a,int b)
{
int c;
c=a+b;
return c;
}


Aufruf dieser Funktion
PORTB=ADD(4,8);

Auf dem Port B wäre die Zahl 12 in Binärform zu sehen.


Online: 1
Heute: 1
Vortag: 1
Tagesrekord: 9
Gesamt: 549
Gezählt seit 06.06.03

Letzte Änderung 15.02.08

© Michael Dworkin

Über mich

Haftungsausschluss