Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
microcontrollertechnik:1_hello_blinking_world [2020/05/05 06:42] tfischer |
microcontrollertechnik:1_hello_blinking_world [2024/03/21 02:58] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== 1. Hello Blinking World ====== | + | wie fi====== 1 Hello Blinking World ====== |
- | ===== AVR Programmierung für Dummies ===== | + | ===== 1.1 AVR Programmierung für Dummies ===== |
- | + | ||
- | <WRAP group> <WRAP column 30%> | + | |
- | + | ||
- | Im Video werden im ersten Teil (bis 15min30sec) die Grundkonzepte für die AVR Programmierung erklärt. | + | |
- | + | ||
- | <panel type=" | + | |
- | Ab der 16. Minute geht es in die Assembler Programmierung. Dies ist nicht Teil des Kurses Mikroprozessortechnik. | + | |
- | </ | + | |
==== Ziele ==== | ==== Ziele ==== | ||
Zeile 18: | Zeile 10: | ||
- wissen was Register sind. | - wissen was Register sind. | ||
- wissen für was das Spezialregister DDRx (x={A, B, C, D}) nützlich ist. | - wissen für was das Spezialregister DDRx (x={A, B, C, D}) nützlich ist. | ||
- | + | < | |
- | </WRAP> <WRAP column 65%> | + | |
==== Video ==== | ==== Video ==== | ||
- | {{youtube>Q1rR1IgBgcU? | + | <WRAP> |
- | </WRAP> </ | + | Im Video werden im ersten Teil (bis 15min30sec) die Grundkonzepte für die AVR Programmierung erklärt. |
+ | |||
+ | <panel type=" | ||
+ | Ab der 16. Minute geht es in die Assembler Programmierung. Dies ist nicht Teil des Kurses Mikroprozessortechnik. | ||
+ | </panel> | ||
+ | |||
+ | {{youtube>Q1rR1IgBgcU}} | ||
+ | |||
+ | </ | ||
+ | |||
+ | ===== 1.2 Es werde Licht! Oder auch nicht... ===== | ||
- | ===== Es werde Licht! Oder auch nicht... ===== | + | < |
- | < | + | |
- | <WRAP column 30%> | + | |
==== Ziele ==== | ==== Ziele ==== | ||
Zeile 35: | Zeile 34: | ||
Nach dieser Lektion sollten Sie: | Nach dieser Lektion sollten Sie: | ||
- | - wissen, wie man im Atmel Studio ein Projekt anlegt. | + | - wissen, wie man im Microchip |
- wissen, wie der Programmierumgebung die Taktfrequenz des Microcontrollers festgelegt wird. | - wissen, wie der Programmierumgebung die Taktfrequenz des Microcontrollers festgelegt wird. | ||
- die wichtigsten Bitmanipulationen (Bitmaske zum setzten und löschen eines einzelnen Bits, togglen) kennen und anwenden können. | - die wichtigsten Bitmanipulationen (Bitmaske zum setzten und löschen eines einzelnen Bits, togglen) kennen und anwenden können. | ||
- | - | ||
==== weiterführende Links ==== | ==== weiterführende Links ==== | ||
* kurzes Youtube Video: [[https:// | * kurzes Youtube Video: [[https:// | ||
- | </ | + | </ |
==== Video ==== | ==== Video ==== | ||
- | {{youtube> | + | {{youtube> |
- | </ | + | </ |
==== Übung ==== | ==== Übung ==== | ||
Zeile 54: | Zeile 52: | ||
--> I. Vorarbeiten # | --> I. Vorarbeiten # | ||
- | - installieren Sie [[0._hilfsmittel#atmel_studio|SimulIDE und Atmel Studio]] | + | - installieren Sie [[0_hilfsmittel#Microchip_studio|SimulIDE und Microchip |
- falls es Probleme bei der Programmierung gibt: nutzen Sie die [[elektronik_labor: | - falls es Probleme bei der Programmierung gibt: nutzen Sie die [[elektronik_labor: | ||
<-- | <-- | ||
- | --> II. Eingabe in Atmel Studio # | + | --> II. Eingabe in Microchip |
- | - öffnen Sie Atmel Studio | + | - öffnen Sie Microchip |
- Anlegen eines neuen Projekts | - Anlegen eines neuen Projekts | ||
- '' | - '' | ||
- Wählen Sie "GCC C Executable Project", | - Wählen Sie "GCC C Executable Project", | ||
- Geben Sie bei Name '' | - Geben Sie bei Name '' | ||
- | - Der Cursor sollte nun im Eingabefeld des Suchfenster für die Microcontroller stehen. Geben Sie dort '' | + | - Der Cursor sollte nun im Eingabefeld des Suchfenster für die Microcontroller stehen. Geben Sie dort '' |
- | - Wählen Sie den ATmega328 | + | - Wählen Sie den mega88 |
- Eingabe und Kompilieren des Code | - Eingabe und Kompilieren des Code | ||
- Ersetzen Sie den vorhandenen Code, durch den rechts stehenden Code | - Ersetzen Sie den vorhandenen Code, durch den rechts stehenden Code | ||
- | - Kompilieren Sie den Code durch '' | + | - Kompilieren Sie den Code durch '' |
- Im unteren Teil des Fensters sollte nun die Ausgabe des Kompilers sichtbar werden. Diese sollte '' | - Im unteren Teil des Fensters sollte nun die Ausgabe des Kompilers sichtbar werden. Diese sollte '' | ||
- Auswählen der hex-Datei | - Auswählen der hex-Datei | ||
- | - im Atmel Studio finden Sie rechts im Fenster den " | + | - im Microchip |
- gehen Sie dort im Solution Explorer zu '' | - gehen Sie dort im Solution Explorer zu '' | ||
- klicken Sie mit rechter Maustaste auf '' | - klicken Sie mit rechter Maustaste auf '' | ||
Zeile 78: | Zeile 76: | ||
--> III. Ausführung in Simulide # | --> III. Ausführung in Simulide # | ||
- Öffnen Sie SimulIDE (unter ...\bin\simulide.exe) | - Öffnen Sie SimulIDE (unter ...\bin\simulide.exe) | ||
- | - links in SimulIDE sollten Sie den Komponenten Browser finden. Wählen Sie dort '' | + | - links in SimulIDE sollten Sie den Komponenten Browser finden. Wählen Sie dort '' |
- | - Ziehen Sie den Eintrag '' | + | - Ziehen Sie den Eintrag '' |
- | - Es sollte nun ein Chip names '' | + | - Es sollte nun ein Chip names '' |
- Erstellen der Ausgangsschaltung | - Erstellen der Ausgangsschaltung | ||
- | - Im Programm wurde im auf PortD das 6bit angesprochen. Entsprechend soll auch hier am Port D der Ausgang | + | - Im Programm wurde im auf PortB das 2bit angesprochen. Entsprechend soll auch hier am Port B der Ausgang |
- Fügen Sie eine LED (im Komponenten Browser über Output LED) und ein Massepotential ein (Sources Ground) | - Fügen Sie eine LED (im Komponenten Browser über Output LED) und ein Massepotential ein (Sources Ground) | ||
- Die Komponenten können mit dem Kontextmenu (Rechtsklick) gedreht und gespiegelt werden. Außerdem ist mit der Auswahl von '' | - Die Komponenten können mit dem Kontextmenu (Rechtsklick) gedreht und gespiegelt werden. Außerdem ist mit der Auswahl von '' | ||
- | - Verbinden Sie die LED mit Masse und mit Port D6. Achten Sie auf die richtige Richtung der LED. Die Verbindungen lassen sich dadurch erstellen, dass auf ein Komponenten-Pin geklickt wird und die Linie zu einem nächsten Komponenten-Pin gezogen wird. | + | - Verbinden Sie die LED mit Masse und mit Port B2. Achten Sie auf die richtige Richtung der LED. Die Verbindungen lassen sich dadurch erstellen, dass auf ein Komponenten-Pin geklickt wird und die Linie zu einem nächsten Komponenten-Pin gezogen wird. |
- Flashen der Software | - Flashen der Software | ||
- Klicken Sie rechts auf den Microcontroller und wählen Sie '' | - Klicken Sie rechts auf den Microcontroller und wählen Sie '' | ||
Zeile 103: | Zeile 101: | ||
- Welche [[Vorgaben für die Softwareentwicklung]] wurden verletzt, trotzdem das Programm lauffähig ist? (Interrupts werden erst in späteren Übungen erklärt) | - Welche [[Vorgaben für die Softwareentwicklung]] wurden verletzt, trotzdem das Programm lauffähig ist? (Interrupts werden erst in späteren Übungen erklärt) | ||
- Wie könnte ein Ampel-Licht-Abfolge oder Lauflicht aus 4 Dioden erstellt und programmiert werden? Welche Optimierungen könnten im Code vorgenommen werden? Welche Komponente in SimulIDE kann genutzt werden? Wie kann die Farbe der LEDs geändert werden? | - Wie könnte ein Ampel-Licht-Abfolge oder Lauflicht aus 4 Dioden erstellt und programmiert werden? Welche Optimierungen könnten im Code vorgenommen werden? Welche Komponente in SimulIDE kann genutzt werden? Wie kann die Farbe der LEDs geändert werden? | ||
- | - Lesen Sie auf Mikrocontroller.net im Kapitel [[https:// | + | - Lesen Sie auf Mikrocontroller.net im Kapitel [[https:// |
+ | - Registeranalyse | ||
+ | - Öffnen Sie in Simulide die RAM Table (Rechtsklick auf Microcontroller '' | ||
+ | - Analysieren Sie das Verhalten der Register '' | ||
+ | - Zählt der Zähler aufwärts oder abwärts? Ändern Sie dazu die Simulationsgeschwindigkeit bei den Einstellungen. Die Einstellungen sind über das Zahnrad in der Menüleiste oben links zu erreichen. Im Reiter '' | ||
- | <WRAP right 80%> | + | <-- |
- | > Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich. | + | |
- | </ | + | |
- | <-- | ||
</ | </ | ||
- | <code C [enable_line_numbers=1, start_line_numbers_at=1] main.c> | + | <sxh c; first-line: |
#define F_CPU 8000000UL | #define F_CPU 8000000UL | ||
Zeile 121: | Zeile 120: | ||
int main(void) | int main(void) | ||
{ | { | ||
- | DDRD=0b01000000; | + | DDRB=0b00000100; |
- | while (1) | + | while (1) |
- | { | + | { |
- | PORTD |= (1<<6); | + | PORTB |= (1<<2); |
_delay_ms(1000); | _delay_ms(1000); | ||
- | PORTD &= ~(1<<6); | + | PORTB &= ~(1<<2); |
- | _delay_ms(1000); | + | _delay_ms(1000); |
- | } | + | } |
- | } | + | }</sxh> |
- | </code> | + | |
<WRAP right>< | <WRAP right>< | ||
Zeile 138: | Zeile 136: | ||
</ | </ | ||
</ | </ | ||
+ | |||
+ | ~~PAGEBREAK~~ ~~CLEARFIX~~ | ||
+ | |||
+ | ===== 1.3 Weiterführende Fragen und Infos ==== | ||
+ | |||
+ | --> Was hat es mit " | ||
+ | |||
+ | Mittels dieser Auswahl lassen sich verschiedene Konfigurationen des Compilers setzen. Der Compiler übersetzt den C-Code in maschinenlesbaren Code und wird bei bei Bedarf Hinweise/ | ||
+ | * Kriterien für Hinweise/ | ||
+ | * Optimierungen bei der Kompilierung | ||
+ | * Ablageort der Dateien | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Was ist DDRB, PORTB?# | ||
+ | |||
+ | Die Anschlüsse (Pins) des Chips sind in 8er Gruppen sortiert, den sogenannten Ports. | ||
+ | Für jeden Port sind jeweils drei Register-Bytes vorhanden: DDRx, PORTx und PINx. Diese Speicherstellen ermöglichen die Konfiguration des Ports. Die Bits in den Registern stehen für die einzelnen Anschlüsse: | ||
+ | |||
+ | Das Bit im **DDRx** (__D__ata __D__irection __R__egister) wählt die Richtung des Pins aus. Wenn dort logisch Eins geschrieben wird, wird der entsprechende Pin als Ausgangspin konfiguriert. Wenn dort logisch Null geschrieben wird, wird der entsprechende Pin als Eingangspin konfiguriert. | ||
+ | |||
+ | Das Bit im **PORTx** Register hat mehrere Eigenschaften: | ||
+ | Wenn das gewünschte Bit in PORTx logisch Eins geschrieben wird und der Pin als Ausgangspin konfiguriert ist, wird der Portpin auf high (eins) gesetzt. Wenn das gewünschte Bit in PORTx logisch Null geschrieben wird und der Pin als Ausgangspin konfiguriert ist, wird der Portpin auf Low (Null) getrieben. | ||
+ | |||
+ | Auch wenn ein Pink als Eingangspin konfiguriert wurde, hat PORTx eine Funktion. Wenn in diesem Fall das gewünschte Bit in PORTx logisch eins geschrieben wird, wird der Pull-up-Widerstand aktiviert. Ein Pull-up-Widerstand ist ein höherohmiger Widerstand (im Bereich $20~\rm k\Omega$ ... $100~\rm k\Omega$), der bei nicht weiter verbundenem Pin den ausgegebenen Wert auf logisch Eins zieht. Um den Pull-up-Widerstand auszuschalten, | ||
+ | |||
+ | Das Einlesen der Signale wird in einem späteren Kapitel erklärt. | ||
+ | <-- | ||
+ | |||
+ | --> | ||
+ | Vielleicht kennen Sie noch die Begriffe Register oder Schieberegister aus den Grundlagen der Digitaltechnik (siehe [[grundlagen_der_digitaltechnik: | ||
+ | sind im allgemeinen Speicherzellen mit besonderen Funktionen, auf denen der Rechenkern besonders schnell zugreifen kann. Im Folgenden sind eine Auswahl an Registern kurz beschrieben: | ||
+ | * AVR-Microcontroller haben 32 **General Purpose Register (R0...R31)**, | ||
+ | * Der **Programm Counter (PC)** ist ein internes Register, welches auf den nächsten Befehl für den Rechenkern zeigt. Intern bedeutet, es kann nicht direkt über den Code ausgelesen oder geändert werden. Indirekt geht dies schon, da der PC nach jedem abgearbeiteten Befehl auf den darauffolgenden zeigt. Bei jedem Sprung in eine Funktion oder Wiederholung einer Schleife weist der PC i.d.R. auf eine Stelle, die nicht direkt aufsteigend erreichbar wäre. | ||
+ | * Das **Status Register (SREG)** zeigt verschiedene Stati des letzten ausgeführten Befehls an. War z.B. das Ergebnis der letzten Berechnung Null, so wird das Z-Bit im SREG gesetzt. Die angezeigten Werte im SREG helfen dem Prozessor schnell auf Ergebnisse zu reagieren. Weitere Details zum SREG finden sich im Kapitel [[https:// | ||
+ | * Verschiedene **Special Function Register (SFR)**, also Spezialregister, | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> | ||
+ | |||
+ | Die Namen sind im Datenblatt des verwendeten Microcontrollers zu finden. Datenblätter lassen sich allgemein mittels auf zwei Wegen finden: | ||
+ | - Mittels einer Suchmaschine über '' | ||
+ | - Direkt über die Hersteller-Seite | ||
+ | Leider gibt es gerade bei dem ATMEGA88 auch ein **veraltetes** Datenblatt, welches just das ist, wass sich z.B. über Google leichter finden lässt. \\ | ||
+ | in diesem Fall muss also über die Herstellerseite gesucht werden, bzw. bei der Suchmaschine '' | ||
+ | |||
+ | Zum Lesen der Datenblätter empfiehlt sich ein Download und die Betrachtung über einen PDF-Viewer, welcher ein Inhaltsverzeichnis als Seitenleiste ermöglicht (z.B. Acrobat Reader). Ansonsten ist das Inhaltsverzeichnis häufig auch auf den hinteren Seiten des Datenblatts zu finden. | ||
+ | |||
+ | Die gesuchte Pinbelegung ist für den ATmega88 konkret auf Seite 3 unter "1. Pin Configurations": | ||
+ | |||
+ | <WRAP right> | ||
+ | | ||
+ | </ | ||
+ | |||
+ | Falls Sie mit dem englischen Datenblatt Probleme haben, kann ich die [[https:// | ||
+ | |||
+ | ~~PAGEBREAK~~ ~~CLEARFIX~~ | ||
+ | |||
+ | < | ||
+ | |||
+ | --> | ||
+ | |||
+ | Die ATmega Microcontroller basieren alle auf einer ähnlichen Struktur. Bei verschiedenen Varianten (insbesondere bei denen mit geringem "Pin Count" | ||
+ | Ähnlich verhält es sich mit Pin PC7. | ||
+ | |||
+ | Die Anschlüsse GND (Masse) und VCC (Versorgung) sind in der Simulation automatisch verbunden. Der Microcontroller ist also stets betriebsbereit. | ||
+ | |||
+ | < | ||
+ | |||
+ | --> Äh.. wir haben 1000ms als Wartezeit eingegeben, aber die LED blinkt doppelt so schnell..# | ||
+ | |||
+ | Richtig bemerkt. Das liegt daran, dass der verwendete Chip in Simulide auf 16 MHz läuft. Dies ist in der Simulation oben unter dem Start-Button zu sehen. | ||
+ | |||
+ | In Realität wird die Taktfrequenz durch die Randbedingungen wie Performance, | ||
+ | Häufig werden hierbei - neben ganzzahligen MHz - auch Vielfache von 256 genutzt, wie z.B. 12,288 MHz. Dies vereinfacht das exakte Abzählen von (Milli)Sekunden, | ||
+ | Der Takt kann bei der realen Hardware in der Regel nicht zur Laufzeit beliebig geändert werden, sondern liegt fest vor. | ||
+ | |||
+ | Der Controller kenn bei der Ausführung des Codes die Taktfrequenz nicht. Sollen genaue Bruchteile einer Sekunde erzeugt werden, muss dem Compiler die Frequenz über einen define mitgeteilt werden. Im Code geschieht dies über '' | ||
+ | |||
+ | In der Simulation kann über '' | ||
+ | |||
+ | In diesem Fall wäre also die Lösung entweder den Wert von '' | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Wie ist die Ansteuerung von den Pins nun genau zu verstehen?# | ||
+ | |||
+ | Ziel der kleinen Projektes ist es einen Pin wechselnd auf logisch Eins und logisch Null zu ändern. Wichtig ist bei jeder Umsetzung zu prüfen, was __**genau**__ umgesetzt werden soll. | ||
+ | |||
+ | Im Prinzip würde folgender Code das auch ermöglichen: | ||
+ | |||
+ | <sxh c; first-line: 1> | ||
+ | #define F_CPU 8000000UL | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | // Die Zahl in folgender Zeile gibt die Bitposition in der nächsten Zeile an: | ||
+ | // | ||
+ | DDRB=0b00000100; | ||
+ | while (1) | ||
+ | { | ||
+ | PORTB = 0b00000100; // Das Bit für B2 wird gesetzt; am Ausgang liegt VCC an | ||
+ | _delay_ms(1000); | ||
+ | PORTB = 0b00000000; // Das Bit für B2 wird gelöscht; am Ausgang liegt 0V an | ||
+ | _delay_ms(1000); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Hierbei gibt es aber mehrere Probleme: | ||
+ | - Bitte geben Sie bei der Kommentierung Ihres Codes keine Trivialitäten an. D.h. alle angegebenen Kommentare sollen so nicht im Code stehen; Sie dienen hier dem Verständnisaufbau | ||
+ | - Es wird hier nicht nur das gewünschte Bit gesetzt, sondern auch die anderen Bits manipuliert. Das ist in diesem konkreten Fall zunächst kein Problem. __ABER__: Jede Software sollte so entwickelt werden, dass Sie den höchsten Grad an Wartbarkeit und Erweiterbarkeit aufzeigt. Es ist also wichtig auf eine gewisse Codehygiene (" | ||
+ | |||
+ | Achten Sie also darauf, dass die Umsetzung im Code genau das tut was gewünscht ist. In diesem Fall soll nur das Bit B2 manipuliert und alle anderen unverändert belassen werden. | ||
+ | |||
+ | Hiermit ergibt sich die Frage, wie genau nur ein Bit in einem Register geändert werden kann. Dies ist über die Funktionen der logischen Bitmanipulation möglich (UND, ODER, etc.). Hierzu wird das gewünschte Register mit einer Maskierung verknüpft. | ||
+ | |||
+ | Über die Disjunktion (ODER bzw. in C über '' | ||
+ | |||
+ | '' | ||
+ | Maske %%............%% MSK = 0b0000**11**00 \\ | ||
+ | Disjunktion %%..%% R01|MSK = 0b0110**11**01 \\ | ||
+ | '' | ||
+ | Die fett markierten Bits mit logisch Eins in der Maske MSK gewährleisten also, dass die Bits in der Disjunktion '' | ||
+ | In C wäre hierfür '' | ||
+ | Auch für das Setzen eines einzelnen Bits in MSK kann eine logische Bitmanipulation genutzt werden: das Verschieben aller Bits nach links. Der Code '' | ||
+ | |||
+ | <sxh c; first-line: 13> | ||
+ | PORTB |= 1<< | ||
+ | </ | ||
+ | |||
+ | Für das Löschen kann ein ähnliches Konzept genutzt werden. Statt eine " | ||
+ | |||
+ | '' | ||
+ | Maske %%............%% MSK = 0b1111**00**11 \\ | ||
+ | Konjunktion %%..%% R01&MSK = 0b0110**00**01 '' | ||
+ | |||
+ | Die Maske MSK kann hier durch die Negation des gesetzten Bits erfolgen: | ||
+ | |||
+ | '' | ||
+ | negierte Maske %%.....%% MSK = ~ORG_MSK = 0b1111**00**11'' | ||
+ | |||
+ | Der Code ergibt sich dann zu: | ||
+ | |||
+ | <sxh c; first-line: 15> | ||
+ | PORTB &= ~(1<< | ||
+ | </ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Was macht ein define? Warum wird manchmal ein ' | ||
+ | |||
+ | Alle Befehle mit '' | ||
+ | |||
+ | <sxh c; first-line: 1> | ||
+ | #define DUMMY 5 | ||
+ | |||
+ | ... | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | ... | ||
+ | A = DUMMY + 2; | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | In diesem Beispiel wird vor der Übersetzung des Codes die Zeichenfolge '' | ||
+ | |||
+ | <sxh c; first-line: 1> | ||
+ | #define DUMMY1 500 | ||
+ | #define DUMMY2 5 + 3 | ||
+ | |||
+ | ... | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | ... | ||
+ | uint8_t a = DUMMY1; // DUMMY1 ist größer als 500 | ||
+ | uint8_t b = DUMMY2 * 2; // Es wird 5 + 3 *2 = 11 ausgegeben, und nicht (5 + 3)*2 = 16 | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Prinzipiell kann also '' | ||
+ | |||
+ | <sxh c; first-line: 1> | ||
+ | # | ||
+ | #define CLR_BIT(BYTE, | ||
+ | #define TGL_BIT(BYTE, | ||
+ | </ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Wie sähe der Code aus, wenn man sich an die Vorgaben für sauberen Code hielte?# | ||
+ | |||
+ | Hierbei ist zu beachten, dass auch die Verwendung von delays vermieden werden soll. Diese sind ein " | ||
+ | |||
+ | <sxh c; first-line: 1> | ||
+ | #define F_CPU 8000000UL | ||
+ | # | ||
+ | #define TGL_BIT(BYTE, | ||
+ | |||
+ | #define LED_WAIT_TIME 1000 // Dauer bis zum Taktwechsel am Pin | ||
+ | #define LED_PIN PB2 // Pin an dem die LED anschlossen ist | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | SET_BIT(DDRB, | ||
+ | while (1) | ||
+ | { | ||
+ | TGL_BIT(PORTB, | ||
+ | _delay_ms(LED_WAIT_TIME); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Beim " | ||
+ | |||
+ | Klicken Sie auf den fraglichen Code-Snipsel (z.B. Variablen- oder Funktionsname) mit einem Rechts-Klick und wählen Sie '' | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Wie finde ich heraus, was wo definiert wurde? # | ||
+ | |||
+ | siehe vorheriger Punkt | ||
+ | |||
+ | <-- | ||