|
![]() |
|
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:
}
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.
Abkürzung für
if ( Plus > 0 )
{
t = 5;
}
Klammern müssen benutzt werden, wenn mehrere Befehle bedingt ausgeführt werden.
Aufruf dieser Funktion
PORTB=ADD(4,8);
Auf dem Port B wäre die Zahl 12 in Binärform zu sehen.
|
Online: 1 |
© Michael Dworkin
|
|