In unserem vorherigen Tutorial haben wir gelernt, wie man eine LED mit einem PIC-Mikrocontroller blinkt, und dieselbe Schaltung auf der Perf-Karte aufgebaut. Dann haben wir PICkit 3, ICSP und MPLAB IPE verwendet, um das Programm auf unser Perf-Board zu übertragen. In diesem Tutorial werden wir uns darauf konzentrieren, mehr Pins für den PIC-Mikrocontroller zu verwenden. Wir werden 7 Ausgänge (LEDs) und einen Eingang verwenden. In diesem Tutorial verwenden wir das alte Perf-Board (siehe unten) und fügen Bergsticks hinzu, um die erforderlichen Stifte auf dem zweiten LED-Board herauszuziehen. Am Ende dieses Tutorials werden wir mit dem PIC-Mikrocontroller PIC16F877A eine Folge blinkender LEDs generieren und lernen, wie mehrere Ein- und Ausgänge verwendet werden. Einige Grundlagen zum Aufrufen von ' for' -Schleifen und Funktionen.
Die LED-Platine ist nichts anderes als eine weitere Perf-Platine, auf die wir die LEDs mit einem Strombegrenzungswiderstand (siehe unten) löten. Wir werden auch einen Druckknopf hinzufügen, um das Blinken der Sequenz-LED einzuleiten.
Schaltplan:
PIC-Mikrocontroller PIC16F877A LED-Blinksequenzcode und Funktionsbeschreibung:
Der vollständige Code wurde unten angegeben (siehe Ende). Hier werden wir ihn Zeile für Zeile durcharbeiten. Dieser Code beginnt nacheinander zu leuchten, wenn der Druckknopf gedrückt wird. Um die Sequenzen zu verstehen, schauen Sie sich bitte das Video am Ende des Tutorials an. Ich würde Ihnen empfehlen, die im Video gezeigte Ausgabe mit dem folgenden Code zu vergleichen und zu versuchen, das Programm zu verstehen.
Schauen wir uns den Code Zeile für Zeile an. Die ersten Zeilen dienen zum Einrichten von Konfigurationsbits, die im vorherigen Lernprogramm erläutert wurden. Ich überspringe sie daher vorerst. Der beste Weg, ein Programm zu verstehen, besteht darin, von der Hauptfunktion ( void main () ) aus zu starten
TRISB0 = 1; // Weisen Sie die MCU an, dass der PORTB-Pin 0 als Eingang für die Schaltfläche verwendet wird. TRISD = 0x00; // Weisen Sie die MCU an, dass alle Pins ausgegeben werden. PORTD = 0x00; // Alle Pins auf 0 initialisieren
Das Wort TRIS wird verwendet, um zu definieren, ob der Pin als Ein- / Ausgang verwendet wird, und das Wort PORT wird verwendet, um einen Pin hoch / niedrig zu machen. Die Zeile TRISB0 = 1 bildet den 0. Pin von PORT B als Eingang. Dies wird unser Druckknopf sein. Die Zeilen TRISD = 0x00; PORTD = 0x00; macht alle Pins von Port D als Ausgang und weist diesen Pins einen Anfangswert von LOW zu.
Da wir gesagt haben, dass B0 als Eingang verwendet wird, verbinden wir ein Ende des Druckknopfs mit dem Pin B0 und das andere Ende mit Masse. Bis dahin wird der Stift bei jedem Drücken der Taste wie im obigen Anschlussplan gezeigt gegen Masse gehalten. Um dies zu erreichen, müssen wir jedoch einen Pull-up-Widerstand verwenden, damit der Stift hoch gehalten wird, wenn der Knopf nicht gedrückt wird. Ein Pull-up-Widerstand ist so etwas.
Unsere PIC-MCU verfügt jedoch über einen internen schwachen Pull-up-Widerstand, der per Software aktiviert werden kann, um viel Aufwand zu sparen (wenn mehr Tasten angeschlossen werden sollen).
Was ist ein schwacher Pull-up-Widerstand?
Es gibt zwei Arten von Pull-Up-Widerständen: den schwachen Pull-up und den starken Pull-up. Die schwachen Pull-up-Widerstände sind von hohem Wert und lassen somit einen schwachen Strom durch und die starken Pull-up-Widerstände sind von geringem Wert, wodurch ein starker Strom fließen kann. Alle MCUs verwenden meistens schwache Pull-up-Widerstände. Um dies in unserer PIC-MCU zu aktivieren, müssen wir in unserem Datenblatt nach OPTION_REG (Optionsregister) suchen, wie im folgenden Schnappschuss gezeigt.
Wie gezeigt, befasst sich das Bit 7 mit dem schwachen Pull-up-Widerstand. Es sollte auf Null gesetzt werden, um es zu aktivieren. Dies erfolgt durch OPTION_REG <7> = 0 . Dies betrifft speziell das Bit 7, wobei die anderen Bits auf ihren Standardwerten belassen werden. Damit gelangen wir in unsere while-Schleife, in der mit if (RB0 == 0) geprüft wird, ob die Taste gedrückt wird . Wenn die Bedingung erfüllt ist, rufen wir unsere Funktion mit den Parametern 1, 3, 7 und 15 auf.
sblink (1); // FUNCTION CALL 1 mit Parameter 1 sblink (3); // FUNCTION CALL 3 mit Parameter 3 sblink (7); // FUNCTION CALL 7 mit Parameter 7 sblink (15); // FUNCTION CALL 4 mit Parameter 15
Warum verwenden wir Funktionen?
Funktionen werden verwendet, um die Anzahl der Zeilen in unserem Code zu reduzieren. Das hätten die meisten von uns gewusst. Aber warum müssen wir die Anzahl der Zeilen reduzieren, insbesondere wenn es um die MCU-Programmierung geht? Der Grund ist der begrenzte Speicherplatz in unserem Programmspeicher. Wenn wir den Code nicht richtig optimieren, geht uns möglicherweise der Speicherplatz aus. Dies ist praktisch, wenn wir lange Seiten mit Codes schreiben.
Jede Funktion hat eine Funktionsdefinition (in unserem Fall sblink (int get) ) und einen Funktionsaufruf (in unserem Fall sblink (1) ). Es ist optional, eine Funktionsdeklaration zu haben. Um dies zu vermeiden, habe ich meine Funktionsdefinition platziert, bevor ich die Funktion in meine Hauptfunktion aufrufe.
Funktionsparameter sind der Wert, der vom Funktionsaufruf an die Funktionsdefinition übergeben wird. In unserem Fall sind die ganzzahligen Werte (1, 3, 7, 15) die Parameter, die vom Funktionsaufruf übergeben werden, und die Variable "get" erhält den Wert der Parameter in die Funktionsdefinition, um sie zu verarbeiten. Eine Funktion kann mehr als einen Parameter haben.
Sobald die Funktion aufgerufen wird, werden die folgenden Zeilen in der Funktionsdefinition ausgeführt.
für (int i = 0; i <= 7 && RB0 == 0; i ++) {PORTD = get << i; // LED nach links bewegen Sequenz __delay_ms (50); } für (int i = 7; i> = 0 && RB0 == 0; i--) {PORTD = get << i; // LED nach links bewegen Sequenz __delay_ms (50); }}
Nun scheint diese Zeile seltsam zu sein: PORTD = get << i . Ich werde erklären, was hier tatsächlich passiert.
"<<" ist ein Linksverschiebungsoperator, der alle Bits in seine linke Position verschiebt. Wenn wir nun die Funktion sblink (int get) mit dem Parameter '1' als sblink (1) aufrufen, wird der Wert von 'get' als 1 angegeben, was in der Binärdatei 0b00000001 ist. Daher ist diese Zeile wie PORTD = 0b00000001 << i .
Der Wert von "i" variiert von 0 bis 7, da wir eine 'for-Schleife' für (int i = 0; i <= 7 && RB0 == 0; i ++) verwendet haben. Der Wert von 'i' von 0 bis 7 ändert das Ergebnis wie folgt:
Wie Sie sehen können, haben wir jeweils eine LED (von links nach rechts) eingeschaltet, indem wir den Rest ausgeschaltet haben. Die nächste 'for-Schleife' für (int i = 7; i> = 0 && RB0 == 0; i--) macht dasselbe, aber dieses Mal wird die LED in einer Sequenz von rechts nach links eingeschaltet. Wir haben eine Verzögerung von 200 ms verwendet, um zu visualisieren, wie die LED ein- und ausgeschaltet wird.
Wenn wir nun den Wert 3 in der Funktion sblink (int get) übergeben , wird die Funktion sblink (3) ausgeführt, wodurch der Wert von 'get' als 0b00000011 festgelegt wird. Daher lautet das Ergebnis auf PORTD:
Diesmal werden also zu jedem Zeitpunkt zwei LEDs mit sblink (3) eingeschaltet. In ähnlicher Weise leuchten bei sblink (7) und sblink (15) drei und vier LEDs nacheinander. Sobald dies abgeschlossen ist, werden alle LEDs mit der Zeile PORTD = 0xFF eingeschaltet . Überprüfen Sie das Video unten für eine vollständige Demonstration.
Ich hoffe, Sie haben den Code verstanden und somit gelernt, wie Sie die Funktionen 'for' und 'while' verwenden, um die gewünschten Ausgaben zu erhalten. Jetzt können Sie den Code anpassen, um Ihre unterschiedliche LED-Blinksequenz zu erhalten. Kompilieren Sie Ihren Code, speichern Sie ihn auf Ihrer MCU und genießen Sie die Ausgabe. Sie können den Kommentarbereich verwenden, wenn Sie irgendwo stecken bleiben. Ich habe hier auch die Simulations- und Programmdateien angehängt.
In unserem nächsten Tutorial erfahren Sie, wie Sie PIC16F877A-Timer anstelle von Verzögerungsfunktionen verwenden. Hier können Sie alle PIC-Mikrocontroller-Tutorials durchsuchen.