This shows you the differences between two versions of the page.
| de:book [2011/07/21 10:54] – angelegt seiler | de:book [2020/07/20 12:00] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Einleitung ====== | ||
| + | |||
| + | Dieses Buch wurde als praktisches Handbuch für Mikorcontroller und Robotik konzipiert, in der Hoffnung, dem Leser bei der Entwicklung von „smarten“ Lösungen zu helfen. Darüber hinaus soll es auch dazu beitragen, die Begeisterung für den Ingenieurberuf bei jungen Menschen zu wecken. In erster Linie richtet sich das Buch an Schulen sowie Universitäten, | ||
| + | |||
| + | Ziel ist es, sowohl Lehrende als auch Lernende dabei zu unterstützen, | ||
| + | |||
| + | |||
| + | **Plattform** | ||
| + | |||
| + | Für die praktischen Beispiele in diesem Buch wird ein AVR ATmega128 Mikrocontrollersystem, | ||
| + | |||
| + | |||
| + | Das Buch ist systematisch in fünf Kapitel unterteilt: | ||
| + | |||
| + | **1.** Das erste Kapitel gibt eine kurze Einführung in die grundlegenden elektronischen Prinzipien und Berechnungen. Die vorgestellten Beispiele und Formeln sind sehr nützlich für viele folgende Aufgaben. Außerdem wird die Programmiersprache „C“ kurz vorgestellt und ein paar grundlegende Anwendungsbeispiele werden diskutiert. | ||
| + | |||
| + | **2.** Im zweiten Kapitel wird am Beispiel des ATmega 128 ein Überblick über 8-bit AVR Mikrocontroller gegeben. Dieses Kapitel basiert weitgehend auf dem Datenblatt des ATmega Mikrocontrollers, | ||
| + | |||
| + | **3.** Dieses Kapitel führt die Hardware- und Softwareplattform ein, welche für Lehrzwecke entwickelt wurde und als Grundgerüst für weitere Beispiele in den folgenden Kapiteln dient. Ferner wird an dieser Stelle auch die „HomeLab Library“, eine für das Kit entwickelte Softwarebibliothek, | ||
| + | |||
| + | **4.** Im vierten Kapitel werden schließlich praktische Beispiele sowie Übungen vorgestellt. Die Beispiele sind unterteilt in „Labs“ (Übungsabschnitte) und decken die meisten elektro-mechanischen Bauteile und Funktionen ab. Jeder Abschnitt enthält zunächst eine kurze Beschreibung des theoretischen Hintergrunds sowie praktische Beispiele. Durch einfaches Kopieren der Beispielprogramme in den Controller hat der Nutzer direkt die Möglichkeit, | ||
| + | |||
| + | **5.** Im fünften Kapitel finden sich Tipps für die gemeinsame Arbeit an Problemstellungen. Hier wird illustriert wie man gemeinsam entwickelte Konzepte implementiert sowie präsentiert und wie Berichte verfasst werden. Dabei sind jene Themen, welche in einem Teambericht enthalten sein sollen, besonders hervorgehoben. Weiterhin wird an dieser Stelle auch ein Beispielprojekt vorgestellt, | ||
| + | |||
| + | Wir hoffen, dass das Buch eine gute Hilfe sowohl für neue als auch für erfahrene Mikrocontroller- und Robotik-Enthusiasten darstellt und vielen Menschen diese Technologie näher bringt. | ||
| + | |||
| + | Bochum, im Sommer 2013 | ||
| + | |||
| + | Sven Seiler | ||
| + | ====== Mikrocontroller und Robotik====== | ||
| + | |||
| + | === Mikrocontroller === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Mikrocontroller sind im Wesentlichen Computer, welche auf einen einzelnen Chip mit integriertem Schaltkreis positioniert werden und aus einer Speichereinheit, | ||
| + | |||
| + | * Sämtliche Funktionen sind auf einem einzelnen, kleineren und kompakteren Chip gespeichert. | ||
| + | * Er wird zur Durchführung einer bestimmte Aufgabe programmiert, | ||
| + | * Er verbraucht weniger Strom, da alle physischen Komponenten kleiner und energiesparender sind als die eines PC, Laptops oder Servers. Entwickler von Mikrocontrollern fokussieren einen geringen Energieverbrauch, | ||
| + | * In- und Outputs, die auf einen bestimmten Zweck ausgelegt sind. Mikrocontroller besitzen so genannte Peripherie-Schnittstellen, | ||
| + | |||
| + | Mikrocontroller finden sich in diversen Gegenständen des täglichen Gebrauchs: in Haushaltsgeräten (z. B. Mikrowelle, Fernsehgerät), | ||
| + | |||
| + | |||
| + | === Robotik === | ||
| + | |||
| + | Robotik ist die Wissenschaft, | ||
| + | |||
| + | |||
| + | === Mikrocontroller in der Robotik=== | ||
| + | |||
| + | Aufgrund der Weitläufigkeit der Robotik, konzentrieren wir uns in diesem Buch auf die Hobby-Robotik. Diese Systeme sind nicht allzu komplex und es ist möglich sie eigenständig zu implementieren. Häufig genutzte Mikrocontroller in der Robotik sind: | ||
| + | |||
| + | |||
| + | * Atmel AVR Mikrocontroller (ATmega, ATtiny, etc.) | ||
| + | * Microchip Technology PIC Mikrocontroller (PIC16, PIC24, etc.) | ||
| + | * Mikrocontroller, | ||
| + | |||
| + | |||
| + | Drittanbieter haben sehr häufig Entwicklungsplatinen und Umgebungen gebaut, die auf den zuvor genannten Mikrocontrollern basieren. Zum Beispiel: Arduino (VAR), BASICStamp (PIC) und Lego NXT (ARM). Die zur Entwicklung von HomeLab notwendigen Grundvoraussetzungen, | ||
| + | Aus der Vielzahl der zur Verfügung stehenden Mikrocontroller und Entwicklungsplatinen gilt es nun, das für den jeweiligen Bedarf am besten geeignete Produkt auszuwählen. Allgemein lassen sich die folgenden 4 Eigenschaften unterscheiden: | ||
| + | |||
| + | * Arbeitsgeschwindigkeit des Prozessors – legt die Arbeitsgeschwindigtkeit des Chips fest | ||
| + | * Speicherkapazität des Programms – bestimmt die Größe des Programms, das auf dem Chip installiert werden kann | ||
| + | * Datenspeicherkapazität – gibt die mögliche Datenverarbeitungsmenge des Programms an | ||
| + | * Anzahl der Input- / Output-Schnittstellen sowie deren Funktionen – unterschiedliche Schnittstellen bieten differenzierte Möglichkeiten | ||
| + | * Anzahl der Timer – wichtig für das Zeitverhalten der Anwendung | ||
| + | * Energieverbrauch – von großer Bedeutung für mobile Anwendungen | ||
| + | |||
| + | |||
| + | In diesem Buch verwenden wir PC-Software als Entwicklungsumgebung, | ||
| + | ====== Elektronik ====== | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Verschiedene elektronische Schaltkreise werden so häufig in praktischen Beispielen verwendet, dass sie in den folgenden Kapiteln separat beschrieben werden. Da sie das Verständnis der Beispiele sowie den Bau eigener Schaltkreise erleichtern, | ||
| + | |||
| + | ===== Ohm' | ||
| + | |||
| + | Das Ohm’sche Gesetz besagt, dass die Stromstärke eines elektrischen Leiters direkt proportional zu der potenziellen Differenz oder Spannung zwischen zwei Punkten sowie umgekehrt proportional zu dem Widerstand zwischen diesen ist, unter der Voraussetzung, | ||
| + | |||
| + | Die Gleichung lautet wie folgt: | ||
| + | [{{ : | ||
| + | |||
| + | I = U / R | ||
| + | |||
| + | mit: | ||
| + | |||
| + | * I für die Stromstärke [in A] | ||
| + | * U für die Spannung [in V] | ||
| + | * R für den elektrische Widerstand [in Ω] | ||
| + | |||
| + | |||
| + | Viele weitere, in der Elektronik häufig verwendete Gleichungen sind vom Ohm’schen Gesetz abgeleitet. | ||
| + | ===== Spannungsteiler ===== | ||
| + | |||
| + | Ein Spannungsteiler ist ein elektrischer Schaltkreis, | ||
| + | |||
| + | Die Ausgangsspannung des Schaltkreises wird mit folgender Gleichung berechnet: | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | U< | ||
| + | |||
| + | mit: | ||
| + | |||
| + | * U< | ||
| + | * U< | ||
| + | * R< | ||
| + | |||
| + | Die Gleichung ist vom Ohm' | ||
| + | |||
| + | mit: | ||
| + | |||
| + | I = U< | ||
| + | |||
| + | und: | ||
| + | |||
| + | U< | ||
| + | |||
| + | Spannungsteiler werden häufig im Zusammenhang mit Widerstandssensoren (Fotowiderstand, | ||
| + | ===== Berechnung des LED-Widerstands ===== | ||
| + | |||
| + | Für den Fall, dass die Betriebsspannung höher ist als die Spannung der LED, muss der Widerstand in Reihe in den Stromkreislauf geschaltet werden. Er begrenzt die Spannung und erzeugt dadurch den notwendigen Spannungsabfall. Um den korrekten Widerstand auszuwählen, | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | R = (U< | ||
| + | U< | ||
| + | P< | ||
| + | |||
| + | mit: | ||
| + | |||
| + | * R für den Widerstand. | ||
| + | * U< | ||
| + | * U< | ||
| + | * I< | ||
| + | * U< | ||
| + | * P< | ||
| + | |||
| + | Der spannungsbegrenzende Widerstand einer LED darf nicht geringer sein als R und muss mindestens die Leistung von P< | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ====== AVR Mikrocontroller ====== | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Das folgende Kapitel stellt den AVR Mikrocontroller vor, auf welchem dieses Buch basiert. Trotz seiner geringen Größe besitzt der Mikrocontroller eine Vielzahl von Funktionen, welche von Atmel in einem fast 400 Seiten umfassenden Handbuch dokumentiert wurden. Darüber hinaus gibt es noch einige weitere Dokumente, die sich mit der Thematik befassen. Sämtliche Informationen werden in dem folgenden Abschnitt in komprimierter Form dargestellt, | ||
| + | |||
| + | ===== Einführung ===== | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | AVR ist eine Serie aus 8-bit RISC Microcontroller produziert von Atmel. AVR folgt der Harcard-Architektur und hat daher separate Programm- und Datenspeicher. Für das Programm hat er einen internen überschreibbaren Flash-Speicher, | ||
| + | |||
| + | Die Produktion des AVR Microcontroller begann 1997 und heute ist AVR einer der am beliebtesten Controller der freischaffenden Elektronik-Ingenieure. Dank der günstigen Entwicklungstools, | ||
| + | |||
| + | Basierend auf den Typ der Anwendung, gibt es unterschiedliche Typen von AVR Microcontroller, | ||
| + | |||
| + | Der folgende Text beschreibt die Hauptfeatures der megaAVR Serie Microcontroller, | ||
| + | Der Hautunterschied liegt in den Peripherals. | ||
| + | Die Codebeispiele dieser Einführung sind mit AVR LibC in Assembler und C geschrieben . | ||
| + | |||
| + | |||
| + | === äußerer Aufbau === | ||
| + | |||
| + | [{{: | ||
| + | |||
| + | Wie alle anderen Controller ist der AVR in einer Standarthülle gepackt. Das traditionelle Gehäuse ist DIP (bzw. DIL). DIP ist eine so genannte Casing-On-Legs. Alle Pins treten wie Beine , ca 5mm in Länge, aus dem schwarzen Plastikgehäuse hervor. | ||
| + | DIP Gehäuse sind eine gute Wahl für Hobbyanwendungen und Prototypen, weil es dafür günstige Sockets gibt. Daher kann der Microcontroller einfach ersetzt werden sollte er Ausfallen. Die Beine sind aber auch der Nachteil des DIP Gehäuses, da man dafür Löcher in die Platine bohren muss. | ||
| + | |||
| + | Die Surface-Mount-Casings (SMT, bzw. SMD) sind viel kompakter, weil die Pins dafür gedacht sind direkt auf die Platine gelötet zu werden ohne zu Bohren. AMT Microchips sind dünne münzen-große rechteckige Gehäuse mit Pins von ca. 1mm Länge. | ||
| + | Eine ruhigere Hand und präzisere Werkzeuge werden zum löten von SMT Chips benötigt. | ||
| + | |||
| + | |||
| + | AVRs gibt es als DIP und SMT Gehäuse. Das Layout der Pins ist vom Design her so logisch und elektronisch ausgeglichen wie es nur möglich ist. Zum Beispiel sind bei größeren Chips die Ground- und Supply-Pins auf mehreren Seiten des Microcontrollers, | ||
| + | Die erlaubte Analogspannung an den ADC Kanälen ist 0-5.5V. | ||
| + | |||
| + | |||
| + | == ATmega128 == | ||
| + | |||
| + | Um die folgenden Beispiele am ATmega 128 besser zu verstehen, gibt es am Ende des Textes ein Pinout-Schema des ATmega128 (SMT Package). | ||
| + | An jedem Pin ist ein Text mit der Nummer, primären Funktion und sekundären (alternativen) Funktion in Klammen. Supply Pins sind GND und VCC. | ||
| + | AVCC und AREG sind die analog zu digital Konverter Supply- und ReferenceVoltage-Pins. | ||
| + | XTAL1 und XTAL2 sind für den Anschluss einen externen Schwingquarzes, | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | ===== Register ===== | ||
| + | |||
| + | Typischerweise ist das Register eines der Bestandteile eines Mikrocontrollers, | ||
| + | |||
| + | === Essence === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Register ähnelt einem Panel von Tasten eines Haushaltsgerätes. Es verfügt über Schalter, die ein- und ausgeschaltet werden können. Das beste Beispiel hierfür ist ein Kassettenrekorder. Zur Erinnerung, ein Kassettenrekorder verfügt über 6 Tasten von links nach rechts: | ||
| + | |||
| + | |||
| + | * Aufnahme | ||
| + | * Zurückspulen | ||
| + | * Abspielen | ||
| + | * Vorspulen | ||
| + | * Stopp | ||
| + | * Pause | ||
| + | |||
| + | Jede Taste führt eine Funktion aus, jedoch nur wenn sie auch korrekt verwendet wird. So macht die Stopp-Taste solange nichts, bis die Kassette abgespielt wird. Erst dann kann die Funktion ausgeführt werden und die Wiedergabe wird gestoppt. Dagegen können Vorlauf- und Rückspultasten zu jeder Zeit betätigt werden, denn die Kassette kann in beide Richtungen gespult werden, unabhängig davon ob sie gerade abgespielt wird oder nicht. Die Aufnahmetaste startet nur dann eine Aufnahme, wenn sowohl die Abspielen- als auch die Aufnahmetaste zeitgleich gedrückt werden. Eventuell hat mancher einmal versucht, mehrere oder alle Tasten auf einmal zu betätigen. Dieses hat vermutlich eine unerwartete Funktion des Kassettenrekorders ausgelöst oder ihn sogar beschädigt. | ||
| + | |||
| + | Die Register von Mikrocontrollern verhalten sich wie Tasten eines Kassettenrekorders – jede Taste führt eine Funktion aus, wenn sie korrekt verwendet wird. Werden die falschen Tasten betätigt, wird der Mikrocontroller in der Regel nicht direkt beschädigt, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Da der Status eines Registerschalters einfach durch eine Nummer abgebildet werden kann, lässt sich ein Register mit einem Speicher vergleichen, | ||
| + | |||
| + | |||
| + | Während es bei einem Kassettenrekorder möglich ist, jeden Knopf einzeln zu betätigen, ergeben sich bei einem Register Schwierigkeiten, | ||
| + | |||
| + | === Gebrauch === | ||
| + | |||
| + | Zur Programmierung eines Registers oder auch dazu, um Werte aus diesem abzulesen muss er als Variable in C deklariert werden. Das folgende Beispiel veranschaulicht, | ||
| + | |||
| + | <code c> | ||
| + | REG = 0b01100001; | ||
| + | unsigned char reg = REG; | ||
| + | </ | ||
| + | |||
| + | Die Schwierigkeit liegt nicht darin, Registerwerte zu schreiben und auszulesen, sondern vielmehr darin, ein einzelnes Bit zu verändern. Hierzu sind Kenntnisse der Binärmathematik sowie im Gebrauch diverser Zahlensysteme notwendig. Es ist auch möglich, nur mit Binärzahlen zu arbeiten. Da diese aufgrund ihrer Länge die Programmierarbeit jedoch erschweren können, verwenden die meisten Programmierer die kürzeren Hexadezimalzahlen. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Im Hexadezimalsystem gibt es nicht nur die Ziffern 0 und 1 wie im binären System oder 0 bis 9 gemäß dem Dezimalsystem, | ||
| + | |||
| + | Um einzelne Bits innerhalb einer Zahl zu verändern (Register, Variable oder ähnliches) müssen Binäroperationen angewandt werden. Binäroperationen sind Vorgänge zwischen zwei Binärzahlen, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | < | ||
| + | |||
| + | * **Negation / Inversion** \\ Eine Negation kehrt den Wert eines Bits in das jeweilige Gegenteil um. So wird aus einer 0 eine 1 und umgekehrt. In C wird eine Negation durch " | ||
| + | * **Logische Multiplikation / Konjunktion** \\ Bei der Multiplikation zweier Bits ist das Ergebnis 1 für den Fall, dass beide Bits den Wert 1 besitzen, ansonsten 0. Eine Logische Multiplikation wird in C durch "&" | ||
| + | * **Logische Addition / Disjunktion** \\ Eine Addition von zwei Bits ergibt 1 wenn zumindest eines der Bits den Wert 1 hat und 0 wenn beide Bits den Wert 0 haben. In C kennzeichnet " | ||
| + | * **Exklusive Disjunktion / Exklusives ODER / XOR** \\ Das Ergebnis einer Exklusiven ODER Operation ist 1 bei zwei unterschiedlichen Bits (also wenn ein Bit den Wert 1 besitzt, das andere den Wert 0), ansonsten 0. Eine Exklusive Disjunktion wird in C durch " | ||
| + | |||
| + | Man benötigt nicht mehr als diese vier Operationen, | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | == Ein einzelnes Bit " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Um einzelne oder mehrere Bits in einem Register “high” zu setzen (1) muss eine logische Addition durchgeführt werden. Hierfür muss ein Operand das Register sein und ein anderer die Binärzahl, wobei das einzige „high“ Bit jenes ist, was ein einem Register „high“ gesetzt werden muss. Diese Binärzahl wird Bitmaske genannt. Nachfolgend ist der C-Code für diese Operation abgebildet: | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x0F | ||
| + | REG = REG | 0x11; // Erste Methode | ||
| + | REG |= 0x11; // Zweite Methode | ||
| + | // Ergebnis REG = 0x1F | ||
| + | </ | ||
| + | |||
| + | == Ein einzelnes Bit “low” setzen == | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Um einzelne oder mehrere Bits in einem Register “low“ zu setzen (0) ist eine logische Multiplikation nötig. Dabei muss ein Operand das Register und ein weiterer eine Bitmaske sein, in welcher das einzige low-Bit jenes ist, welches im Register „low“ gesetzt werden soll. | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x0F | ||
| + | REG = REG & 0xFE; // Erste Methode | ||
| + | REG &= 0xFE; // Zweite Methode | ||
| + | // Ergebnis REG = 0x0E | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | |||
| + | == Ein einzelnes Bit invertieren / umkehren == | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Zum Invertieren einzelner oder mehrerer Bits eines Registers muss eine Exklusive Disjunktion angewandt werden. Hierzu ist ein Operand das Register, der andere muss eine Bitmaske sein, in der das einzige high Bit jenes ist, welches invertiert werden soll. Der C-Code für diese Operation ist unten abgebildet: | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x0F | ||
| + | REG = REG ^ 0x11; // Erste Methode | ||
| + | REG ^= 0x11; // Zweite Methode (nur eine pro Inversion verwenden) | ||
| + | // Ergebnis REG = 0x1E | ||
| + | </ | ||
| + | |||
| + | == Das gesamte Register invertieren == | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Durch die Negationsoperation werden sämtliche Bits eines Register invertiert. Diese Operation besteht aus nur einen Operanden und ist daher unär. Der hierfür benötigte C-Code ist unten abgebildet: | ||
| + | |||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x0F | ||
| + | REG = ~REG; | ||
| + | // Ergebnis REG = 0xF0 | ||
| + | </ | ||
| + | |||
| + | == Den Wert eines einzelnen Bits auslesen == | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Sollen ein oder mehrere Bits aus einem Register gelesen werden muss ebenfalls die logische Multiplikation angewandt werden. Einer der Operanden ist das Register, der zweite eine Bitmaske, in welcher das einzige high-Bit jenes ist, welches aus dem Register gelesen werden soll. Unten ist der C-Code für diesen Vorgang dargestellt. | ||
| + | |||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x0F | ||
| + | unsigned char x = REG & 0x01; | ||
| + | // Ergebnis x = 0x01 | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | |||
| + | == Ein Bit verschieben == | ||
| + | |||
| + | Viele Programmiersprachen verfügen mittlerweile über einige zusätzliche Bitoperationen, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Das Bild auf der rechten Seite zeigt einen Linksshift. Auch wenn ein Bitshift keine logische Operation darstellt und kein zugehöriges Symbol hat, wird diese Operation in C mit "<<" | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | REG = 0x01 << 5; | ||
| + | // Ergebnis REG = 0x20 | ||
| + | </ | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Der Rechtsshift funktioniert auf die gleiche Weise und wird in C durch ">>" | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // Annahme REG = 0x20 | ||
| + | unsigned char x = REG >> 5; | ||
| + | // Ergebnis x = 0x01 (or simply 1) | ||
| + | </ | ||
| + | |||
| + | Wird durch diese Operationen ein Bit vom niedrigsten Rang nach rechts oder vom höchsten Rang nach links verschoben, verschwindet es. Einige Programmiersprachen verfügen jedoch über rotierende Bitshiftoperationen, | ||
| + | |||
| + | Sämtliche Bitoperationen sind nicht nur mit Registern durchführbar, | ||
| + | |||
| + | === AVR Register === | ||
| + | |||
| + | Um tatsächlich mit dem Register eines Mikrocontrollers zu arbeiten, ist es notwendig zu wissen, wie dieser spezielle Mikrocontroller verwendet wird. Zu jedem Mikrocontroller gibt es ein oder mehrere Datenblätter, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die Abbildung zeigt das UCSRnA Register des ATmega128. UCSRnA bezeichnet „USART Control and Status Register A“. Dieses Register wird verwendet um das USART Modul der AVR Mikrocontroller zu konfigurieren und deren Status auszulesen. Sämtliche AVR Registernamen werden in Großbuchstaben geschrieben, | ||
| + | |||
| + | Der Inhalt des Registers wird durch eine Box mit 8 Feldern und einem dicken schwarzen Rahmen dargestellt. Jedes Feld steht hier für ein Bit. Die Bitränge sind oberhalb der Box abgebildet – von links nach rechts ansteigend. Da der AVR ein 8-Bit Mikrocontroller ist, haben auch die meisten seiner Register 8-Bit. | ||
| + | |||
| + | Unterhalb der Bits des Registers finden sich im Datenblatt zwei Zeilen. Die erste gibt an, ob das Bit lesbar (R), beschreibbar (W) oder beides (R/W) ist. Kann beispielsweise der Status eines Bits nicht überschrieben werden, so bleibt das Bit unverändert, | ||
| + | |||
| + | Während die AVR Registernamen auf eine tatsächliche Adresse im Speicher verweist, enthalten Bitnamen den Rang und das zugehörige Bit. Daher ist eine Transformation der Namen zu Bitmasken mit einer Shiftoperation notwendig, wenn man mit Bits in einem Register arbeiten will. Der folgende Code zeit einige Beispielzeilen für die Nutzung des USART 0 Modul Registers. | ||
| + | |||
| + | <code c> | ||
| + | // Setze TXC0 Bit high | ||
| + | UCSR0A |= (1 << TXC0); | ||
| + | |||
| + | // Setze U2X0 Bit low | ||
| + | UCSR0A &= ~(1 << U2X0); | ||
| + | |||
| + | // Lies den Wert aus UDRE0 Bit(Maske) | ||
| + | unsigned char u = (UCSR0A & (1 << UDRE0)); | ||
| + | |||
| + | // An dieser Stelle ist der Wert entweder 0 oder 32, | ||
| + | // wodurch die Nutzung in einer logischen Operation aktiviert wird | ||
| + | if (u) | ||
| + | { | ||
| + | // Invertiere MPCM0 Bit | ||
| + | | ||
| + | } | ||
| + | |||
| + | // Manchmal ist es notwendig einen spezifischen 1 oder 0 Wert zu erhalten | ||
| + | // Dazu muss das Bit nach rechts verschoben werden | ||
| + | u >>= UDRE0; | ||
| + | |||
| + | // Nun ist der Wert entweder 0 oder 1 | ||
| + | </ | ||
| + | |||
| + | ===== Architektur ===== | ||
| + | |||
| + | Der AVR hat einen internen 8-Bit Daten-Bus, durch den Daten zwischen der arithmetisch-logischen Einheit (ALU), dem Status Register (SREG), dem Befehlszähler (PC), dem Random-Access-Memory (SRAM), und den Peripherieschnittstellen bewegt werden können. Das Programm, eine Reihe an Befehlen, die in der ALU ausgeführt werden, resultiert aus einer Adresse im Flash-Speicher, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | === Befehls-Pipeline === | ||
| + | |||
| + | Der AVR hat eine zweistufige Befehls-Pipeline. Während ein Befehl ausgeführt wird, wird der nächste aus dem Programmspeicher geholt. Darum sind beim Ausführen einer „Jump-Instruction“ zwei Takte notwendig, um die Bedingungen des Jumps zu erfüllen. Neue Befehle werden immer von der nächsten Speicheradresse geholt. Dadurch ist es notwendig die vorherigen Befehle zu löschen und neue zu laden, wenn man zu einer neuen Adresse springt, da der Ort an dem der Befehl geholt wurde nun nicht mehr stimmt. | ||
| + | |||
| + | === Mehrzweckregister === | ||
| + | |||
| + | Mehrzweckregister R0-R31 sind wie Buffer, um mit Speicher- und Peripheriedaten zu arbeiten und sie zu speichern. Sie vereinfachen die Architektur des Prozessors, weil sie schnellen Zugang der ALU erlauben und der Datenbus nicht immer benutzt werden muss um Operanden aus dem Speicher zu lesen. Mehrzweckregister werden für alle datenbezogenen arithmetischen und logischen Abläufe benutzt. | ||
| + | |||
| + | Wenn man in Assembler programmiert, | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | register char x; | ||
| + | </ | ||
| + | |||
| + | === Befehlssatz === | ||
| + | |||
| + | Der Befehlssatz der meisten AVRs besteht aus 90-133 verschiedenen Befehlen. Der ATmega128 hat 133 Befehle. Befehle haben entweder ein, zwei, oder keine Operanden. Die meisten Befehle benötigen nur einen Takt zur Ausführung, | ||
| + | <box 100% round # | ||
| + | |||
| + | Die ist ein Teil eines in Assembler geschrieben Codes, der bloße Befehle beinhaltet, welcher eine 5 zum Byte in der RAM-Adresse $100 (dezimal 256) hinzufügt. Diese Befehle gibt es alle im AVR. | ||
| + | |||
| + | <code asm> | ||
| + | ldi r1, 5 ; Lädt die Konstante 5 in das Mehrzweckregister r1 | ||
| + | lds r2, $100 ; Lädt das Byte aus dem Speicher in das Register r2 | ||
| + | add r2, r1 ; Fügt den Wert von r1 zu r2 hinzu | ||
| + | sts $100, r2 ; Schreibt den Wert von r2 zurück in den Speicher | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | === Programmstapelspeicher (stack) === | ||
| + | |||
| + | Ein Stapelspeicher (stack) ist eine Datenstruktur, | ||
| + | |||
| + | Der Stack der MegaAVR-Serie ist physikalisch im Random-Access-Memory zu finden. Einige Modelle der tinyAVR-Serie besitzen jedoch keinen Random-Access-Memory sodass der Stack hier durch eine kleine, separate und begrenzte Speichereinheit realisiert. Normalerweise gibt es keinen Compiler für Modelle ohne Random-Access-Memory. | ||
| + | |||
| + | Um in einer hochleveligen Sprache zu programmieren (Pascal, C, C++), ist es nicht notwendig, sich mit der inneren Arbeitsweise eine Mikrocontrollers zu beschäftigen, | ||
| + | ===== Taktgeber ===== | ||
| + | |||
| + | Wie die meiste digitale Elektronik, arbeitet auch der AVR in einer konstanten Frequenz. Eine konstante Frequenz versichert die Zuverlässigkeit von Datenaustausch im Gerät. Es gibt unterschiedliche Methoden um ein Taktsignal für den AVR zu generieren. | ||
| + | |||
| + | **Interner RC Oszillator** | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Dies ist ein interner Taktgeber, welcher keine externen Komponenten benötigt. Seine größten Nachteile sind niedrige Taktfrequenz und Ungenauigkeit. | ||
| + | |||
| + | **Externer RC Oszillator** | ||
| + | |||
| + | Funktioniert nach dem gleichen Prinzip wie ein interner Taktgeber und hat keine signifikanten Vorteile gegenüber diesem. | ||
| + | |||
| + | **Schwingquarz** | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Schwingquarze nutzen einen Kristall (gewöhnlich einen Quarz), welcher in einem elektrischen Feld in seiner Resonanzfrequenz vibriert. Er hat die piezoelektrische Eigenschaft bei mechanischer Deformation (Vibration) ein elektrisches Feld zu produzieren. Schwingquarze haben eine Präzision von ca. 0.001%, welche temperaturunabhängig ist. | ||
| + | |||
| + | **Keramische Resonatoren** | ||
| + | |||
| + | Keramische Resonatoren ähneln den Schwingquarzen, | ||
| + | |||
| + | **Externes Taktsignal** | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Externes Taktsignal kann mit jedem Gerät erzeugt werden, solange die Frequenz und die Amplitude (Spannung) im richtigen Bereich liegen. Zum Beispiel kann ein externer Taktgeber benutzt werden um ein Taktsignal gleichzeitig an mehrere Microcontroller weiterzugeben. | ||
| + | |||
| + | ===== Interrupts ===== | ||
| + | |||
| + | Interrupts können im AVR – je nach Controller - durch Zähler, Kommunikations-Interfaces, | ||
| + | |||
| + | Jeder Interrupt des AVR Microcontrollers ist an ein bestimmtes Ereignis gebunden. Jedes Ereignis hat einen Flag-Bit im Status-Register, | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Um Interrupts mit der AVR LibC Bibliothek zu nutzen, ist es notwendig interrupt.h einzubinden. Der Code der ausgeführt wird, wenn der Interrupt stattfindet, | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | ISR(XXX_vect) | ||
| + | { | ||
| + | // Anweisungen | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | Die generelle Erlaubnis sämtlicher Interrupts wird vom Control- und Statusregister SREG konfiguriert. Die Option, alle Interrupts sofort zu erlauben oder zu verbieten existiert zum Schutz von Daten. Da Interrupts das Ausführen eines Programms unterbrechen, | ||
| + | |||
| + | < | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Angenommen, in diesem Programm wird eine 16-Bit Variable verwendet, welche sowohl von dem Hauptprogramm, | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | // Globale 16-Bit Variable x und y | ||
| + | unsigned short x, y; | ||
| + | |||
| + | // Ein zufälliger Interrupt der den Wert von x ändert. | ||
| + | ISR(XXX_vect) | ||
| + | { | ||
| + | x = 0x3333; | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // x einen Wert geben | ||
| + | x = 0x1111; | ||
| + | |||
| + | // Interrupts generell erlauben | ||
| + | sei(); | ||
| + | |||
| + | // y erhält Wert von x | ||
| + | y = x; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | Das Programm selbst ist sehr einfach - zuerst bekommt die Variable x den Wert 0x1111 und später wird dieser an y weitergegeben. Wenn ein Interrupt zwischen diesen beiden Operationen auftritt, bekommt x einen Wert von 0x3333. Logisch gesehen kann y somit zwei mögliche Werte am Ende des Programms haben, allerdings existiert bei einem 8-Bit AVR noch eine dritte Möglichkeit. Hierzu kommt es, da die 8-Bit Architektur zur Verarbeitung von 16-Bit Daten 2 Taktzyklen braucht. Daher kann ein Interrupt durch schlechtes Timing die Integrität dieser Daten beschädigen. Dadurch kann y am Ende des Programms den Wert 0x1111 oder 0x3333, aber auch 0x3311 haben Um den dritten und ungewollten Wert zu verhindern, sollten alle Interrupts temporär verboten werden wenn eine Operation mehr als einen Taktzyklus umfasst. | ||
| + | |||
| + | Im folgenden Beispiel wird eine sichere Methode benutzt um y den Wert von x zu geben: | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // Interrupts generell verbieten | ||
| + | cli(); | ||
| + | |||
| + | // y erhält Wert von x | ||
| + | y = x; | ||
| + | |||
| + | // Sämtliche Interrupts wieder zulassen | ||
| + | sei(); | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | ===== Digitale Inputs/ | ||
| + | |||
| + | Sämtliche Busse des AVR sind sowohl lesbar als auch beschreibbar, | ||
| + | |||
| + | * PORT - Zur Festsetzung des Outputwertes | ||
| + | * PIN - Zum Auslesen des Inputs am Bus | ||
| + | * DDR - Zur Festlegung der Richtung des Busses. | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Die Pins 0-3 von Bus B sollen Input sein, die Pins 4-7 Output, setzen Sie Pin 5 „high“ und lesen Sie die Werte der Pins 0-3 in einer Variable aus. Der C-Code sieht wie folgt aus: | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | unsigned char x; | ||
| + | |||
| + | // Pins 0-3 als Input, 4-7 als Output | ||
| + | DDRB = 0xF0; | ||
| + | |||
| + | // Setzt Pin 5 " | ||
| + | PORTB |= (1 << PIN5); | ||
| + | |||
| + | // Liest den Wert der Pins 0-3 | ||
| + | x = PINB & 0x0F; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | In diesem Beispiel, wird der Input im Hi-Z (hochohmig) Modus verwendet. Im Wesentlichen liegt an diesem Input keine Ladung an. Diese Betriebsart könnte hilfreich sein, wenn der Pin als Datenbus genutzt wird. Es ist sinnvoll, einen Pull-Up-Widerstand für den Input zu nutzen, wenn der Pin als Taste, Schalter oder anderes verwendet wird wobei er mit der Masse verbunden ist. Hierfür muss das korrespondierende Output-Bit im Inputmodus „high“ gesetzt werden. Als Folge daraus muss zwischen Stromversorgung und Input ein Widerstand eingefügt werden, welcher die Inputspannung hoch hält, bis irgendetwas sie heruntersetzt. Ein solcher Pull-Up-Widerstand dient dazu, ein Floaten des Inputs aufgrund von Reibungselektrizität oder anderen Einwirkungen zu verhindern. Nachdem der Controller gebootet wurde, befinden sich sämtliche IO Busse standardmäßig im hochohmigen Inputmodus. | ||
| + | |||
| + | Normalerweise werden die Pins am IO Bus, neben den logischen Anschlüssen, | ||
| + | ===== Externe Interrupts ===== | ||
| + | |||
| + | Externe Interrupts sind eine der einfachsten Funktionen der Peripheriegeräte. Normalerweise haben AVR's 1 bis 8 spezielle Pins, welche benutzt werden um Interrupts im Programm auszulösen, | ||
| + | |||
| + | Um einen externen Interrupt zu nutzen, muss der Pins als Standard IO Input (er kann auch als Output genutzt werden, jedoch kann der Interrupt dann nur vom Controller selbst ausgelöst werden) konfiguriert werden. Außerdem muss der Empfang von Interrupts zugelassen sein und die Bedingung, welche den Interrupt auslöst, muss im externen Konfigurationsregister des Interrupts spezifiziert werden. | ||
| + | |||
| + | Es existieren vier mögliche Bedingungen: | ||
| + | |||
| + | * Logische Null (Spannung von 0 V) | ||
| + | * Änderung des logischen Werts | ||
| + | * Fallende Flanke – logische Änderung von 1 zu 0 | ||
| + | * Steigende Flanke – logische Änderung von 0 zu 1 | ||
| + | |||
| + | |||
| + | Der Modus „logische Null“ bewirkt, dass der Interrupt durchgehend ausgelöst wird, solange der Pin den Wert Null hat. Während dieser Periode wird die Ausführung des Hauptprogramms gestoppt. | ||
| + | |||
| + | Prinzipiell gibt es zwei Typen von Interrupts: Mit dem Taktgeber des Controllers synchrone und asynchrone Interrupts. Synchrone Interrupts funktionieren indem sie den Wert des Inputs behalten. Auf diese Weise können Änderungen der logischen Werte aufgedeckt werden, indem die Werte zwischen zwei Taktzyklen verglichen werden. Erfolgen die Änderungen des Signals schneller als der Tastzyklus des Controllers, | ||
| + | |||
| + | |||
| + | < | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Lassen Sie ATmega128 Pin Nummer 9 (Pin 7 an Bus E) einen Interrupt auslösen, wenn sich sein Wert ändert. Der Pin gehört zum externen, synchronen INT7 Interrupt. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | // Der Code des externen Interrupts | ||
| + | ISR(INT7_vect) | ||
| + | { | ||
| + | // mache irgendetwas | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Ändere Pin 7 an Bus E zu einem Inputpin, indem Bit 7 auf 0 gesetzt wird | ||
| + | DDRE &= ~(1 << PIN7); | ||
| + | |||
| + | // Definiere einen Pull-Up Widerstand für Pin 7 an Bus E | ||
| + | // um Input Floating zu verhindern. | ||
| + | PORTE |= (1 << PIN7); | ||
| + | |||
| + | // Setzt den Interruptmodus auf “Logische Änderung” für den Interrupt 7 | ||
| + | // im externen Interruptkonfigurationsregister. | ||
| + | EICRB = (1 << ISC70); | ||
| + | |||
| + | // Erlaube externen Interrupt 7 | ||
| + | EIMSK |= (1 << INT7); | ||
| + | |||
| + | // Erlaube globale Interrupts | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | Verfügt der AVR über ausreichend Pins, ist es möglich, zusätzlich zu einem Interrupt der von einem einzelnen Pin ausgelöst wird, eine ganze Gruppe an Pins zu nutzen, um Interrupts durch logische Wertänderungen auszulösen. Diese Interrupts werden einfach „Pin change Interrupts“ genannt. Sie lösen aus, sobald mindestens der Wert von einem Pin in der Gruppe sich ändert. | ||
| + | ===== Analog-zu-Digital Konverter ===== | ||
| + | |||
| + | Analog-zu-Digital Konverter (ADC) transformieren einen analogen Spannungswert in einen digitalen Wert. Die erlaubte Spannungsreichweite am ADC-Input eines AVR Microcontrollers liegt bei 0-5.5V. Der digitale Wert ist 10 Bit groß und bis auf ± 2 Einheiten genau. Der Fehler kann jedoch auch noch größer sein, wenn die Betriebsspannung nicht vor Störungen geschützt ist. Der AVR hat separate Betriebs- und Vergleichsspannungs-Pins für den ADC. Die separate Betriebsspannung trägt dazu bei, Störungen möglichst klein zu halten wobei sie sich nicht mehr als 0.3V von der Hauptbetriebsspannung unterscheiden darf. Die Vergleichsspannung definiert den maximalen digitalen Wert. Beträgt sie zum Beispiel 3V beträgt, dann wird ein Input mit der gleichen Spannung mit 210 - 1 (1023) ausgelesen. | ||
| + | |||
| + | Der AVR ADC arbeitet nach dem Prinzip der schrittweisen Annäherung. Kurz gesagt, die gemessene Spannung wird mit bestimmten Spannungslevels verglichen und die Ergebnisse werden als Bit-Array ausgegeben. Diese Methode ist relativ langsam, da jedes Bit im Endergebnis einzeln berechnet wird. Der AVR benötigt 13 Taktzyklen für jede Messung, für die Erste jedoch (beim Start-up ) werden, 25 Taktzyklen benötigt. Diese Taktzyklen entsprechen jedoch nicht den Arbeitstakten des Controllers, | ||
| + | |||
| + | Der gemessene Wert kann als 8- oder 10-Bit Wert gelesen werden. Da der AVR ein 8-Bit Mikrocontroller ist, verfügt er über zwei 8-Bit Register um ADC-Werte zu speichern. In den Einstellungen kann festgelegt werden, ob die ersten oder letzten zwei Bits in ein seperates Register sollen. Falls die zwei zuletzt ausgelesenen Bits, welche das Ergebnis weniger widergeben, separiert werden, kann das Ergebnis als 8-Bit Wert ausgelesen werden. Eine solche Kombination nennt man „left aligned result“. Darüber hinaus kennzeichnet „right aligned result“ | ||
| + | |||
| + | Ein normaler AVR verfügt über 8 analoge Spannungs-Input-Kanäle. Die Mikrocontroller der ATtiny Serie besitzen weniger, einige ATmega haben 16, allerdings existiert immer nur ein ADC. Um verschiedene Inputs nutzen zu können hat das Gerät einen eingebauten Multiplexer. Der Input des Multiplexer kann durch Nutzung eines speziellen Registers definiert werden. Die ADC Einheit weist darüber hinaus noch weitere Eigenschaften auf: Der Sleepmodus des Prozessors wird für die Umwandlung genutzt, um Störungen zu verringern. Außerdem gibt es die Option zur Nutzung einer internen festen Vergleichsspannung (gewöhnlich 2.65 V, bei manchen Modellen aber 1 V) | ||
| + | |||
| + | |||
| + | < | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Messen Sie die Spannung des ADC Kanals 3 eines ATmega128. Der Spannungsbereich liegt bei 0-5 V und das Ergebnis sollte 8-Bit präzise sein. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | unsigned char result; | ||
| + | |||
| + | // Wähle den AREF Pin zum Vergleich der Spannung | ||
| + | // (es wird angenommen, dass AREF mit der +5V Stromversorgung verbunden ist)) | ||
| + | // Wähle Kanal 3 im Multiplexer r | ||
| + | // ordne das Ergebnis links an | ||
| + | ADMUX = (1 << REFS0) | (1 << ADLAR) | (3); | ||
| + | |||
| + | // Starte den ADC, | ||
| + | // setze den Umwandlungszyklus 16 mal langsamer als das Tastverhältnis | ||
| + | ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADSC); | ||
| + | |||
| + | // Warte auf Beendigung des Messvorganges | ||
| + | while (ADCSRA & (1 << ADSC)) continue; | ||
| + | |||
| + | // Lies den 8-Bit Wert aus | ||
| + | result = ADCH; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | ===== Counters/ | ||
| + | |||
| + | Counter, welche man auch in einigen Fällen Taktgeber nennen kann, sind einer der wichtigsten Unterfunktionen eines Microcontrollers. Diese ermöglichen es Prozesse exakt zu timen, Signale zu generieren und Ereignisse zu zählen. Ein Zähler konvertiert die Nummer der Inputzyklen in einen binären Wert mit Hilfe eines Arrays an Triggern. Die maximale Nummer der gezählten Zyklen hängt von der Länge des Arrays ab und diese ist markiert von der Länge des binären Codes. Der AVR hat 8- und 16- Bit Counter. Wenn ein Timer seinen | ||
| + | Counter unterscheiden sich auch in Applikationsfällen und Arbeitsmodi. | ||
| + | |||
| + | === Counter' | ||
| + | |||
| + | Im Default-Modus macht ein Counter nichts anderes, als fortlaufend Nummer zu zählen | ||
| + | Sein wert kann natürlich jederzeit ausgelesen, und von einem Programm verändert werden. | ||
| + | Die einzige zusätzliche Funktion im Default-Modus ist, dass er ein Interrupt beim Counter-Overflow verursacht. Der Default-Modus wird normalerweise benutzt, um eine Sektion eines Programms in bestimmten Intervallen laufen zulassen. | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Ein 8 MHz ATmega128 soll einen Interrupt alle 10ms (100 Hz) auslösen. Dafür ist der 8-Bit Counter 0 brauchbar. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | ISR(TIMER0_OVF_vect) | ||
| + | { | ||
| + | // Gibt den Counter einen Wert, | ||
| + | // dass der nächste Overflow in 10Hz passiert. | ||
| + | // Formel: 256 - 8 MHz / 1024 / 100 Hz = 177,785 = ~178 | ||
| + | TCNT0 = 178; | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Um den ersten Interrupt in 10ms auszulösen, | ||
| + | // muss der Counter initialisiert werden. | ||
| + | TCNT0 = 178; | ||
| + | |||
| + | // Prescaler Wert 1024 | ||
| + | TCCR0 = 0x07; | ||
| + | |||
| + | // Erlaubt Overflow Interrupts | ||
| + | TIMSK |= (1 << TOIE0); | ||
| + | |||
| + | // Erlaubt global Interrupts | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Der Counter in diesem Beispiel wird den Interrupt nicht in exakt 10 ms generieren, dafür müsste man dem Counter einen Dezimalwert geben, das ist aber nicht möglich. | ||
| + | Um einen präzisen Intervall zwischen den Interrupts zu verwirklichen, | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | == Externer Taktgeber == | ||
| + | |||
| + | Es ist auch möglich einen externen Taktgeber als das Taktsignals eines Counters zu nutzen. | ||
| + | Der AVR hat einen Pin " | ||
| + | Das Externe Taktsignal und die Polarität kann man im Prescaler Register auswählen. | ||
| + | |||
| + | == Timing events == | ||
| + | |||
| + | Da die Counter zeitlich abgestimmte Operationen ermöglichen, | ||
| + | Der Teil des Counter heißt "Input Capture Unit". Es gibt eine Auswahl zwischen zwei Ereignissen: | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Miss die Frequenz eines Externen 122Hz - 100kHz logischen Rechtecksignals mit einem 8MHz ATmega128. Die Messung soll mit einer 1 Hz-Präzision erfolgen. Das Programm nutzt einen 16-Bit Counter mit einer Input Capture Unit. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | unsigned long frequency; | ||
| + | |||
| + | // Interrupt für das Ereignis | ||
| + | ISR(TIMER1_CAPT_vect) | ||
| + | { | ||
| + | // Counter to 0 | ||
| + | TCNT1 = 0; | ||
| + | |||
| + | // Das Ergebnis ist nur gültig wenn der Counter | ||
| + | // noch kein Overflow hatte. | ||
| + | if (!(TIFR & (1 << TOV1))) | ||
| + | { | ||
| + | // Berechnen der Frequenz von der Periode | ||
| + | frequency = (unsigned long)8000000 / | ||
| + | (unsigned long)ICR1; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // Frequenz ist weniger als 122Hz | ||
| + | frequency = 0; | ||
| + | |||
| + | // Setzt die Counter Overflow Flagge auf 0 | ||
| + | TIFR &= ~(1 << TOV1); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Registriert eine " | ||
| + | TCCR1B = (1 << ICES1) | (1 << CS10); | ||
| + | |||
| + | // Erlaubt Ereignis-Interrupts | ||
| + | TIMSK = (1 << TICIE1); | ||
| + | |||
| + | // Erlaubt global Interrupts | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das Programm löst jedes mal bei einer " | ||
| + | Während des Interrupts, überprüft das Programm den Counter auf einen Overflow - dass kann passieren wenn die Frequenz des Signals unter 122Hz (8 MHz / 2< | ||
| + | </ | ||
| + | |||
| + | Events erfassen und die Zeit registrieren die es brauchte damit das Event auftrat kann auf Software Level abgehandelt werden. Es ist möglich einen externen oder andere Interrupts zu nutzen und den Wert des Counters während des Events auszulesen. Das Erfassen auf Hardwarelevel wird genutzt um unabhängig vom Hauptprogramm zu arbeiten und sehr kurze (oder häufige) Events zu timen. | ||
| + | |||
| + | |||
| + | === Taktsignal generieren === | ||
| + | |||
| + | Komplexere Counter können ein Taktsignal generieren, zusätzlich zum Timen eines Signals. Dafür hat der Counter eine " | ||
| + | Ein Interrupt kann generiert werden und spezielle Pin Werte können geändert werden wenn der Counter Wert gleich der des Compare Unit Registers ist. In diesem Moment kann ein Pin entweder High oder low gesetzt oder invertiert werden. Das Signal wird durch Änderungen im Wert des Output-Pins generiert. | ||
| + | |||
| + | In einigen Signal-generierenden Modi, kann der maximale Wert des Counters verändert werden. | ||
| + | Die physikalische Größe bleibt die gleiche, aber ein Vergleichsregister wird benutzt um den Counter bei einem bestimmten Wert zu resetten. | ||
| + | Das vorherige Beispiel kann auch mit dieser Methode gelöst werden, aber die Funktion ist eher für das Ändern der Periode des Signals gedacht. Zusätzlich kann ein Counter so eingestellt werden, dass er mit auf- oder absteigenden Werten arbeitet. | ||
| + | |||
| + | Der Counter und die Signal-generierenden Modi die diese nutzten sind einer der komplexesten Peripheriemodule in einem AVR. Über jeden hier zu schreiben würde eine große Zeitverschwendung sein, normalerweise gibt es keinen Grund alles zu wissen, um sie zu nutzen. Der folgende Absatz beschreibt einer der üblichen PWM Signale in den Robotics. Der Rest kann den AVR Dokumentationen entnommen werden. | ||
| + | |||
| + | == Pulse Width Modulation == | ||
| + | |||
| + | Pulsweitenmodulation (PWM) ist ein Typ eines Signals, wo die Frequenz und die Periode(normalerweise) konstant sind, aber die Länge der Halb-Periode ändert sich. PWM Signale werden benutzt um elektromechanische, | ||
| + | Zum Beispiel, ein Servomotor nutzt ein ein 50Hz PWM Signal und haben einen hohe Halbperiode von 1 - 2 ms. | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Generiere mit einem 8Mhz ATmega128, zwei Geschwindigkeits-regulierende Servomotor Signale. Nutze Pin PB5 (OC1A) um eine Pulsweite von 1ms zu generieren und Pin PB6 (OC1B) um eine Pulsweite von 2ms zu generieren. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Set pins as outputs | ||
| + | DDRB |= (1 << PIN5) | (1 << PIN6); | ||
| + | |||
| + | // Set outputs A and B low for comparison, | ||
| + | // "Fast PWM" mode, prescaler value 8 | ||
| + | TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); | ||
| + | TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); | ||
| + | |||
| + | // Maximum value of the counter. Formula: | ||
| + | // TOP = 8 MHz / 8 / 50 Hz | ||
| + | ICR1 = 20000; | ||
| + | |||
| + | // Half-period of the first motor is 1 ms, and second 2 ms | ||
| + | OCR1A = 1000; | ||
| + | OCR1B = 2000; | ||
| + | |||
| + | // Endless loop | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | ===== USART ===== | ||
| + | |||
| + | USART ist ein Universal Synchrones Serielles Interface, UART ist die vereinfachte Version - Universelles Asynchrones Interface. Der Unterschied zwischen beiden liegt darin, dass das USART auch eine Taktsignalleitung nutzt um Daten zu synchronisieren, | ||
| + | |||
| + | Jede Einstellungsoption hat ein eigenes Register, welches recht einfach anhand des Datenblatts konfiguriert werden kann. Die Baud-Rate ist allerdings etwas schwieriger einzustellen. Das Taktsignal für die Datenübertragung wird vom Taktgeber des Controllers generiert und der Nutzer kann eine Zahl von 1 bis 4096 eingeben, durch welche die Taktrate dividiert wird. Das Ergebnis wird darüber hinaus, je nach Modus, durch 2, 8 oder 16 dividiert. Das Problem ist, dass nicht alle Taktfrequenzen so dividiert werden können, dass das Ergebnis eine Standard-Baud-Rate ergibt. Bei einigen Frequenzen kann die Baud-Rate bis zu 10% vom Standardwert abweichen. Die Datenblätter des AVR beinhalten Tabellen mit Angaben zu den typischen Taktfrequenzen, | ||
| + | |||
| + | Da die Datenübertragung unabhängig vom Prozessor und viel langsamer geschieht, ist es nötig zu bestätigen, | ||
| + | |||
| + | Der Empfang eines Wortes ist wird durch ein spezielles Status-Bit gekennzeichnet. Zusätzlich gibt es Status-Bits, | ||
| + | |||
| + | Der Sende- und Empfangspuffer sind physikalisch getrennte Register, aber sie nutzen die gleiche Speicheradresse und den gleichen Namen. Während des Schreibens in ein gemeinsam benutztes Register, werden die Daten im Sendepuffer gespeichert, | ||
| + | |||
| + | |||
| + | < | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Konfigurieren Sie die USART0 Schnittstelle eines 8 MHz ATmega128 so, dass sie ein 8-Bit-Wort asynchron überträgt, | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Setzt die Baud-Rate auf 9600 bps. Formel: | ||
| + | // | ||
| + | // UBRR = 8000000 / 16 / 9600 - 1 = ~51 | ||
| + | UBRR0H = 0; | ||
| + | UBRR0L = 51; | ||
| + | |||
| + | // Erlaube Senden | ||
| + | UCSR0B = (1 << TXEN0); | ||
| + | |||
| + | // Konfiguriere den asynchronen Modus, setze die Wortgröße auf 8 Bit, | ||
| + | // 1 Stoppbit, kein Paritätsbit. | ||
| + | UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); | ||
| + | |||
| + | // Warte solange, bis der Datenpuffer leer ist (das vorherige Wort wurde gesendet) | ||
| + | // In diesem Beispiel ist es jedoch nicht nötig zu warten, da nur das erste Symbol | ||
| + | // gesendet wird. Es sollte jedoch beachtet werden, wenn mehr als ein Symbol gesendet wird. | ||
| + | while (!(UCSR0A & (1 << UDRE))) continue; | ||
| + | |||
| + | // Schreibe das Symbol in den Sendepuffer. | ||
| + | UDR0 = ' | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | ====== Robotic HomeLab Kit ====== | ||
| + | |||
| + | {{: | ||
| + | | ||
| + | Das auf dem ATmega128 Mikrocontroller basierende Mechatronik und Robotik HomeLab ist eine Zusammenstellung von Modulen in einem tragbaren Koffer. Es ermöglicht die Durchführung diverser Mechatronik- und Robotikexperimente und –übungen, | ||
| + | |||
| + | Das HomeLab kit wurde von der Tallinn University of Technology sowie estnischen Unternehmen in Kooperation mit europäischen Partneruniversitäten und der Unterstützung des Leonardo da Vinci Programms entwickelt. Die HomeLab Module sind zu verschiedenen Bausätzen zusammengestellt. Die Grundausstattung, | ||
| + | |||
| + | Die HomeLab Basic und Advanced kits eignen sich zur Durchführung von Experimenten, | ||
| + | |||
| + | HomeLab Webseite\\ | ||
| + | http:// | ||
| + | |||
| + | DistanceLab Webseite\\ | ||
| + | http:// | ||
| + | |||
| + | |||
| + | |||
| + | ===== Ganzheitliches Konzept der Robotik ===== | ||
| + | |||
| + | Die Ingenieurausbildung kann sich heutzutage nicht mehr auf einer bestimmten Lehrmethode aufbauen, wie zum Beispiel klassische universitäre Vorlesungen und Übungen. Lernende sind heute nicht mehr mit zeitlich festgelegten Vorlesungen und Übungen zufrieden. Viele junge Leute, aber auch Erwachsene, leben ein Leben in einer modernen Informationsgesellschaft, | ||
| + | The integrated concept of robotic and mechatronic study incorporates the standard teaching and studying aids and novel approaches, which are integrated into one methodical unit. | ||
| + | |||
| + | Das ganzheitliche Konzept der Robotik und Mechatronik beinhaltet sowohl standardisierte Lehrmethoden und Lernhilfen, als auch neue Ansätze, welche in einer systematischen Einheit untergebracht sind. | ||
| + | |||
| + | Das folgende Beispiel kann Schulen helfen Kurse zur Robotik zu starten oder einen Denkanstoß zu geben, wie man verschiedene Lernkonzepte in einer praktische Lerneinheit in diesem technologischen Feld anwendet. | ||
| + | |||
| + | Das Konzept beinhaltet die folgenden Lehr- und Lernhilfsmittel: | ||
| + | |||
| + | * Koventionelles Lehrbuch, z.B. „Integrated Systems & Design“ ISBN: 978-9985-59-850-4. | ||
| + | * Praktisches Übungsbuch | ||
| + | * Robotic HomeLab | ||
| + | * DistanceLab | ||
| + | * Das Kompetenznetzwerk der Robotik- und Mechatronikgemeinschaft http:// | ||
| + | |||
| + | Theoretische Lernhilfsmittel sind das konventionelle Lehrbuch und das Übungsbuch, | ||
| + | |||
| + | Der praktische Teil besteht aus dem Robotic HomeLab und dem DistanceLab, | ||
| + | |||
| + | Der Ablauf von einem Lernprozess bzw. der Arbeit mit dem Lab ist auf dem nächsten Bild beschrieben. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Das Thema beginnt mit einer Einführung, | ||
| + | |||
| + | Nach der Einführungsvorlesung wird der praktische Arbeitsteil realisiert. Die Praktische Arbeit besteht anfangs darin, die Codebeispiele auszuführen und später darin, die Beispiele entsprechend der Übung zu verändern. Daraufhin folgen komplexere Übungen, welche durch einen Lehrer jeder Person oder jedem Team individuell aus dem Übungsbuch zugeteilt werden. | ||
| + | |||
| + | Die Ergebnisse der praktischen Arbeit werden in einem Bericht zusammengefasst und dem Betreuer zugeschickt. Falls die Entwicklungsumgebung eine automatische Berichterstattung unterstützt, | ||
| + | ===== Robotik unterrichten ===== | ||
| + | |||
| + | Es ist allseits bekannt, dass die Informations- und Telekommunikationstechnologie (ICT) in das tägliche Leben von vielen Menschen eingetreten ist und die Art und Weise des Lernens und der Kommunikation verändert hat. Viele junge Leute sind es gewohnt Informationen über das Kursmaterial über verschiedene Kommunikationswege aus dem Internet zu bekommen. Bevor versucht wird ein Problem zu lösen wird erst eine schnelle Suche nach möglichen Lösungen, Beispielen oder Hintergrundinformationen durchgeführt. Da die tägliche Kommunikation teilweise in soziale Netzwerke verlagert wurde, ist es nur natürlich, dass die Methodik, welche von den Schulen angewandt wird auch diesem Trend folgen muss, um die Studierenden in ihrem täglichen Umfeld zu erreichen. Natürlich wird die traditionelle Lehrmethodik nicht komplett ersetzt, aber sich nur auf diese zu verlassen ist heutzutage nicht mehr genug. | ||
| + | |||
| + | Robotik und Mechatronik sind sehr zukunftsreiche Gebiete, in denen es sehr wichtig ist den neuesten Trends und Technologien zu folgen. Gleichzeitig sind diese Gebiete sehr praktisch veranlagt und es verlangt viel manuelle Erfahrung Fähigkeiten und Wissen zu erlangen. Selbst verschiedene virtuelle Simulationen können durchgeführt werden um das Systemverhalten zu verstehen. Trotzdem ersetzten die virtuellen Simulationen nicht die praktische Erfahrung mit echter Hardware. | ||
| + | Das Folgende ist eine praktische Anleitung wie ein Robotikkurs eingeführt werden kann, in dem verschiedene Lehransätze genutzt werden. Die Methodik erwartet, dass der Lehrer das HomeLab kit benutzen kann. | ||
| + | |||
| + | Aspekte die bei der Erstellung eines neuen Kursen berücksichtigt werden müssen: | ||
| + | |||
| + | - **Gruppengröße** \\ | ||
| + | Die optimale Anzahl der Teammitglieder ist weitgehend durch die Anzahl der Computer Arbeitsplätze begrenzt. Das bedeutet, dass normalerweise nicht mehr als 3 Personen zusammen an einem Arbeitsplatz arbeiten können. Wenn mehr Personen an einem Arbeitsplatz arbeiten müssen könnte es sein, dass sie nicht in der Lage sind aktiv an der Arbeit teilzunehmen und somit die Konzentration auf die Arbeit verloren geht. | ||
| + | - **Praktische Arbeit und Berichterstattung** \\ | ||
| + | Die Praktische Arbeit ist unterteilt in Übungseinheiten, | ||
| + | * Einführung in die Übung | ||
| + | * Der Lehrer erklärt die neue Übung, geht alle nötigen theoretischen Inhalte durch und führt zusammen mit dem Teilnehmern ein Beispielprogramm aus. | ||
| + | * Die Übungseinheit ist in kleinere Teile unterteilt, wobei jeder Teil aus einem theoretischen und einem praktischen Teil besteht, in welchem dann Quellcode entwickelt werden soll. Das bedeutet, dass der Quellcode anhand von theoretischen Erklärungen entwickelt wird. | ||
| + | * Individuelle Arbeit. Die individuelle Arbeit erfolgt gemäß den Arbeitsanweisungen der Übungseinheit. Hier sind Ziele, Arbeitsprozesse, | ||
| + | * Berichte. Lernende müssen einen Bericht verfassen, in welchem sie ihre Arbeit gemä´den Anforderungen an einen Bericht beschreiben und welcher Antworten auf Fragen des Lehrers an die Gruppe gibt. Der Bericht sowie die Lösung der Aufgabe (HEX-Datei) sollen dem Lehrer per E-Mail zugeschickt oder in den E-Learning Bereich hochgeladen werden. | ||
| + | * Überprüfung | ||
| + | * Der Lehrer überprüft und bewertet den Bericht sowie die erarbeitete Lösung jeder Gruppe qualitativ. | ||
| + | * Er kann überprüfen, | ||
| + | - ** Gruppenmanagement ** \\ | ||
| + | Bei der Durchführung von Übungen in einem Klassenraum kommt es häufig vor, dass eine GRuppe langsamer arbeitet als die anderen und somit stärker vom Lehrer unterstützt werden muss, um nicht hinterherzuhängen. Ähnlich ist es, wenn eine Gruppe schneller arbeitet als alle anderen und somit auf die nächste Aufgabe warten muss. Beide Probleme können minimiert werden, wenn der Arbeitsprozess für alle offensichtlich dargestellt ist und jeder einzelne die vollständigen Übungsanweisungen zu Beginn der Übung erhält. So kann die Gruppe arbeiten, ohne auf die nächstesn Anweisungen des Lehrers warten zu müssen, indem sie einfach den Anweisungen folgt. Darüber hinaus enthält jeder Übungsabschnitt am Ende Aufgaben in verschiedenen Schwierigkeitsgraden, | ||
| + | - **Bewertung** \\ | ||
| + | Soll letztendlich sicher gestellt werden, dass alle Teilnehmer die vorgestellten Programmierfähigkeiten erlernt haben, so kann der Leherer die Gruppenarbeit derart gestalten, dass jedes Gruppenmitglied selbst programmieren und dieses auch präsentieren muss. Eine andere Möglichkeit wäre, dass der Lehrer zufällig ein Mitglied der Gruppe auswählt, welches dann das Programm vorstellen muss. Auch wenn diese Person den Code vielleicht nicht persönlich geschrieben hat. Das Endergebnis wird dann für die gesamte Gruppe gezählt, ausgehend vom Schwächsten Mitglied. Sollte diese Art der Bewertung ungerecht wirken, kann auch innerhalb der Gruppe eine individuelle Berichterstattung durchgeführt werden. | ||
| + | - **Fehlerbehebung** \\ | ||
| + | Die Schüler machen im Umgang mit der Hardware oder beim Programmieren häufig ähnliche Fehler. Daher ist es sinnvoll, auf der Webseite einen Bereich für häufig gestellte Fragen (FAQ - Frequently Asked Questions) einzurichten. So können die Lernenden Zeit sparen, da sie bei häufig auftretenden Fragen oder Problemen schnell Hilfe finden. Der FAQ-Bereich sollte zusammen mit den Lösungen im Support-Bereich der HomeLab Webseite verfügbar sein. | ||
| + | - **Wettbewerb** \\ | ||
| + | Zur Steigerung der Begeisterung für Robotik-Studien kann die praktische Arbeit mit einer Art Wettbewerb verbunden werden. Die Gruppen müssen zu einem gegebenen Problem eine Lösung erarbeiten, welche anschließend gemeinsam bewertet wird. Die Beurteilungskriterien (Zeit, Geschwindigkeit, | ||
| + | |||
| + | < | ||
| + | |||
| + | Das folgende Beispiel veranschaulicht eine typische Übungsanweisung, | ||
| + | |||
| + | <box 100% round #EEEEFF|Lab Nr 3. Sensoren und Analog-Digital Konverter> | ||
| + | |||
| + | **Leiter**: Sven Seiler | ||
| + | |||
| + | **Das Ziel** | ||
| + | |||
| + | - Grundlagen über Analog-Digital-Konverter und das Konvertieren analoger Signale mit dem AVR ATmega128 8-Bit Mikrocontroller. | ||
| + | - Verschiedenen Sensoren mit analogem Output kennenlernen | ||
| + | - Eine einfache Übung mit einem analogen Sensor durchführen. | ||
| + | |||
| + | **Benötigte Ausrüstung** | ||
| + | |||
| + | HomeLab Basic kit, Sensor and Motor Add-On kit, AVR Programmiersoftware. | ||
| + | |||
| + | **Arbeitsanweisungem** | ||
| + | |||
| + | - Führen Sie die Übung mit dem Potentiometer durch. \\ http:// | ||
| + | - Führen Sie die allgemeine Aufwärmübung durch. \\ http:// | ||
| + | - Absolvieren Sie die gruppenspezifische Aufgabe. (diese wird rechtzeitig vom Übungsleiter bekannt gegeben) | ||
| + | - Beantworten Sie die Fragen (gruppenspezifische Fragen werden rechtzeitig vom Übungsleiter bekannt gegeben) | ||
| + | |||
| + | **Bericht** | ||
| + | |||
| + | Der elektronische Bericht muss nach der eigenständigen Arbeit eingereicht werden und folgende Struktur aufweisen: | ||
| + | * Arbeitsbericht | ||
| + | * Das Ziel | ||
| + | * Kurze Beschreibung der durchgeführten Arbeit | ||
| + | * Ausdruck des Algorithmus und Quellcodes für die Schritte 2 und 3. \\ Achtung! Der Quellcode muss kommentiert und farbig gekennzeichnet sein(um das Farbsystem korrekt in MS Word oder einem OpenOffice Programm darzustellen könnte das " | ||
| + | * Anworten auf die Fragen (Schritt4) | ||
| + | * Ergebnisse und Kommentare | ||
| + | * Lösungen (HEX-Dateien) von Schritt 2 und 3 | ||
| + | |||
| + | Der Bericht muss den eigenen Namen, die Nummer des Übungsabschnitts, | ||
| + | |||
| + | **Lektüren** | ||
| + | - HomeLab Support-Center: | ||
| + | - ATmega128 Datenblatt | ||
| + | - Sharp Infrarotsensor Datenblatt | ||
| + | - http:// | ||
| + | </ | ||
| + | ===== HomeLab Hardware ===== | ||
| + | |||
| + | Die Module des Robotik HomeLab sind in unterschiedliche Bausätze („kits“) eingeteilt, um so die am besten geeignete Ausstattung für die Bedürfnisse eines Studenten oder einer Schule auswählen zu können. Das einfachste Set ist das HomeLab Basic kit, welches die für grundlegende Mikrocontrollerexperimente notwendigen Komponenten enthält. Darüber hinaus verfügt es über eine Anwendungsoberfläche mit LCD Display. Das Basic kit kann zusammen mit dem Motor and Sensor Add-On kit verwendet werden. Letzteres beinhaltet verschiedene Arten von Motoren und Sensoren sowie zusätzliches Zubehör und Kommunikationsmodule. Das Sensor and Motor Add-On kit kann nicht ohne das Basic kit verwendet werden, da der Mikrocontroller nicht in dem Add-On enthalten ist. Außerdem enthält das Add-On kit RFID sowie Machine Vision Module. Basic und Add-On kit sind komfortabel im Gebrauch und können bequem transportiert werden, um die Robotikexperimente zu Hause oder am Arbeitsplatz durchzuführen. | ||
| + | |||
| + | === HomeLab Basic kit === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | * AVR ATmega2561 Entwicklungsplatine, | ||
| + | * Benutzerschnittstellenplatine (Schalter, LEDs, graphisches LCD, 7-Segment Anzeige) | ||
| + | * USB Kabel | ||
| + | * Beispielaufgaben mit C-Quellcode | ||
| + | * Softwarebibliothek | ||
| + | * Stromversorgung | ||
| + | * Multimeter | ||
| + | * Software zur Programmierung in Assembler und C | ||
| + | * Tragbarer Koffer | ||
| + | |||
| + | === Sensor and Motor Add-On kit === | ||
| + | |||
| + | |||
| + | == Sensormodul == | ||
| + | |||
| + | * Analoge Sensoren- und Tiefpassplatine mit on-board Sensoren (Temperatursensor, | ||
| + | * Ultraschallentfernungssensor SRF05 mit Kabel | ||
| + | * Infrarotentfernungssensor mit Kabel | ||
| + | |||
| + | == Motormodul == | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | * DC Motor (mit Getriebe und Kodierer) | ||
| + | * RC Servomotor | ||
| + | * Schrittmotor (uni- oder bipolarer Schrittbetrieb) | ||
| + | * Motorentreiberplatine | ||
| + | * Versorgungsteiler | ||
| + | |||
| + | == Kommunikationsmodul == | ||
| + | |||
| + | * Kommunikationsplatine, | ||
| + | * ZigBee oder Bluetooth Funkeinheit | ||
| + | | ||
| + | === Zusätzliche HomeLab Module === | ||
| + | |||
| + | Zusätzliche Module sind nicht in den Koffern enthalten, können jedoch direkt mit dem HomeLab Kommunikationsmodul verbunden werden. Es gibt für diese Module ebenfalls praktische Beispiele und Übungsaufgaben. | ||
| + | |||
| + | == RFID Modul == | ||
| + | |||
| + | * Hochfreqzenz RFID Lesegerät | ||
| + | * Tag (2) | ||
| + | * Kabel | ||
| + | |||
| + | |||
| + | == Machine Vision Module== | ||
| + | |||
| + | * Intelligentes Kamera Module (CMUcam3) | ||
| + | |||
| + | {{: | ||
| + | |||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ===== HomeLab Bibliothek ===== | ||
| + | |||
| + | Die HomeLab Bibliothek besteht aus einigen C Header-Dateien (mit der Dateiendung „.h“) und einer statischen Bibliotheksdatei (mit der Dateiendung „.a“). Während der Installation der Bibliothek werden diese Dateien vollständig in den AVR-GCC Unterordner kopiert. Hier findet der Compiler sie automatisch. Der Benutzer muss diese Dateien somit nicht mehr in den Programmordner kopieren. | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die schrittweisen Installationsanweisungen der AVR Entwicklungssoftware für Windows und Linux sind im ersten Kapitel zu den praktischen Beispielen dargestellt. Auch wenn unterschiedliche Beispiele auf verschiedene Teile der Bibliothek zurückgreifen, | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | Falls die HomeLab Bibliothek nicht genutzt wird, muss die folgende avrlibc Header-Datei in das Projekt eingefügt werden: | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | Die HomeLab Bibliothek enthält diese Datei bereits in der //pin.h// Datei. | ||
| + | |||
| + | Das Installationsprogramm für die HomeLab Bibliothek ist auf der HomeLab Webseite verfügbar. Nutzer, die die Bibliothek an Ihre Bedürfnisse anpassen möchten, können hier auch den Quellcode dafür herunterladen. Das folgende Kapitel beschreibt die Funktionen der Bibliothek. | ||
| + | ==== Bitweise Operationen ==== | ||
| + | |||
| + | Die Bibliothek für bitweise Operationen beinhaltet eine Zusammenstellung von Makrofunktionen zur Durchführung von Bitmanipulationsoperationen. Sie werden von den anderen Komponenten der Bibliotheken genutzt und können überall angewandt werden. Da die Makrofunktionen keinen speziellen Typ haben, sind sie mit jedem Datentyp kompatibel. | ||
| + | |||
| + | Der Bit-Index wird genutzt um das Bit in einer Binärzahl zu spezifizieren. Indizes werden beginnend bei Null gezählt, wobei Null das niedrigstwertige Bit (LSB) kennzeichnet. Eine 8-Bit-Zahl hat zum Beispiel Indizes von 0 bis 7, eine 16-Bit Zahl Indizes von 0 bis 15. | ||
| + | |||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **// | ||
| + | Bit-Index zu Bitmaske konvertieren. Parameter: | ||
| + | * //bit// - Bit-Index. | ||
| + | * Gibt Bitmaske aus. | ||
| + | |||
| + | * **// | ||
| + | Setzt ein bestimmtes Bit in einer Variablen. Parameter: | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | |||
| + | * **// | ||
| + | Löscht ein bestimmtes Bit in einer Variablen. Parameter: | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | |||
| + | * **// | ||
| + | Setzt ein bestimmtes Bit einer Variablen in einen gewünschten Zustand. Parameter: | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | * //state// - Status (//true// or //false//). | ||
| + | |||
| + | * **// | ||
| + | Invertiert ein bestimmtes Bit der Variable. Parameter: | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | |||
| + | * **// | ||
| + | Überprüft, | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | * Gibt den Bool’schen Wert //true//, wenn das Bit gesetzt und //false// wenn das Bit gelöscht wurde zurück. | ||
| + | |||
| + | * **// | ||
| + | Überprüft, | ||
| + | * //value// - Variable. | ||
| + | * //bit// - Bit-Index. | ||
| + | * Gibt den Bool’schen Wert //true//, wenn das Bit gelöscht wurde und// | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Das dritte Bit einer 8-Bit Variablen //b// setzen und Invertieren des letzten Bits. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | unsigned char b = 0x00; | ||
| + | |||
| + | bit_set(b, 2); | ||
| + | bit_invert(b, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Quelle === | ||
| + | Nachfolgend eine gekürzte Version des Quellcodes der Bibliothek für bitweise Operationen. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Funktionen zur Bearbeitung von Bits. | ||
| + | // | ||
| + | #define bit_mask(bit) | ||
| + | #define bit_set(value, | ||
| + | #define bit_clear(value, | ||
| + | #define bit_invert(value, | ||
| + | #define bit_is_set(value, | ||
| + | #define bit_is_clear(value, | ||
| + | #define bit_set_to(v, | ||
| + | |||
| + | // | ||
| + | // Funktionen zur Bearbeitung von Bitmasken. | ||
| + | // | ||
| + | #define bitmask_set(value, | ||
| + | #define bitmask_clear(value, | ||
| + | #define bitmask_invert(value, | ||
| + | #define bitmask_set_to(v, | ||
| + | #define bitmask_is_set(value, | ||
| + | </ | ||
| + | |||
| + | ==== Pins ==== | ||
| + | |||
| + | Die Pins-Bibliothek erleichtert die Arbeit mit digitalen AVR In- und Output-Pins. Der Nutzer kann eine zu einem Pin gehörige Variable erstellen und mit dieser sämtliche Pin-Operationen vornehmen. Auf diese Weise entfällt die Verwendung von Registernamen oder Bit-Indizes, | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **//pin//** Datentyp für Adressen von Pin-Registern und Bitmasken. Um das effizienteste Programm zu entwickeln, sollten //pin// Variablen konstant sein und am Anfang des Programmcodes initialisiert werden. Letzteres kann mit der Makrofunktion //PIN// durchgeführt werden, deren erster Parameter der Buchstabe des Ports ist (A, B, C, etc.) und zweiter Parameter der Pin-Index (0 – 7). Es können nur bestehende Ports und Pins verwendet werden. | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void pin_setup_output(pin pin)//** \\ | ||
| + | Konfiguriert einen Pin als Output. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_setup_input(pin pin)//** \\ | ||
| + | Konfiguriert einen Pin als Input ohne Pull-up Widerstand. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_setup_input_with_pullup(pin pin)//** \\ | ||
| + | Konfiguriert einen Pin als Input mit Pull-up Widerstand. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_set(pin pin)//** \\ | ||
| + | Setzt einen Output-Pin high. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_clear(pin pin)//** \\ | ||
| + | Setzt einen Output-Pin low. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_toggle(pin pin)//** \\ | ||
| + | Invertiert den Status eines Output-Pins. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * **//void pin_set_to(pin pin, bool value)//** \\ | ||
| + | Setzt einen Output-Pin in den gewünschten Zustand. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * //value// - Gewünschter Status als Bool' | ||
| + | * **//bool pin_get_value(pin pin)//** \\ | ||
| + | Holt Pin-Wert. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * Gibt Bool' | ||
| + | * **//bool pin_get_debounced_value(pin pin)//** \\ | ||
| + | Liest den Pinwert durch den Switch-Debounce-Filter. Das Filtern benötigt mindestens 8 ms und kann bis zu 100 ms benötigen, je nachdem wann das Bouncing endet. Falls es nicht endet wird //false// ausgegeben. Funktionen nutzen Softwareverzögerung. Parameter: | ||
| + | * //pin// - Pin Variable. | ||
| + | * Gibt dem Pin den Bool' | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Beispiel um einen Pin-Wert zu erhalten und zu setzen. Pin PC0 Wert wird invertiert und an Pin PC3 angeschlossen. | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | pin output_pin = PIN(C, 3); | ||
| + | pin input_pin = PIN(C, 0); | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | bool value; | ||
| + | |||
| + | // Konfiguriert Pin als Output-Pin | ||
| + | pin_setup_output(output_pin); | ||
| + | |||
| + | // Konfiguriert Pin als Input-Pin mit Pull-up Widerstand | ||
| + | pin_setup_input_with_pullup(input_pin); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Wert eines Input-Pins erhalten | ||
| + | value = pin_get_value(input_pin); | ||
| + | |||
| + | // Wert für den Output-Pin setzen | ||
| + | pin_set_to(output_pin, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Analog-Digital-Wandler==== | ||
| + | |||
| + | Diese Bibliothek enthält Funktionen um den AVR Analog-Digital-Wandler zu nutzen. Sämtliche Funktionen dieser Bibliothek sind blockierend, | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void adc_init(adc_reference reference, adc_prescale prescale)// | ||
| + | Initialisiert ADC. Parameter: | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | Konvertiert bestimmte analoge ADC Kanalwerte in digitale. Die Funktion blockiert. Parameter: | ||
| + | * //channel// - ADC Kanalnummer (0 bis 7). | ||
| + | * Liefert einen digitalen 10-bit Wert. | ||
| + | |||
| + | * **// | ||
| + | Konvertiert eine gewünschte Anzahl analoger Werte eines bestimmten ADC Kanals zur digitalen Werten und berechnet den Mittelwert. Die Funktion blockiert. | ||
| + | * //channel// - ADC Kanalnummer (0 bis 7). | ||
| + | * // | ||
| + | * Liefert einen digitalen 10-bit Wert. | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Der ADC sei initialisiert und zwei analoge Kanalwerte zu digitalen konvertiert. Der Wert von Kanal 0 wird der Variable //x// zugewiesen und der durchschnittliche Wert von Kanal 1 der Variable //y//. | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | unsigned short x, y; | ||
| + | |||
| + | // Initialisierung ADC. Vergleichsspannung von AVCC. | ||
| + | // Takt ist 8 mal langsamer als der Systemtakt. | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Konvertierung des Wertes von Kanal 0. | ||
| + | x = adc_get_value(0); | ||
| + | |||
| + | // Konvertieren des Wertes von Kanal 1 und Errechnung des Durchschnitts. | ||
| + | y = adc_get_average_value(1, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Serielles Interface ==== | ||
| + | |||
| + | Diese Bibliothek bietet die Funktionen für das AVR asynchrone serielle Interface | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **// | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **// | ||
| + | Makrofunktion um den USART Baudratenregisterwert im asynchronen Modus zu berechnen. Parameter: | ||
| + | * //baud// - Gewünschte Baudrate | ||
| + | * Gibt Baudratenregisterwert wieder. | ||
| + | |||
| + | * **//void usart_init_async(usart port, usart_databits data_bits, usart_stopbits stop_bits, usart_parity parity, usart_baudrate baudrate)// | ||
| + | Initialisiert asynchrones USART. Parameter: | ||
| + | * //port// - USART Schnittstellenvariable. | ||
| + | * // | ||
| + | * // | ||
| + | * //parity// - Paritätsmodus. | ||
| + | * // | ||
| + | |||
| + | * **//void usart_send_char(usart port, char symbol)//** \\ | ||
| + | Blockiert die Übertragung von Zeichen. Die Funktionen warten solange bis der Ausgabespeicher leer ist, bevor ein Zeichen in den Speicher geschrieben wird. Parameter: | ||
| + | * //port// - USART Schnittstellenvariable. | ||
| + | * //symbol// - zu sendendes Zeichen. | ||
| + | |||
| + | * **//void usart_send_string(usart port, char *text)//** \\ | ||
| + | Blockierende String-Übertragung. Parameter: | ||
| + | * //port// - USART Schnittstellenvariable. | ||
| + | * //text// - Zeiger auf einen String(char array). Der String muss mit einer Null enden. | ||
| + | |||
| + | * **//bool usart_has_data(usart port)//** \\ | ||
| + | Überprüft Empfangsspeicher auf Daten. Parameter: | ||
| + | * //port// - USART Schnittstellenvariable. | ||
| + | * Gibt //true// zurück wenn Zeichen im Empfangsspeicher und //false// wenn nicht. | ||
| + | |||
| + | * **//char usart_read_char(usart port)//** \\ | ||
| + | Liest ein Zeichen aus dem Empfangsspeicher. Zuvor muss der Nuter überprüfen ob tatsächlich ein Zeichen empfangen wurde. Parameter: | ||
| + | * //port// - USART Schnittstellenvariable. | ||
| + | * Gibt Zeichen aus. | ||
| + | |||
| + | * **//bool usart_try_read_char(usart port, char *symbol)// | ||
| + | Liest ein Zeichen aus dem Empfangsspeicher, | ||
| + | * //port// - USART Interfacevariable. | ||
| + | * //symbol// - Verweis auf die Variable des Zeichens. Wenn ein Zeichen im Empfangsspeicher vorhanden ist, wird es der betreffenden Variable zugeschrieben. | ||
| + | * Gibt //true// aus, wenn ein Zeichen im Empfangsspeicher vorhanden ist und //false// wenn nicht. | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Die USART Schnittstelle ist konfiguriert um 8 Datenbits, ein Stop-Bit, 9600 bps Baudrate und keinen Paritätsmodus zu nutzen. Das Programm sendet einen String, wartet bis die Zeichen empfangen wurden und ließt sie dann aus. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | // Nutze USART Schnittstelle 0. | ||
| + | usart port = USART(0); | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | char c; | ||
| + | |||
| + | // Initialisierung der Schnittstelle. | ||
| + | usart_init_async(port, | ||
| + | USART_DATABITS_8, | ||
| + | USART_STOPBITS_ONE, | ||
| + | USART_PARITY_NONE, | ||
| + | USART_BAUDRATE_ASYNC(9600)); | ||
| + | |||
| + | // Senden des String. | ||
| + | usart_send_string(port, | ||
| + | |||
| + | // Auf ankommende Daten warten. | ||
| + | while (!usart_has_data(port)) {} | ||
| + | |||
| + | // Empfangenes Zeichen auslesen. | ||
| + | c = usart_read_char(port); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Timer ==== | ||
| + | |||
| + | Diese Bibliothek deckt einen großen Teil der Funktionen des Timers des ATmega128 ab. Es gibt Datentypen und Funktionen welche das Benutzen von Timern vereinfachen. Aufgrund der Komplexität der AVR Timer gibt es leider keine allgemeingültige Funktion, die für verschiedene Timer genutzt werden kann. Die Funktionen jedes Timers beginnen mit dem Präfix " | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void timer0_init_normal(timer0_prescale prescale)// | ||
| + | Initialisiert Timer 0 im normalen Modus. In diesem Modus zählt der Timer von 0 bis 255 (inkl.). Overflowinterrupts können genutzt werden. Parameter. | ||
| + | * // | ||
| + | |||
| + | * **//void timer2_init_normal(timer2_prescale prescale)// | ||
| + | Initialisiert Timer 2 im normalen Modus. In diesem Modus zählt der Timer von 0 bis 255 (inkl.). Overflowinterrupts können genutzt werden. Parameter. | ||
| + | * // | ||
| + | |||
| + | * **//void timer0_stop()// | ||
| + | * **//void timer2_stop()// | ||
| + | Stoppt Timer 0/2. | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | Returns timer 0/2 current value. Parameters: | ||
| + | * Return 8-bit timer value. | ||
| + | |||
| + | * **//void timer0_set_value(unsigned char value)//** | ||
| + | * **//void timer2_set_value(unsigned char value)//** \\ | ||
| + | Sets timer 0/2 value. Parameters: | ||
| + | * //value// - New 8-bit timer value. | ||
| + | |||
| + | * **//void timer0_overflow_interrupt_enable(bool enable)//** | ||
| + | * **//void timer2_overflow_interrupt_enable(bool enable)//** \\ | ||
| + | Enables or disables timer 0/2 overflow interrupt. The name of the interrupt vector is " | ||
| + | * //enable// - //true// to enable interrupt, //false// to disable. | ||
| + | |||
| + | * **//bool timer0_overflow_flag_is_set(void)// | ||
| + | * **//bool timer2_overflow_flag_is_set(void)// | ||
| + | Checks timer 0/2 overflow flag. Parameters: | ||
| + | * Returns //true// when overflow has happened, //false// when not. | ||
| + | |||
| + | * **//void timer0_overflow_flag_clear(void)// | ||
| + | * **//void timer2_overflow_flag_clear(void)// | ||
| + | Resets timer 0/2 overflow flag. | ||
| + | |||
| + | * **//void timer1_init_normal(timer1_prescale prescale)// | ||
| + | * **//void timer3_init_normal(timer3_prescale prescale)// | ||
| + | Initializes timer 1/3 in normal mode. In this mode timer counts from 0 to 65535 (including). Overflow interrupt can be used. Parameters: | ||
| + | * // | ||
| + | |||
| + | * **//void timer1_init_ctc(timer1_prescale prescale, timer1_ctc_top top)//** | ||
| + | * **//void timer3_init_ctc(timer3_prescale prescale, timer3_ctc_top top)//** \\ | ||
| + | Initializes timer 1/3 in CTC (//Clear Timer on Compare Match//) mode. In this mode timer counts to specified top value. Overflow interrupt can be used. Parameters: | ||
| + | * // | ||
| + | * //top// - Timer top value selection. Actual value must be specified with register selected as a top value holder. | ||
| + | |||
| + | * **//void timer1_init_fast_pwm(timer1_prescale prescale, timer1_fast_pwm_top top, timer1_fast_pwm_output_mode output_a, timer1_fast_pwm_output_mode output_b, timer1_fast_pwm_output_mode output_c)// | ||
| + | * **//void timer3_init_fast_pwm(timer3_prescale prescale, timer3_fast_pwm_top top, timer3_fast_pwm_output_mode output_a, timer3_fast_pwm_output_mode output_b, timer3_fast_pwm_output_mode output_c)// | ||
| + | Initializises timer 1/3 in fast PWM mode. In this mode timer counts to a specified value, which also determines the period of the PWM signal. Timer 1/3 has three 3 output compare units (A, B and C) to generate PWM signals. Overflow and compare match interrupts can be used. Parameters: | ||
| + | * // | ||
| + | * //top// - Timer top value selection. Actual value must be specified with register selected as a top value holder. | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | * **//void timer1_stop()// | ||
| + | * **//void timer3_stop()// | ||
| + | Stops timer 1/3. | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | Returns timer 1/3 current value. Parameters: | ||
| + | * Returns 16-bit timer value. | ||
| + | |||
| + | * **//void timer1_set_value(unsigned char value)//** | ||
| + | * **//void timer3_set_value(unsigned char value)//** \\ | ||
| + | Sets timer 0/2 value. Parameters: | ||
| + | * //value// - New 16-bit timer value. | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | * **// | ||
| + | * **// | ||
| + | * **// | ||
| + | * **// | ||
| + | | ||
| + | * Returns 16-bit compare match register value. | ||
| + | |||
| + | * **//void timer1_set_compare_match_unitA_value(unsigned short value)//** | ||
| + | * **//void timer1_set_compare_match_unitB_value(unsigned short value)//** | ||
| + | * **//void timer1_set_compare_match_unitC_value(unsigned short value)//** | ||
| + | * **//void timer3_set_compare_match_unitA_value(unsigned short value)//** | ||
| + | * **//void timer3_set_compare_match_unitB_value(unsigned short value)//** | ||
| + | * **//void timer3_set_compare_match_unitC_value(unsigned short value)//** \\ | ||
| + | Sets timer 1/3 output compare unit A/B/C compare match register value. Parameters: | ||
| + | * //value// - New 16-bit compare match register value. | ||
| + | |||
| + | * **// | ||
| + | * **// | ||
| + | Returns timer 1/3 input capture register value. Parameters: | ||
| + | * Returns 16-bit input capture register value. | ||
| + | |||
| + | * **//void timer1_set_input_capture_value(unsigned short value)//** | ||
| + | * **//void timer3_set_input_capture_value(unsigned short value)//** \\ | ||
| + | Sets timer 1/3 input capture register value. Parameters: | ||
| + | * //value// - New 16-bit input capture register value. | ||
| + | |||
| + | * **//void timer1_overflow_interrupt_enable(bool enable)//** | ||
| + | * **//void timer3_overflow_interrupt_enable(bool enable)//** \\ | ||
| + | Enables or disables timer 1/3 overflow interrupt. The name of the interrupt vector is " | ||
| + | * //enable// - //true// to enable interrupt, //false// to disable. | ||
| + | |||
| + | * **//void timer1_compare_match_unitA_interrupt_enable(bool enable)//** | ||
| + | * **//void timer1_compare_match_unitB_interrupt_enable(bool enable)//** | ||
| + | * **//void timer1_compare_match_unitC_interrupt_enable(bool enable)//** | ||
| + | * **//void timer3_compare_match_unitA_interrupt_enable(bool enable)//** | ||
| + | * **//void timer3_compare_match_unitB_interrupt_enable(bool enable)//** | ||
| + | * **//void timer3_compare_match_unitC_interrupt_enable(bool enable)//** \\ | ||
| + | | ||
| + | * //enable// - //true// to enable interrupt, //false// to disable. | ||
| + | |||
| + | * **//void timer1_input_capture_interrupt_enable(bool enable)//** | ||
| + | * **//void timer3_input_capture_interrupt_enable(bool enable)//** \\ | ||
| + | Enables or disables timer 1/3 input capture interrupt. The name of the interrupt vector is " | ||
| + | * //enable// - //true// to enable interrupt, //false// to disable. | ||
| + | |||
| + | * **//bool timer1_overflow_flag_is_set(void)// | ||
| + | * **//bool timer3_overflow_flag_is_set(void)// | ||
| + | Checks timer 1/3 overflow flag. Parameters: | ||
| + | * Returns //true// when overflow has happened, //false// when not. | ||
| + | |||
| + | * **//bool timer1_input_capture_flag_is_set(void)// | ||
| + | * **//bool timer3_input_capture_flag_is_set(void)// | ||
| + | Checks timer 1/3 input capture flag. Parameters: | ||
| + | * Returns //true// when input capture has done, //false// when not. | ||
| + | |||
| + | * **//void timer1_overflow_flag_clear(void)// | ||
| + | * **//void timer3_overflow_flag_clear(void)// | ||
| + | Resets timer 1/3 overflow flag. | ||
| + | |||
| + | * **//void timer1_input_capture_flag_clear(void)// | ||
| + | * **//void timer3_input_capture_flag_clear(void)// | ||
| + | Resets timer 1/3 input capture flag. | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Im folgenden Programm wird Timer 0 im normalen Modus mit Overflowinterrupt gestartet. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // Overflow interrupt program. | ||
| + | ISR(TIMER0_OVF_vect) | ||
| + | { | ||
| + | } | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Initializing of timer 0 in normal mode. | ||
| + | timer0_init_normal(TIMER0_PRESCALE_32); | ||
| + | |||
| + | // Enabling timer 0 overflow interrupt. | ||
| + | timer0_overflow_interrupt_enable(true); | ||
| + | |||
| + | // Global interrupts enabling. | ||
| + | sei(); | ||
| + | } | ||
| + | </ | ||
| + | ==== Verzögerung ==== | ||
| + | |||
| + | Dieser Teil der Bibliothek enthält die benötigten Funktionen, um in einem Programm mit Hilfe von Software Algorithmen oder Hardwaretimern Verzögerungen zu generieren. Verzögerungen blocken keine Interrupts, daher werden Softwareverzögerungen durch Interrupts unterbrochen. Verzögerungsfunktionen sind nicht vor-kompiliert, | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void sw_delay_ms(unsigned short count)//** \\ | ||
| + | Softwareverzögerung in Millisekunden (ms). Für diese Funktion wird ein Compiler Optimierungsmodus benötigt. Parameter: | ||
| + | * //count// - Verzögerungszeit in ms. 0 bis 65535 ms. | ||
| + | |||
| + | * **//void sw_delay_us(unsigned short count)//** \\ | ||
| + | Softwareverzögerung in Mikrosekunden (μs). Für diese Funktion wird ein Compiler Optimierungsmodus benötigt. Parameter: | ||
| + | * //count// - Verzögerungszeit in μs. 0 bis 65535 μs. | ||
| + | |||
| + | * **//void hw_delay_ms(unsigned short count)//** \\' | ||
| + | Zeitgeber basierte Verzögerung in Millisekunden. Diese Funktionen verwenden den ATmega128 8-bit Timer 0. In Abhängigkeit von der Taktfrequenz kann eine Verzögerung von bis zu einigen Millisekunden auftreten. Parameter: | ||
| + | * //count// - Verzögerungszeit in ms. 0 bis 65535 ms. | ||
| + | |||
| + | === Beispiele === | ||
| + | |||
| + | Demonstration beider Typen einer Verzögerung: | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Software-basierte Verzögerung von 100 ms. | ||
| + | sw_delay_ms(100); | ||
| + | |||
| + | // Hardware- (Timer-) basierte Verzögerung von 100 ms. | ||
| + | hw_delay_ms(100); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | --- | ||
| + | | ||
| + | ==== 7-Segment LED Display ==== | ||
| + | |||
| + | //In Bezug auf: [HW] [[en: | ||
| + | |||
| + | Diese Bibliothek dient zur Nutzung des 7-Segment LED Displays der digitalen HomeLab digitalen I/O Modulplatine gedacht. Mit dieser Bibliothek können Zahlen von 0 bis 9 dargestellt werden. | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void segment_display_init(void)// | ||
| + | Konfiguriert Kontrollpins für den Displaytreiber. | ||
| + | |||
| + | * **//void segment_display_write(unsigned char digit)//** \\ | ||
| + | Zeigt eine Ziffer auf dem Display an. Parameter: | ||
| + | * //digit// - Zahlenwert von 0 bis 9. Ansonsten wird ein E für " | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Die Zahl 5 wird auf dem LED-Display angezeigt. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Initialisierung des Displays | ||
| + | segment_display_init(); | ||
| + | |||
| + | // Anzeige der Zahl. | ||
| + | segment_display_write(5); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Alphanumerisches LCD ==== | ||
| + | |||
| + | //Bezug nehmend auf: [HW] [[en: | ||
| + | |||
| + | Diese Bibliothek enthält die Funktionen, um das alphanumerische LCD des HomeLab zu nutzen. | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **// | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | * // | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void lcd_alpha_init(lcd_alpha_mode disp_attr)// | ||
| + | Initialisiert LCD. Parameter: | ||
| + | * // | ||
| + | |||
| + | * **//void lcd_alpha_clear(void)// | ||
| + | Löscht die Anzeige. Cursor wird zum Anfang der ersten Zeile bewegt. | ||
| + | |||
| + | * **//void lcd_alpha_clear_line(unsigned char line)//** \\ | ||
| + | Löscht eine Zeile am Display. Cursor wird zum Anfang der ersten Zeile bewegt. Parameter: | ||
| + | * //line// - Zeilennummer: | ||
| + | |||
| + | * **//void lcd_alpha_home(void)// | ||
| + | Cursor wird zum Anfang der ersten Zeile bewegt. | ||
| + | |||
| + | * **//void lcd_alpha_goto_xy(unsigned char x, unsigned char y)//** \\ | ||
| + | Bewegt den Cursor zur gewünschten Position. Parameter: | ||
| + | * //x// - X Koordinate (Spaltennumner). 0 bis 15. | ||
| + | * //y// - Y Koordinate (Zeilennumner). 0 bis 1. | ||
| + | |||
| + | * **//void lcd_alpha_write_char(char c)//** \\ | ||
| + | Schreibt ein Zeichen auf die Position des Cursors. Parameter: | ||
| + | * //c// - ASCII Zeichen. | ||
| + | |||
| + | * **//void lcd_alpha_write_string(const char *s)//** \\ | ||
| + | Schreibt einen String aufs Display, beginnend bei der Cursorposition. Parameter: | ||
| + | * //s// - Zeiger auf einen String(char array). | ||
| + | |||
| + | * **//void lcd_alpha_write_string_p(const char *progmem_s)// | ||
| + | Schreibt einen String vom Programmspeicher aufs Displays, beginnt an der Cursorposition. | ||
| + | Parameter: | ||
| + | * // | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Nutzung des alphanumerischen LCD zur Darstellung von Text: | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Initialisierung des LCD. | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Löschen des Displays. | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Cursor an den Beginn der zweiten Zeile setzen. | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | |||
| + | // Anzeige des Texts. | ||
| + | lcd_alpha_write_string(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Graphisches LCD ==== | ||
| + | |||
| + | //Related to: [HW] [[en: | ||
| + | |||
| + | Diese Bibliothek enthält die Funktionen zur Nutzung des graphischen LCD des HomeLab. Obwohl das LCD graphische Bilder wiedergeben kann, enthält die Bibliothek diese Funktionen nicht. Das LCD wird als alphanumerisches Display mit 14 x 6 Zeichen genutzt. | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void lcd_gfx_init(void)// | ||
| + | Intialisiert das LCD. | ||
| + | |||
| + | * **//void lcd_gfx_backlight(bool set)//** \\ | ||
| + | Schaltet die Hintergrundbeleuchtung des LCD an/aus. Parameter: | ||
| + | * //set// - //true// wenn Hintergrundbeleuchtung an, //false// wenn aus. | ||
| + | |||
| + | * **//void lcd_gfx_clear(void)// | ||
| + | Löscht das gesamte Display | ||
| + | |||
| + | * **//void lcd_gfx_clear_line(unsigned char line)//** \\ | ||
| + | Löscht eine Zeile Text. Parameter: | ||
| + | * //line// - Zeilennummer. 0 bis 5. | ||
| + | |||
| + | * **//void lcd_gfx_goto_char_xy(unsigned char x, unsigned char y)//** \\ | ||
| + | Wählt eine Position zum Beschreiben aus. Parameter: | ||
| + | * //x// - X-Koordinate. 0 bis 13. | ||
| + | * //y// - Y-Koordinate. 0 bis 5. | ||
| + | |||
| + | * **//void lcd_gfx_write_char(char c)//** \\ | ||
| + | Schreibt ein Zeichen an eine zuvor bestimmte Position. Parameter: | ||
| + | * //c// - ASCII Zeichen. | ||
| + | |||
| + | * **//void lcd_gfx_write_string(char *s)//** \\ | ||
| + | Schreibt einen String an eine zuvor bestimmte Position. Parameter: | ||
| + | * //s// - Zeiger auf einen String(char array). | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Nutzung des graphischen LCD: | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Initialisierung des LCD. | ||
| + | lcd_gfx_init(); | ||
| + | |||
| + | // Löschen des Displays. | ||
| + | lcd_gfx_clear(); | ||
| + | |||
| + | // Cursor in die Mitte des Bildschirms bewegen. | ||
| + | lcd_gfx_goto_char_xy(5, | ||
| + | |||
| + | // Anzeige eines Textes. | ||
| + | lcd_gfx_write_string(" | ||
| + | } | ||
| + | </ | ||
| + | ==== Motoren ==== | ||
| + | |||
| + | //Bezug nehmend auf: [HW] [[en: | ||
| + | |||
| + | Diese Bibliothek enthält Funktionen zur Steuerung der verschiedenen HomeLab Motoren. Sie enthält Funktionen für Gleichstrom- (DC-), Schritt- und Servomotoren, | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//void dcmotor_init(unsigned char index)//** \\ | ||
| + | Initialisiert einen der Controller für die DC Motoren. Parameter: | ||
| + | * //index// - Index des Motorencontrollers. 0 bis 3. | ||
| + | |||
| + | * **//void dcmotor_drive(unsigned char index, signed char direction)// | ||
| + | Betriebt einen der Controller der DC Motoren. Parameter: | ||
| + | * //index// - Index des Motorencontrollers. 0 bis 3. | ||
| + | * // | ||
| + | |||
| + | * **//void unipolar_init(unsigned char index)//** \\ | ||
| + | Initialisiert den Controller eines der unipolaren Schrittmotoren. Parameter: | ||
| + | * //index// - Index des Motorencontrollers. 0 oder 1. | ||
| + | |||
| + | * **//void unipolar_halfstep(unsigned char index, signed char direction, unsigned short num_steps, unsigned char speed)//** \\ | ||
| + | Befehl zum Halbschrittbetrieb für unipolaren Schrittmotor. Die Funktion ist blockierend bis sie erfüllt ist, bis alle Schritte durchgeführt wurden. Parameter. | ||
| + | * //index// - Index des Motorencontrollers. 0 oder 1. | ||
| + | * // | ||
| + | * // | ||
| + | * //speed// - Zeit eines einzelnen Schritts in Millisekunden. | ||
| + | |||
| + | * **//void bipolar_init(void)// | ||
| + | Initialisiert den Controller des bipolaren Schrittmotors. | ||
| + | | ||
| + | * **//void bipolar_halfstep(signed char direction, unsigned short num_steps, unsigned char speed)//** \\ | ||
| + | Befehl zum Halbschrittbetrieb für bipolaren Schrittmotor. Die Funktion ist blockierend bis sie erfüllt ist, bis alle Schritte durchgeführt wurden. Parameter: | ||
| + | * // | ||
| + | * // | ||
| + | * //speed// - Zeit eines einzelnen Schritts in Millisekunden. | ||
| + | |||
| + | * **//void servomotor_init(unsigned char index)//** \\ | ||
| + | Initialisiert eine der PWM Signal-generierenden Einheiten eines Servomotors des ATmega128 Timers 1. Das PWM Signal beträgt 50 hz bei einer high period of 1.5 ms ± 0.5 ms. Parameter: | ||
| + | * //index// - Index des Servomotors. 0 oder 1. | ||
| + | |||
| + | * **//void servomotor_position(unsigned char index, signed short position)// | ||
| + | Takt des Servomotors mit Kontrollbefehl. Die Position eines Servomotors verändert sich wenn dieser betrieben wird. Wird er gedreht, verändert sich seine Drehzahl. Parameter: | ||
| + | * //index// - Index des Servomotors. 0 oder 1. | ||
| + | * // | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Nutzung von Gleichstrom- (DC-), Schritt- und Servomotoren. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | // Initialisierung der DC Motoren. | ||
| + | dcmotor_init(0); | ||
| + | dcmotor_init(1); | ||
| + | |||
| + | // Initialisierung des bipolaren Schrittmotors. | ||
| + | bipolar_init(); | ||
| + | |||
| + | // Initialisierung der Servomotoren. | ||
| + | servomotor_init(0); | ||
| + | servomotor_init(1); | ||
| + | |||
| + | // Ein DC Motor fährt vorwärts, ein anderer rückwärts. | ||
| + | dcmotor_drive(0, | ||
| + | dcmotor_drive(1, | ||
| + | |||
| + | // Bewegt den Schrittmotor 100 Schritte in eine Richtung | ||
| + | // und daraufhin zurück mit doppelter Geschwindigkeit. | ||
| + | bipolar_halfstep(1, | ||
| + | bipolar_halfstep(-1, | ||
| + | |||
| + | // Bewegt Servomotoren in entgegengesetzte Richtungen. | ||
| + | servomotor_position(0, | ||
| + | servomotor_position(1, | ||
| + | } | ||
| + | </ | ||
| + | ==== Sensoren ==== | ||
| + | |||
| + | //Bezug nehmend auf: [HW] [[en: | ||
| + | |||
| + | Diese Bibliothek enthält Funktionen für die verschiedenen Sensoren im HomeLab kit. | ||
| + | |||
| + | === Datentypen === | ||
| + | |||
| + | * **// | ||
| + | Infrarotentfernungssensor, | ||
| + | * //a// - Dividend. | ||
| + | * //b// - Nicht-lineare Konstante. | ||
| + | * //k// - Lineare Konstante. | ||
| + | |||
| + | === Konstante === | ||
| + | |||
| + | * **// | ||
| + | Sharp GP2Y0A21YK Formelparameter zur Entfernungsberechnung. | ||
| + | |||
| + | === Funktionen === | ||
| + | |||
| + | * **//signed short thermistor_calculate_celsius(unsigned short adc_value)// | ||
| + | Berechnet die Thermistor Temperatur in Grad Celcius aus ADC Umrechnungsergebnissen. Die Funktionen benutzen eine vorgefertigte Umrechnungstabelle. Parameter: | ||
| + | * // | ||
| + | * Gibt die Temperatur mit Grenzwerten von -20 bis 100 °C an. | ||
| + | |||
| + | * **//signed short ir_distance_calculate_cm(ir_distance_sensor sensor, unsigned short adc_value)// | ||
| + | Berechnet die Entfernung von ADC Ergebnissen die vom IR-Entfernungssensor empfangene Spannung an. Parameter: | ||
| + | * //sensor// - Kalkulationsparameter des Distanzsensors. | ||
| + | * // | ||
| + | * Gibt die Entfernung in cm an, oder -1 wenn eine Messung nicht möglich ist. | ||
| + | |||
| + | * **// | ||
| + | Misst die Entfernung mit dem Ultraschallentfernungsmesser. Die Funktionen generieren einen Auslöseimpuls an einem Pin und messen die Zeit bis zum Echopulses am anderen Pin. Die Entfernung wird über die Zeit berechnet. Die Funktionen benötigen eine 14.7456Mhz Taktfrequenz. Die Messung kann bis zu 36ms dauern. Parameter: | ||
| + | * //trigger// - Variable des auslösenden Pins. | ||
| + | * //echo// - Variable des Echo-Pin variable. | ||
| + | * Gibt Entfernung in cm an, oder 0 wenn Messung nicht möglich. | ||
| + | |||
| + | === Beispiel === | ||
| + | |||
| + | Nutzung des Infrarot- und Ultraschallentfernungssensors. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | // Kontroll-Pins des Ultraschallentfernungssensors. | ||
| + | pin pin_trigger = PIN(G, 1); | ||
| + | pin pin_echo | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | unsigned short adc_value = 400; // zufälliges ADC Ergebnis. | ||
| + | signed short distance; | ||
| + | |||
| + | // Entfernungsberechnung des ADC Ergebnisses des IR-Entfernungssensors. | ||
| + | distance = ir_distance_calculate_cm(GP2Y0A21YK, | ||
| + | |||
| + | // Messung mit Ultraschallentfernungssensor. | ||
| + | distance = ultrasonic_measure(pin_trigger, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ====== Praktische Beispiele ====== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Die, in diesem Kapitel vorgestellten, | ||
| + | |||
| + | Das erste Kapitel weicht etwas von diesem Schema ab, hier wird primär die Installation und Konfiguration der notwendigen Softwarekomponenten beschrieben. Die Installationsanweisungen sind für Windows und Linux Betriebssysteme ausgelegt. Nachdem die Software einmal eingerichtet wurde, macht es keinen Unterschied mehr, ob ein Windows oder ein Linux/Unix basierendes Betriebssystem verwendet. Die Handhabung und Programierung wird dadurch nicht beeinflusst. | ||
| + | |||
| + | Ein praktisches Beispiel beginnt immer mit einer Aufzählung von erforderlichen Vorkenntnissen. Dabei werden Bezüge zu anderen Kapiteln hergestellt, | ||
| + | |||
| + | * [HW] Physikalisches Modul, das im Beispiel genutzt wird. | ||
| + | * [LIB] Teil der Softwarebibliothek, | ||
| + | * [ELC] Verweis auf das Kapitel über die Grundlagen der Elektronik. | ||
| + | * [AVR] Verweis auf das Kapitel über die AVR Mikrocontrollermodule. | ||
| + | * [PRT] Verweis auf andere Aufgaben. | ||
| + | |||
| + | **Grundlegende Software für die Beispiele** | ||
| + | |||
| + | Wie zuvor erwähnt werden die Codebeispiele auf Basis der HomeLab Bibliothek erstellt. | ||
| + | Die meisten AVR-spezifischen Operationen und Verfahren, die auf die HomeLab Kit Hardware | ||
| + | |||
| + | **Programmierstil in den Beispielen** | ||
| + | |||
| + | Die Beispielprogramme sind in einem einheitlichen Stil geschrieben, | ||
| + | |||
| + | |||
| + | * Das Programm, all seine Funktionen und Variablen sind in englischer Sprache und Kleinbuchstaben geschrieben, | ||
| + | * Die Funktionen werden wie folgt gekennzeichnet: | ||
| + | * Wichtigere Teile des Programms werden kommentiert. | ||
| + | * Jeder Block in C-Code (markiert durch { und } )startet und beginnt in einer neuen Zeile. | ||
| + | * Blöcke werden mit der Tabulatortaste geordnet. Die Tabulatortaste wird nicht innerhalb einer Zeile verwendet. | ||
| + | ===== Anfang ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Zur Programmierung des AVR Mikrocontrollers werden eine Programmierumgebung, | ||
| + | |||
| + | Sämtliche, zur Durchführung der Beispiele notwendige Software, ist auf der HomeLab-Homepage zu finden. | ||
| + | |||
| + | |||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ===== Digitale Input/ | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Die folgenden Kapitel stellen den digtalen Input/ | ||
| + | |||
| + | Fast alle typischen Mikrocontroller Pins erlauben die Ausführung einfacher Input-Output Funktionen, auch wenn diese Pins häufig noch alternative Funktionen haben. Zunächst sollen jedoch erst die Pins mit ihren Grundfunktionen dargestellt werden, bevor in separaten Kapiteln auf die alternativen Funktionen eingegangen wird. | ||
| + | ==== Light-emitting Diode (LED) ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Leuchtdioden sind Halbleiter die Licht abstrahlen, wenn Strom in Durchlassrichtung durch die Diode fließt. Die Abkürzung LED steht für " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Wenn Strom in Durchlassrichtung durch die LED fließt, ist die Anode mit der positiven und die Kathode mit der negativen Spannung verbunden. Die Spannung der LED hängt von der Farbe der LED ab: lange Wellenlängen (rot) ~2V, kürzere Wellenlängen (blau) ~3V. Die Stromverbrauch einer LED ist in der Regel nicht mehr als ein paar Dutzend mW. Die Stromstärke darf daher nicht zu hoch sein, wenn größere Stromstärken oder Spannungen verwendet werden kann die LED zerstört werden. | ||
| + | |||
| + | Wenn die LEDs nur zur Beleuchtung verwendet werden, sollte man spezielle elektrische Schaltkreise verwenden, welche die Spannung und die Stromstärke für die LEDs regulieren. | ||
| + | Jedoch werden LEDs sehr oft als Indikatoren genutzt und direkt vom Mikrocontroller mit Strom versorgt. Da die Betriebsspannung eines Mikrocontrollers höher ist, als die der LEDs, muss ein Widerstand in Serie mit der LED geschaltet werden um die Stromstärke zu regulieren und für den nötigen Spannungsabfall zu sorgen. Das Kapitel " | ||
| + | |||
| + | LEDs werden in vielen Formen gefertigt. Die meisten LEDs haben runde eine Hülle mit 3mm oder 5mm Durchmesser und zwei lange metallische Pins. Der längere Pin ist die Anode, der kürzere die Kathode. " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | === HomeLab Übung 1 === | ||
| + | |||
| + | Das HomeLab Controller Controllermodul hat eine rote LED, dessen Anode über einen Widerstand an die +5V Stromversorgung angeschlossen ist und dessen Kathode am ATmega128 Pin PB7. | ||
| + | Um die LED an- und auszuschalten muss PB7 als Output Pin definiert werden und entweder high oder low gesetzt werden. Wenn der Pin high gesetzt wird ist die LED aus, wird er low gesetzt ist die LED an. Grundsätzlich ist es möglich die LED so anzubringen, | ||
| + | dann leuchtet die LED wenn der Pin high gesetzt ist und der LED ist aus wenn der Pin low ist. | ||
| + | |||
| + | Alle praktischen Beispiele für das HomeLab kit, inklusive LEDs schalten, nutzen die HomeLab Pin Bibliothek. Die Pin Bibliothek hat den Datentyp //pin//, welcher die Addressen des zum Pin gehörigen Register und der Bitmaske des Pins enthält. Wenn eine Pin Variable mit der Makrofunktion Pin im Programm erschaffen und initialisiert wird, kann der Pin mit dieser Variable im gesamten Programm genutzt werden, ohne Register benutzen zu müssen. | ||
| + | Hier sind 2 Beispielprogramme, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // HomeLab Controllermodule LED Testprogramm. | ||
| + | // Der Cose basiert auf der HomeLab Bibliothek. | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // LED Pin Konfiguration. | ||
| + | // | ||
| + | pin debug_led = PIN(B, 7); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // konfiguriert LED Pin als Output | ||
| + | pin_setup_output(debug_led); | ||
| + | |||
| + | // Aufleuchten der LED | ||
| + | pin_clear(debug_led); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // HomeLab Controllermodul LED Testprogramm. | ||
| + | // Der Code greift direkt auf Register zu. | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Konfiguriert LED Pin als Output | ||
| + | DDRB |= (1 << 7); | ||
| + | |||
| + | // Aufleuchten der LED | ||
| + | PORTB &= ~(1 << 7); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das erste Beispiel nutzt die Pin Bibliothek (//pin.h// Datei). Zuerst wird eine Pin-Typ Variable //debug led// erschaffen, welche Informationen über den LED Pin enthält. | ||
| + | Im Hauptprogramm wird dieser Pin mit // | ||
| + | Danach wird der Pin low gesetzt: // | ||
| + | Im zweiten Beispiel werden keine Variablen genutzt. Um die LED als Output zu markieren und zum Leuchten zu bringen, werden die Datenrichtung des Port B und die Output Registerwerte verändert. Der Leser, der mehr über den AVR weiß bemerkt, dass in beiden Beispielen kein Befehl nötig ist um die LED zum leuchten zu bringen, da der Standardoutputwert des AVR 0 ist. Aus Gründen der Vollständigkeit wird es jedoch hier beschrieben. | ||
| + | |||
| + | Was ist der Unterschied zwischen dem Gebrauch von Bibliothek und Register? Der Unterschied liegt im Komfort - Die Bibliothek ist einfacher, weil man die Registernamen und deren Auswirkungen nicht kennen muss. Der entscheidende Vorteil der Bibliothek ist jedoch die Anpassungsfähigkeit. | ||
| + | Arbeitet man mit Registern müssen im Programm stets die Registernamen und Bitmasken geändert werden um einen Pin zu ändern. Nutzt man die Bibliothek muss dieses nur am Anfang, bei Initialisierung der Variable erfolgen. Die Nutzung von Registern hat jedoch einen entscheidenden Vorteil: Die Nutzung eines Pins erfolgt direkt und nicht über den Programmspeicher und zeitfressenden Funktionen. Jedoch sind die neuren AVR-GCC Kompiler Versionen so schlau, dass sie die Bibliotheksfunktionen zu direkten Befehle für die Registermanipulation transformieren, | ||
| + | |||
| + | Der folgende Programmcode ist ein Teil der Pin Operations Bibliothek, um die Vorgehensweise mit Pin Variblen zu erklären. Es wird für Anfänger nicht einfach sein zu verstehen, da C-Sprache Pointer genutzt werden, die nicht in diesem Buch beschrieben sind. Es gibt jedoch sehr viel Material über Pointer in Büchern und natürlich im Internet. | ||
| + | |||
| + | <code c> | ||
| + | // Makrokonstante um Register-Pointer zu definieren | ||
| + | #define _REG_PTR_ volatile uint8_t * | ||
| + | |||
| + | // | ||
| + | // Pin Datentyp | ||
| + | // | ||
| + | typedef struct pin | ||
| + | { | ||
| + | _REG_PTR_ ddr; | ||
| + | _REG_PTR_ port; | ||
| + | _REG_PTR_ pin; | ||
| + | uint8_t mask; | ||
| + | } | ||
| + | pin; | ||
| + | |||
| + | // | ||
| + | // Makrofunktion für Initialisierung der Pin Variable | ||
| + | // | ||
| + | #define PIN(port_char, | ||
| + | { \ | ||
| + | (_REG_PTR_)& | ||
| + | (_REG_PTR_)& | ||
| + | (_REG_PTR_)& | ||
| + | bit_mask(bit_index) \ | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Konfiguriere Pin als Output | ||
| + | // | ||
| + | inline void pin_setup_output(pin pin) | ||
| + | { | ||
| + | bitmask_set(*pin.ddr, | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Setze Pin high | ||
| + | // | ||
| + | inline void pin_set(pin pin) | ||
| + | { | ||
| + | bitmask_set(*pin.port, | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Setze Pin low | ||
| + | // | ||
| + | inline void pin_clear(pin pin) | ||
| + | { | ||
| + | bitmask_clear(*pin.port, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === HomeLab Übung 2 === | ||
| + | |||
| + | Zusätzlich zum Controllermodul befinden sich LEDs auch auf der digtalen I/O Modulplatine. | ||
| + | Sie sind elektrisch genau so angeschlossen wie auf dem Controllerboard, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // HomeLab Digitales i/o Modul LED Testprogramm. | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // LED Pin Konfiguration. | ||
| + | // | ||
| + | pin led_red | ||
| + | pin led_yellow = PIN(C, 4); | ||
| + | pin led_green | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Konfiguriere LED Pins als Output | ||
| + | pin_setup_output(led_red); | ||
| + | pin_setup_output(led_yellow); | ||
| + | pin_setup_output(led_green); | ||
| + | |||
| + | // Aufleuchten der grünen LED | ||
| + | pin_clear(led_green); | ||
| + | |||
| + | // Ausschalten der roten und gelben LED | ||
| + | pin_set(led_red); | ||
| + | pin_set(led_yellow); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ~~Diskussion~~ | ||
| + | --- | ||
| + | | ||
| + | ==== Schalter ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Ein Schalter ist ein elektromagnetisches Gerät, welches einen elektrischen Schaltkreis verbindet oder trennt. Es gibt viele Typen von Schaltern, die am weitesten verbreiteten sind einfache mechanische Schalter, bei denen elektrische Anschlüsse mechanisch geschaltet werden. | ||
| + | Sind die Anschlüsse verbunden, wird der elektrische Schaltkreis geschlossen und Strom kann durch den Schalter fließen. Wenn die Anschlüsse nicht verbunden sind, kann keine Elektrizität fließen. | ||
| + | |||
| + | Schalter werden normalerweise benutzt um elektrische Schaltkreise zu schalten, sie können jedoch auch als Sensoren benutzt werden. Der Schalter als Sensor ist auch Teil dieser Übung, | ||
| + | |||
| + | Es werden unterschiedliche Schaltbildsymbole genutzt um die verschiedenen Typen von Schaltern zu identifizieren. Unterhalb sind Beispiele typischer elektrischer Schalter in einem Schaltbild: | ||
| + | |||
| + | ^ Druckknopfschalter ^ Wechselschalter ^ Kippschalter ^ Mikroschalter ^ DIL Schalter ^ | ||
| + | |{{: | ||
| + | | {{: | ||
| + | |||
| + | Um einen Schalter als Sensor mit einem Mikrocontroller zu nutzen, muss ein Kontakt des Schalters mit dem Pin des Mikrocontrollers verbunden sein und dieser muss als Input im Programm definiert werden. Wenn der Kontakt mit der Masse oder einem Inputpotential verbunden ist, wir die Bus Bitrate des Mikrocontroller-Pins geändert. Es erscheint logisch einen Wechselschalter zu nutzen, welcher es erlaubt einen Kontakt an den gewünschten Kontakt anzubringen (hier Masse oder Input). Für unseren Zweck ist es nicht ganz so einfach, denn im Moment des Schaltens sind die Kontakte nicht verbunden. Der Moment an sich ist sehr kurz (ms), aber in diesem Moment ist der Input-Pin des Mikrocontrollers nicht verbunden und hat daher einen unendlichen Wert. | ||
| + | Auf Grund elektromagnetischer Störung (welche überall existiert) kann der Input-Pin der nicht angeschlossen ist, zu jeder Zeit zufällig einen Wert von 0 oder 1 haben. | ||
| + | |||
| + | |||
| + | Die Störanfälligkeit macht die Nutzung von Schaltern kompliziert. Die am häufigsten verwendete Methode um dies zu verhindern, ist den Input des Microcontrollers durch einen Widerstand an die Erde oder das Inputpotential anzuschließen. Einen so benutzten Widerstand nennt man einen pull-down oder pull-up Widerstand. Normalerweise liegt der Widerstand eines pull-down oder pull-up zwischen 1kΩ bis 1 MΩ. Wenn der Schalter offen ist, wird der Input mit der Spannung des Widerstands geladen, wenn man den Schalter schließt, empfängt der Input die Spannung des Schalters, da der Leitungswiderstand des Schalters im Vergleich zum Widerstand beinahe 0 ist. Allgemein kann er als " | ||
| + | |||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | Ein einfacher zwei-Kontakt Schalter kann als Sensor mit einen pull-up oder pull-down Widerstand genutzt werden. Hierzu wird ein Kontakt des Schalters mit dem Input verbunden und der andere mit dem Widerstand. Normalerweise haben Mikrocontroller eingebaute pull-up oder down Widerstände, | ||
| + | AVR Mikrocontroller haben beispielsweise 20 kΩ – 50 kΩ pull-up Widerstände an ihren I/O Pins. | ||
| + | Darüber hinaus muss noch erwähnt werden, dass mechanische Schalter ein weiteres Problem haben, den " | ||
| + | | ||
| + | |||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Es gibt drei Druckknopf-Schalter am digitalen I/O Modul. Diese verbinden die Pins den Mikrocontrollers mit der Erde, aber nicht direkt durch einen Widerstand. Auf diese Weise soll ein Kurzschluss vermieden werden, wenn der Knopf gedrückt wird, während der Pin als Output definiert wird. Die Schalter besitzen einen pull-up Widerstand, welcher aber einen viel größeren Widerstand als die Schutzwiderstände hat, daher liegt beim Drücken des Schalter eine Spannung von nahezu 0 V am betreffenden Pin an. | ||
| + | |||
| + | Die Schalter befinden sich an den PC0, PC1 und PC2 Pins. Um den Status der Schalter zu lesen müssen die betreffenden Pins des Mikrocontrollers als Input gesetzt werden. Man benötigt nicht die internen pull-up Widerstände des AVR, da die Pins schon externe Widerstände haben. | ||
| + | Wenn der Schalter betätigt wird, hat der entsprechende Bus des Pins den Wert 0, wird er losgelassen, | ||
| + | |||
| + | Der Beispielcode zur Benutzung der Schalter basiert auf der HomeLab Pins Bibliothek, welche im LED Kapitel eingeführt wurde. | ||
| + | |||
| + | | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Program zum Testen der Schalter des digitalen I/O Moduls | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung der Pins von LED-d sowie der Schalter. | ||
| + | // | ||
| + | pin leds[3] | ||
| + | pin buttons[3] = { PIN(C, 2), PIN(C, 1), PIN(C, 0) }; | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned char i; | ||
| + | |||
| + | // Setzt die LED Pins als Output und die Schalter-Pins als Input. | ||
| + | for (i = 0; i < 3; i++) | ||
| + | { | ||
| + | pin_setup_output(leds[i]); | ||
| + | pin_setup_input(buttons[i]); | ||
| + | } | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Jeder Schalter hat eine zugehörige LED, | ||
| + | // die aufleuchtet, | ||
| + | for (i = 0; i < 3; i++) | ||
| + | { | ||
| + | pin_set_to(leds[i], | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Im Beispiel werden LEDS und Knöpfe als Array definiert - das ermöglicht es Sie in einer //for// Schleife zu nutzen. Wird das Programm gestartet, werden die LED Pins als Output und die Schalter als Input gesetzt. In der Endlosschleife des Programms wird durchgehend der Status der Schalter abgefragt, welcher den Status der dazugehörigen LED bestimmt. Der erste Schalter ist für die grüne LED, der Zweite für die Gelbe und der Dritte für die Rote. | ||
| + | ==== Vermeidung von Kontaktprellung | ||
| + | |||
| + | //Vajalikud teadmised: [HW] [[en: | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Wie bereits im einleitenden Kapitel zu Schaltern erwähnt, gibt es im Ungang mit mechanischen Schaltern den Effekt des Prellens (ungewolltes, | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die bekannteste Methode zur Vermeidung von Kontaktprellung ist die Filtrierung. Dieses kann elektrisch oder durch Software erfolgen. Um elektrisch zu filtern muss der Schalter an einen Tiefpassfilter angeschlossen werden - zum Beispiel an einen RC Filter - welcher die Spannungschwankungen beseitigt sodass der Pin des Mikrocontrollers keine schwankenden Werte erhält. Ein solcher RC Filter ist auf der Zeichnung abgebildet. Filtrierung mittels Software wird durchgeführt, | ||
| + | |||
| + | |||
| + | === Praktisches Beispiel === | ||
| + | |||
| + | Elektrische Filtrierung wird für die HomeLab Schalter nicht verwendet, da hier die Beseitigung von Fehlschaltungen mit Hilfe von Software geübt werden soll. Die Übung besteht aus zwei Teilen. Das Ziel des ersten Teils ist, das Prellen der Schalter des digitalen Input/ | ||
| + | <code c> | ||
| + | // | ||
| + | // Das Programm um Kontaktprellung am digitalen Input/ | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung der LED-Pins und Schalter. | ||
| + | // | ||
| + | pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; | ||
| + | pin button | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned char new_value, old_value = 0; | ||
| + | unsigned char index, counter = 0; | ||
| + | |||
| + | // LED-Pins als Output setzen. | ||
| + | for (index = 0; index < 3; index++) | ||
| + | { | ||
| + | pin_setup_output(leds[index]); | ||
| + | } | ||
| + | |||
| + | // Schalter-Pins als Input setzen. | ||
| + | pin_setup_input(button); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Status des Schalters auslesen. | ||
| + | new_value = pin_get_value(button); | ||
| + | |||
| + | // Kontolle, ob der Schalter heruntergedrückt wurde, | ||
| + | // was bedeutet, dass der neue Status 1 ist, der alte 0. | ||
| + | if ((new_value) && (!old_value)) | ||
| + | { | ||
| + | // Erweiterung des Lesegerätes und Nutzungvon Modul 3 | ||
| + | counter = (counter + 1) % 3; | ||
| + | |||
| + | // Aufleuchten der LED, welche mit dem Wert des Lesegerätes übereinstimmt. | ||
| + | for (index = 0; index < 3; index++) | ||
| + | { | ||
| + | pin_set_to(leds[index], | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Berücksichtigung des alten Status. | ||
| + | old_value = new_value; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Es gibt diverse Softwarelösungen zur Filtrierung. Sie können einfach oder komplex sein, wobei jede ihre Vor- und Nachteile hat. Sieht das Programm nur wenige seltene Betätigungen des Schalters vor, kann eine lange Pause als Folge der Betätigung eingefügt werden. Auf diese Weise können durch Kontaktprellung verursachte Wirkungen auf die Schaltung vermieden werden. Jedoch muss bei Anwendung dieser Lösung bedacht werden, dass, sofern der Nutzer den Schalter für eine längere Zeit gedrückt hält, das Programm ebenfalls auf die Fehlschaltung, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Funktion zum Auslesen filtrierter Werte aus dem I/O Erweiterungsmodul. | ||
| + | // | ||
| + | unsigned char pin_get_debounced_value(pin button) | ||
| + | { | ||
| + | unsigned char buffer = 0xAA; | ||
| + | unsigned char timeout = 100; | ||
| + | |||
| + | // Abwarten, bis der Status des Schalters We wait until the status of the button is celar or clearing the state expires | ||
| + | while (timeout-- > 0) | ||
| + | { | ||
| + | // Having 8 place (bit) bufffer of state. | ||
| + | // All previous states (bits) are shifted to left | ||
| + | // and a new state(bit) is added to the right. | ||
| + | buffer <<= 1; | ||
| + | buffer |= (pin_get_value(button) ? 0x01 : 0x00); | ||
| + | |||
| + | // If all 8 bits are high, then the button is definitely pressed down | ||
| + | if (buffer == 0xFF) | ||
| + | { | ||
| + | return 1; | ||
| + | } | ||
| + | |||
| + | // If all 8 bits are low, then the button is definitely up. | ||
| + | if (buffer == 0x00) | ||
| + | { | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | // 1 ms break. | ||
| + | // This function can be found from the library of the HomeLab. | ||
| + | sw_delay_ms(1); | ||
| + | } | ||
| + | |||
| + | // If we can not examine the state, then we assume that the button was not pressed. | ||
| + | return 0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Diese Funktion generiert eine Verzögerung durch Nutzung einer Funktion, die in der entsprechenden Übung erläutert wurde. Zu dieser Zeit müssen wir nur wissen, dass die Verzögerungsfunktion eine Verzögerung von 1 ms am Ende jedes Zyklus generiert, um den Status des Schalters lesen zu können. Befindet sich der Schalter 8 Lesezyklen lang in der gleichen Position, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // The program for filtering the debounce of buttons of Digital i/o module. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Determining pins of LEDs and buttons. | ||
| + | // | ||
| + | pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; | ||
| + | pin button | ||
| + | |||
| + | // | ||
| + | // Main program | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned char new_value, old_value = 0; | ||
| + | unsigned char index, counter = 0; | ||
| + | |||
| + | // Setting the pins of LEDs as outputs. | ||
| + | for (index = 0; index < 3; index++) | ||
| + | { | ||
| + | pin_setup_output(leds[index]); | ||
| + | } | ||
| + | |||
| + | // Setting the pins of button as input. | ||
| + | pin_setup_input(button); | ||
| + | |||
| + | // Endless loop. | ||
| + | while (true) | ||
| + | { | ||
| + | // Reading the state of the button. | ||
| + | new_value = pin_get_debounced_value(button); | ||
| + | |||
| + | // Control whether the button was pressed down, that means, | ||
| + | // is the new state 1 and the old state 0. | ||
| + | if ((!new_value) && (old_value)) | ||
| + | { | ||
| + | // Widening the counter and taking module number 3. | ||
| + | counter = (counter + 1) % 3; | ||
| + | |||
| + | // Lighting the LED witch corresponds to the value of the counter. | ||
| + | for (index = 0; index < 3; index++) | ||
| + | { | ||
| + | pin_set_to(leds[index], | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Remember the old state. | ||
| + | old_value = new_value; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Testen wir das Programm nun, leuchten die LEDs in genau der Sequenz auf, in welcher der Nutzer den Schalter betätigt. | ||
| + | === Aufgaben: Digitale I/O === | ||
| + | |||
| + | Ziel ist es, ein Programm zu schreiben, welches die unten beschriebenen Aufgaben ausführt. | ||
| + | |||
| + | === Aufwärm-Übung === | ||
| + | |||
| + | * Durch Drücken von S1 leuchtet eine LED auf, drückt man S2 leuchten zwei und bei S3 drei LEDs. | ||
| + | |||
| + | === Für Anfänger === | ||
| + | |||
| + | - Es wird eine von Hand betriebene Ampel an einer Fußgängerkreuzung simuliert. Solange kein Schalter gedrückt wird, leuchtet eine grüne LED für die Autos. Nach Betätigung eines zufälligen Schalters beginnt die grüne LED für drei Sekunden zu blinken, daraufhin leuchtet die gelbe LED für 3 Sekunden und die rote für 10 Sekunden. Nach dieser Sequenz leuchtet erneut die grüne LED. | ||
| + | - Es soll gezählt werden, wie oft ein Schalter betätigt wurde. Nur durch ein vollständiges Lösen des Schalters wird das Herunterdrücken vollendet. Das Ergebnis wird als Binärcode auf den LEDs angezeigt. Das maximale Ergebnis bei drei LEDs ist 7 (23-1). Die grüne markiert das erste, die gelbe das zweite und die rote das dritte Bit. | ||
| + | - Durch Drücken von Schalter 1 leuchten LED 1 und LED 3. Drückt man S2 leuchtet die gelbe LED, Schalter 3 sorgt dafür, dass keine LED leuchtet. Diese Operation muss unter direkter Verwendung von Registerwerten (also ohne Nutzung der HomeLab Bibliothek) durchgeführt werden. | ||
| + | - Es soll gezählt werden, wie oft ein Schalter gedrückt wurde. Das Ergebnis wird durch Blinken der LEDs dargestellt. Nach jeder Betätigung des Schalters wird die Anzahl der blinkenden LEDs um eins erhöht. Der Schalter kann zufällig ausgewählt werden. Damit die LED blinkt muss eine Unterfunktion genutzt werden, deren Parameter die blinkenden LEDs zählt. | ||
| + | - Wird S1 betätigt, sendet die rote LED durch Blinken " | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Zu jedem der drei Schalter gehört eine LED, welche aufleuchtet wenn der Schalter betätigt wird. Zum an- oder ausschalten sollen Register und nur eine zuordnende Operation genutzt werden (Hinweis: Nutzen Sie Bitverschiebungen). | ||
| + | - Für jede LED gibt es einen Schalter. Der Controller bringt die LEDs in zufälliger Reihenfolge zum Blinken und der Nutzer muss diese Sequenz wiederholen. Die Blinksequenz verlängert sich, nach jeder Runde kommt eine LED hinzu. Bei einem falschen Eintrag blinken alle LEDs dreimal (Die Anzahl korrekter Einträge des Nutzers muss auf einem LCD-Display angezeigt werden). | ||
| + | - Das Programm misst die Zeit für eine Reaktion. Eine zufällige LED leuchtet auf und der Nutzer muss den zugehörigen Schalter so schnell wie möglich betätigen. Die Zeit bis zum Aufleuchten der LED ist zufällig, aber nicht kleiner als 100 ms. Das Ergebnis wird auf einem LCD-Display in Millisekunden dargestellt. Der Wert der Schalter kann nicht mit einer Filterfunktion für das Flackern gelesen werden, da diese eine weitere Verzögerung verursacht. | ||
| + | |||
| + | === Fragen === | ||
| + | |||
| + | - Was ist der Unterschied zwischen den Operationen ”=” und ”==”? Nennen Sie zwei Beispiele um Ihre Antwort zu verifizieren. | ||
| + | - Was ist der Unterschied zwischen den Operationen “|” und “||”? Nennen Sie zwei Beispiele um Ihre Antwort zu verifizieren. | ||
| + | - Schreiben Sie einen Ausdruck, welcher die Gleichung “x = x + 1” zwölfmal verwendet. | ||
| + | - Wie wird eine Endlosschleife in C geschrieben? | ||
| + | - Welcher Variablentyp wird in C verwendet um positive Werte zwischen 7 und 154 dazustellen? | ||
| + | - Welches Register legt die Richtung eines Anschlusses fest? Nennen Sie ein Beispiel zur Konfiguration von Input und Output eines Anschlusses. | ||
| + | - Welche Methoden gibt es um das Zurückspringen von Kontakten zu sowie der durch Flimmern hervorgerufenen falschen Verbindungen zu verhindern? Geben Sie Lösungsbeispiele unter der Nutzung von Hard- und Software. | ||
| + | - Was versteht man unter einer Bitverschiebung? | ||
| + | - Warum werden pull-up Widerstände in Schalter verwendet? Wie ist deren Widerstand festgelegt? | ||
| + | - Errechnen Sie den Widerstand für die regulierende LED Stromstärke, | ||
| + | |||
| + | ===== Timer und Verzögerungen ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Dieses Kapitel beschreibt die Möglichkeit, | ||
| + | |||
| + | Beide Methoden haben ihre Vor- und Nachteile, welche in den entsprechenden Übungen besprochen werden. Anfangs waren Timer separate Schaltkreise, | ||
| + | |||
| + | Timer haben sich von einfachen Zeitzählgeräten zu komplexen System entwickelt, welche Signale empfangen und generieren. Sie modulieren und demodulieren Signale und ermöglichen, | ||
| + | |||
| + | ==== Softwareverzögerungen ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Oft ist es wichtig in einem Programm eines Mikrocontrollers Verzögerungen einzubauen, einige Aktionen zu terminieren, | ||
| + | Eine Zahl von Null bis zum Wert der Taktfrequenz des Prozessors in Hz, sollte theoretisch eine Verzögerung von einer Sekunde erzeugen. Aus verschiedenen Gründen ist dieses jedoch praktisch nicht ganz so einfach. | ||
| + | |||
| + | Wenn der Prozessor des Microcontrollers mit Nummern rechnet, deren Binärform so groß ist wie der innere Bus (AVR hat 8 Bits), dann braucht es einen Taktzyklus des Prozessors um eine arithmetische Operation, wie z.B. 1 zu einem Wert zu addieren, durchzuführen. Soll mit tausenden oder millionen gerechnet werden, muss die Nummer 16 oder 32 Bit groß sein und ein 8-Bit Prozessor benötigt zur Berechnung mehr als eine Taktfrequenz. Daher sollte man sich mit der Arbeitsweise und insbesondere den Befehlen des Prozessors auskennen, wenn man mit großen Werten arbeitet. | ||
| + | |||
| + | Wenn man in fortgeschrittenen Sprachen programmiert (z.B. C), werden die Programme nicht auf Basis des Befehls geschrieben, | ||
| + | |||
| + | === Beispiel ==== | ||
| + | |||
| + | Das folgende Beispiel generiert eine Softwareverzögerung im AVR Mikrocontroller. Ein Teil des in C geschriebenen Programms zählt eine Variable x in vier Zyklen von 0 bis 100. | ||
| + | In jedem Zyklus wird ein leerer " | ||
| + | |||
| + | <code c> | ||
| + | unsigned char x; | ||
| + | |||
| + | // Zyklus bis x ist 100 | ||
| + | for (x = 0; x < 100; x++) | ||
| + | { | ||
| + | // Mit " | ||
| + | asm volatile (" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Dies ist der gleiche Teil des Programms nach dem Kompilieren. Die beiden Hexadezimalzahlen links geben den Maschinencode an, und rechts befindet sich der Befehl mit den Operanden in Assembler. | ||
| + | Der Maschinencode und die Assemblersprache sind konform; Assembler dient nur dazu, den Maschinencode für Menschen lesbar zu machen. Kompiliert wurde mit der Optimierungsmethode für die Länge des Programms (Parameter -Os). | ||
| + | |||
| + | <code asm> | ||
| + | 80 e0 | ||
| + | 00 00 | ||
| + | 8f 5f subi r24, 0xFF ; subtrahieren von 255 aus dem r24 Index, was bedeutet +1 addieren | ||
| + | 84 36 | ||
| + | e1 f7 brne .-8 ; Falls der Vergleich nicht übereinstimmt, | ||
| + | </ | ||
| + | |||
| + | In der kompilierten Form erkennt man, was mit dem Zyklus der C-Sprache passiert und man kann berechnen wie viele Taktfrequenzen benötigt werden, um den Zyklus einer Periode zu beenden. Die Information über die Wirkung der Befehle und ihre Laufzeit findet man im AVR Datenblatt. Im vorliegenden Beispiel, braucht es 4 Taktzyklen um 4 Befehle in einer Periode auszuführen, | ||
| + | Wenn man nun den Arbeitstakt von 14,7456 MHz annimmt, kann man die vom Programm verursachte Verzögerung berechnen. | ||
| + | |||
| + | (1 + 100 ⋅ 4 + 1) / 14745600 = 27,26 μs | ||
| + | |||
| + | Die Verzögerung in diesem Beispiel ist in Mikrosekunden angegeben und die Variable nutzt 8-Bit, daher ist der Maschinencode recht einfach. Um eine Pause in Millisekunden zu verursachen, | ||
| + | |||
| + | Das Ziel dieser Übung ist es nicht präzise Softwareverzögerungen in Maschinencode zu erstellen, da diese eine sehr präzise Arbeit ist und die Funktionen zur Erzeugung von Verzögerungen bereits in der avr-libc und der Bibliothek von HomeLab hinterlegt sind. Diese werden auch in den folgenden Beispielen genutzt. | ||
| + | |||
| + | Bei der Arbeit mit Softwareverzögerungen arbeitet, ist es wichtig zu wissen, dass diese trotz ihrer Einfachheit, | ||
| + | Während jedes Taktes in dem der Mikrocontroller unnötig Zahlen zählt, wird Energie verbraucht. Wenn also batteriebetriebene Anwendungen genutzt werden, ist es nicht sinnvoll lange Softwareverzögerungen zu schreiben. Für diesen Fall sollte man lieber Hardwaretimer nutzen, welche unabhängig arbeiten und den Prozessor aus dem Ruhezustand holen wenn es an der Zeit ist die Arbeit fortzuführen. | ||
| + | |||
| + | === Übung ==== | ||
| + | |||
| + | Der folgende Programmcode beinhaltet die Softwareverzögerunsfunktion // | ||
| + | // | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Softwareverzögerung in Millisekunden. | ||
| + | // | ||
| + | void sw_delay_ms(unsigned short count) | ||
| + | { | ||
| + | // Zählen der Variable der Verzögerung auf 0 | ||
| + | while (count-- > 0) | ||
| + | { | ||
| + | // 1ms Verzögerung mit spezieller Funktion. | ||
| + | _delay_ms(1); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das folgende Programm dient dazu, die gegebene Funktion zu nutzen, es erzeugt zwei Verzögerungen in der Endlosschleife: | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Das Vorführprogramm des HomeLab für Softwareverzögerungen. | ||
| + | // Es lässt eine LED für ~1 Sekunde aufleuchten. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung des Pins zum Testen der LED | ||
| + | // | ||
| + | pin debug_led = PIN(B, 7); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Setzt LED Pin als Output. | ||
| + | pin_setup_output(debug_led); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Aufleuchten der LED | ||
| + | pin_clear(debug_led); | ||
| + | |||
| + | // Softwareverzögerung für 100 ms | ||
| + | sw_delay_ms(100); | ||
| + | |||
| + | // Ausschalten der LED | ||
| + | pin_set(debug_led); | ||
| + | |||
| + | // Softwareverzögerung für 900 ms. | ||
| + | sw_delay_ms(900); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Auch wenn es so aussieht, als blinke die LED jede Sekunde, dauert es tatsächlich etwas länger, da das ansprechen der LED und die Verzögerungsfunktionen ein paar Taktfrequenzen des Mikrocontrollers benötigen. | ||
| + | ==== Hardwareverzögerung ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Neben der Softwareverzögerung gibt es auch Timer, um Unterbrechungen zu erzeugen. Timer sind Hardwarekomponenten, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | AVR Taktgeber können so eingestellt werden, dass sie bei Überlauf des Timers oder bei Vergleichstreffern informieren. Ein Überlauf tritt auf, wenn der Timer seinen maximalen Wert erreicht hat und der Zyklus wieder bei 0 anfängt. Nach Erreichen eines vorgegebenen Wertes beginnt der Timer bei jedem Anstieg seines Wertes diesen mit einem vom Benutzer vorgegebenen Wert zu vergleichen. Daraufhin werden die Bits des AVR-Statusindexes automatisch high gesetzt. | ||
| + | |||
| + | Um eine Verzögerung mit einem Timer zu generieren, muss man nur den Timer setzen und darauf warten, dass das Statusbit high wird. Im Unterschied zur Softwareverzögerung ist die Arbeit des Timers nicht vom Compiler abhängig, wodurch er zuverlässiger ist. Gleichzeitig ist die Diversität (bzw. Komplexität) der Einstellungen des AVR Timers hoch. Je nach Taktsignal des Mikrocontrollers kann es sein, dass es nicht exakt mit der gewünschten Verzögerungsperiode dividiert und die Verzögerung so ungenau wird. | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Der Programmcode unterhalb stellt eine vereinfachte Timer-basierte Verzögerungsfunktion dar. Das Zählen funktioniert genauso wie bei einer Softwareverzögerungsfunktion. Es wird eine gewünschte Verzögerung von 1 ms mit dem Timer 0 eines 8-Bit ATmega128 erzeugt. Die zuvor errechnete Taktfrequenz liegt bei 14,7456 MHz und das Timersignal muss mindestens 64 Mal dividiert werden, so dass der Timer seinen Überlauf nicht in einer Millisekunde erreicht. | ||
| + | Der Wert den der Timer haben muss, so dass der Überlauf nach 1 ms stattfindet wird mit durch die Variable // | ||
| + | Leider entsteht hier eine gewisse Ungenauigkeit, | ||
| + | |||
| + | In dem Zyklus wird der Timer initialisiert und die Überlauf-Flagge genullt (in dem eine 1 hineingeschrieben wird). Dann wird abgewartet bis der Timer vom Startwert bis 256 gezählt hat, also zum Überlauf. In dem Moment wird die Flagge hoch gesetzt und eine Verzögerung von einer 1 ms hat stattgefunden. Am Ende der Funktion wird der Timer gestoppt. | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Hardwareverzögerung in Millisekunden. | ||
| + | // | ||
| + | void hw_delay_ms(unsigned short count) | ||
| + | { | ||
| + | // Berechnung des Startwertes des Timers. | ||
| + | register unsigned char timer_start = 256 - F_CPU / 1000 / 64; | ||
| + | |||
| + | // Start des Timers. | ||
| + | timer0_init_normal(TIMER0_PRESCALE_64); | ||
| + | |||
| + | // Zählen der Verzögerungsvariable auf 0. | ||
| + | while (count-- > 0) | ||
| + | { | ||
| + | // Initialisierung des Timers. | ||
| + | timer0_set_value(timer_start); | ||
| + | |||
| + | // Überlauf-Flagge auf Null setzen. | ||
| + | timer0_overflow_flag_clear(); | ||
| + | |||
| + | // Warten auf den Überlauf. | ||
| + | while (!timer0_overflow_flag_is_set()) | ||
| + | { | ||
| + | asm volatile (" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Überlauf-Flagge auf Null setzen. | ||
| + | timer0_overflow_flag_clear(); | ||
| + | |||
| + | // Timer anhalten. | ||
| + | timer0_stop(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das folgende Programm ist ähnlich wie das für die Softwareverzögerung. In der kürzeren 100 ms langen halb-Periode wird die LED eingeschaltet und in der längeren 900 ms halb-Periode ausgeschaltet. Das Resultat: die LED blinkt jede Sekunde. Leider beträgt die Periode in diesem Beispiel ebenfalls nicht exakt eine Sekunde, da die Ausführung anderer Funktionen des Programms ebenfalls Zeit verbraucht. Für ein exaktes Timing, muss ein 16-Bit Timer mit Interrupts genutzt werden. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm für eine Hardwareverzögerung mit dem HomeLab. | ||
| + | // Das Programm lässt eine LED immer nach ~1 Sekunde blinken. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung des Pins der Test-LED. | ||
| + | // | ||
| + | pin debug_led = PIN(B, 7); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // LED Pin als Output setzen. | ||
| + | pin_setup_output(debug_led); | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Aufleuchten der LED. | ||
| + | pin_clear(debug_led); | ||
| + | |||
| + | // Hardwareverzögerung von 100 ms. | ||
| + | hw_delay_ms(100); | ||
| + | |||
| + | // Ausschalten der LED. | ||
| + | pin_set(debug_led); | ||
| + | |||
| + | // Hardwareverzögerung von 900 ms. | ||
| + | hw_delay_ms(900); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Periodische Interrupts ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Ziel dieses praktischen Beispiels ist es, die Verwendung von Interrupts an Beispiel von Timern darzustellen. Interrupts sind Programmteile welche auf Ereignisse, die in einem Mikrocontroller stattfinden, | ||
| + | Es ist beispielsweise möglich eine LED durch Interrupts blinken zu lassen, so dass die Blinkfrequenz nicht von einem Programm abhängig ist. | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das folgende Programm zeigt wie Timer eingestellt werden, um einen Interrupt auszulösen. | ||
| + | Das Programm nutzt zwei LEDs des digitalen I/O Moduls. Der Status der roten LED wird mit einer Softwareverzögerung periodisch geändert, der Status der grünen LED wird geändert wenn ein Interrupt auftritt. Es gibt ein separates Beispiel für blinkende LEDs durch Softwareverzögerung, | ||
| + | |||
| + | Zu Beginn des Programms wird der 16-Bit Timer 1 mit der Funktion // | ||
| + | Der Teiler des Timers ist 1024 und der Wert des ICR1 beträgt 14400. Bei einer Taktfrequenz von 14,7456MHz umfasst eine Periode somit genau eine Sekunde. Dieses kann mit folgender Formel berechnet werden: | ||
| + | |||
| + | f = 14745600 Hz / 1024 / 14400 = 1 | ||
| + | |||
| + | Nachdem zugelassen wurde, dass ein Interrupt den maximalen Wert von Counter 1 erreicht, muss ein Interrupt auch global, also im Mikrocontroller, | ||
| + | Ein Interrupt wird im Programm durch die Makrofunktion ISR definiert, deren Parameter der Name des Interruptvektors ist. Im folgenden Beispiel beträgt der Interruptvektor des maximal erreichbaren Wertes von Counter 1 // | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // HomeLab Beispiel für blinkende LED aufgrund von Counter-Interrupts. | ||
| + | // Zum Vergleich blinkender LEDs aufgrund von Interrupts, | ||
| + | // gibt es parallel eine durch Softwareverzögerung blinkende LED. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung der Pins der LEDs. | ||
| + | // | ||
| + | pin led_red | ||
| + | pin led_green = PIN(C, 3); | ||
| + | |||
| + | // | ||
| + | // Interrupt | ||
| + | // | ||
| + | ISR(TIMER1_CAPT_vect) | ||
| + | { | ||
| + | // Status der grünen LED ändern. | ||
| + | pin_toggle(led_green); | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // LED Pins als Output setzen. | ||
| + | pin_setup_output(led_red); | ||
| + | pin_setup_output(led_green); | ||
| + | |||
| + | // Timer in den CTC Modus setzen. | ||
| + | timer1_init_ctc( | ||
| + | TIMER1_PRESCALE_1024, | ||
| + | TIMER1_CTC_TOP_ICR); | ||
| + | |||
| + | // Maximaler Wert des Timers ist 14400, wodurch | ||
| + | // die Periode 1 s lang ist. | ||
| + | // Formel: 14,7456Mhz / 1024 = 14400 | ||
| + | timer1_set_input_capture_value(14400); | ||
| + | |||
| + | // Dem Interrupt erlauben, den Wert zu erreichen. | ||
| + | timer1_input_capture_interrupt_enable(true); | ||
| + | |||
| + | // Globalen Interrupt zulassen. | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Softwareverzögerung 1000 ms. | ||
| + | sw_delay_ms(1000); | ||
| + | |||
| + | // Status der roten LED ändern. | ||
| + | pin_toggle(led_red); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Zu Beginn des Programms sieht man, dass unabhängig davon was der Mikrocontroller gerade im Hauptprogramm macht, Interrupts stattfinden und die grüne LED blinkt. | ||
| + | |||
| + | Läuft das Programm ein paar Minuten wird ein entscheidender Aspekt deutlich, der im Rahmen der Softwareverzögerung nicht so einfach zu erkennen ist. Auch wenn die Verzögerung der blinkenden roten LED 1000 ms beträgt, ist die tatsächlich benötigte Zeit um einen Zyklus zu beenden länger. Das liegt daran, dass die Änderung vom LED-Status', | ||
| + | ==== Aufgaben ==== | ||
| + | |||
| + | Ziel ist es, ein Programm zu schreiben welches die unten genannten Aufgaben durchführt. | ||
| + | |||
| + | === Aufwärm-Übung === | ||
| + | |||
| + | * Lassen Sie die rote LED blinken. Die Periode soll 10 Sekunden (Halbperiode 5 Sekunden) betragen. Nutzen Sie eine Softwareverzögerungsfunktion, | ||
| + | |||
| + | === Für Anfänger === | ||
| + | |||
| + | - Zeigen Sie mit einer Genauigkeit von 100 ms auf dem LCD Display die Zeit zwischen der Betätigung von 2 beliebigen Schaltern an. Die Art der Zeitmessung können Sie frei bestimmen. | ||
| + | - Wird Schalter S1 betätigt, wird die Blinkgeschwindigkeit aller 3 LEDs zweimal reduziert. Durch Betätigung von S3, blinken die LEDs doppelt so schnell, und S2 setzt die Blinkfrequenz auf 1 Hz. Nutzen Sie Verzögerungsfunktionen oder Interrupts (die Interrupts sind schwieriger, | ||
| + | - zeige die Druckfrequenz von Schalter S1 auf dem 7 Segment LED-Display in Hz-s. Die Anzeige der Frequenz muss nach unten mit 0 und nach oben mit 9 begrenzt werden. | ||
| + | - Wird Schalter S1 gedrückt wird, zählt das Programm die Sekunden von 60 bis 0 herunter und schaltet dann die rote LED ein. Bei S2 beträgt die Zeit nur 30 s, anschließend wird die gelbe LED eingeschaltet. Die Zeit bei Betätigung von S3 beträgt 10 s, dann leuchtet die grüne LED. Alle Prozesse müssen gleichzeitig stattfinden. Die LEDs schalten sich aus, wenn der dazugehörige Schalter betätigt wird. | ||
| + | - Zeigen Sie die Zeit auf dem LCD wie folgt an: hh:mm:ss. Nutzen Sie den Hardwaretimer 1 mit Interrupts, die Zeit muss mit den Schaltern eingestellt werden können. Es sollten drei Schalter genutzt werden, S1 erhöht die Stunden, S2 die Minuten, und S3 die Sekunden. | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Entwickeln Sie eine Stoppuhr, die Stunden, Minuten, Sekunden, und Millisekunden auf dem LCD anzeigt. Schalter S1 startet die Zeit, S2 hält sie an, und S3 nullt die Uhr. Es müssen Interrupts des Timers genutzt werden. | ||
| + | - Die rote, gelbe und grüne LED müssen in 2-Sekunden Intervallen fließend nacheinander ein- und ausgeschaltet werden. Das fließende Licht wird erzeugt, in dem man die LED mit mehreren hundert Hertz moduliert (also sehr schnell ein- und ausschaltet) und die Abstände zwischen dem Ein- und Ausschalten verändert. Dadurch wird für das Auge der Effekt erzeugt, dass sich die Helligkeit der LED ändert (Pulsweitenmodulation). | ||
| + | - Erstellen Sie einen Programmteil in C, welcher eine Verzögerung von 10 µs ± 10% bei einer Taktfrequenz von 14,7456 MHz erzeugt. Verifizieren Sie theoretisch, | ||
| + | |||
| + | === Fragen === | ||
| + | |||
| + | - Welche Methoden zur Erstellung von Verzögerungen gibt es? | ||
| + | - Wie wird eine Softwareverzögerung erstellt? Von welchen Parametern hängt die Softwareverzögerung ab? | ||
| + | - Warum werden Hardwareverzögerungen/ | ||
| + | - Berechnen sie die die Überlauf-Interruptperiode für einen 8-Bit Timer, wenn Taktfrequenz 16M Hz und Frequenzteilerfaktor 1024 betragen. | ||
| + | - Was ist ein Echtzeitgeber in einem Computer? | ||
| + | - Was geschieht am 19.01.2038 in der Computerwelt? | ||
| + | - Wozu können AVR Timer noch genutzt werden, außer um Zeit zu zählen? | ||
| + | - Welche Indizes können genutzt werden um den ATmega128 Timer 0 einzustellen? | ||
| + | - Wie lang ist die längste Zeitspanne von Unterbrechungen in Millisekunden, | ||
| + | - Hat es einen Effekt auf die Genauigkeit von Timern, wenn der Prozessor mit der Ausführung eines Programms stark ausgelastet ist (z.B. mehrere Motoren und Werte verschiedener Sensoren gleichzeitig kontrollieren)? | ||
| + | ===== Anzeigen und Displays ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Einer der einfachsten Methoden um sicher zu gehen, dass ein Mikrocontroller funktioniert ist Code zu einem Programm hinzuzufügen, | ||
| + | |||
| + | Das folgende Kapitel befasst sich mit einfachen Displays und Bildschirmen. Anzeigen mit LED-Segmenten und zwei Typen von monochromen LCD´s. Zusätzlich zu diesen werden auch LED-Matrizen und organischen Farb-LED´s(OLED) mit Mikrocontrollern genutzt. Früher wurden Nixie-Röhren verwendet, welche separate Glühdrähte für jede Zahl hatten. Darüber hinaus gibt es elektromechanische Anzeigen, deren verschiedenfarbige Segmente physisch gedreht werden. Neuerdings erfreuen sich E-Paper-Displays, | ||
| + | |||
| + | |||
| + | ==== 7-Segment-LED-Anzeige ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Die 7-Segment-LED-Zifferanzeige ist ein Display, welches aus sieben, in Form einer Acht angeordneten, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Elektrisch werden alle Anoden der LEDs an einer Anode am Pin //ca// angeschlossen. Die LEDs leuchten durch Schalten ihrer Kathoden (//a, b, c ...//). Es gibt auch andere Verbindungen, | ||
| + | |||
| + | LED number-indicators are easy to use, they can be controlled directly from the pins of the microcontroller, | ||
| + | |||
| + | Die Benutzung von LED Zifferanzeigen ist recht einfach. Sie können direkt über die Pins des Mikrocontrollers kontrolliert werden. Es gibt jedoch auch spezielle Treiber, die dafür sorgen, dass für die Nutzung der Anzeige weniger Pins des Mikrocontrollers benötigt werden. Es gibt zwei verschiedene Farben von LED-Zifferanzeigen, | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Am digitalen I/O Modul befindet sich eine 7-Segment-LED-Zifferanzeige. Sie wird über einen Treiber mit der seriellen Schnittstelle A6275 kontrolliert. Die serielle Schnittstelle des Treibers ist dem SPI ähnlich, bei dem sowohl Taktsignal als auch Datensignale genutzt werden. Anders als beim SPI wird // | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | * Latch-Signal (//latch//) - PG2 | ||
| + | * Taktsignal (//clock//) - PC7 | ||
| + | * Datensignal (//data//) - PC6 | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | Die Daten werden in Form von Bits über den Datenpin gesendet. Immer, wenn das Taktsignal high wird, wird der Inhalt des Verschiebungsindexes nach rechts geschoben und das Bit vom Datenpin wird in die Zelle ganz links gelesen. So werden 8 Bits in den Verschiebungsindex geladen. Wenn das Latch-Signal high gesetzt wird, wird der Wert des Verschiebungsindexes in den Latch-Index geladen, und verbleibt dort bis zu einem erneuten Laden. Jedes Bit des Latch-Indexes ist durch eine Spannungsschaltung mit einem Segment der Zifferanzeige verbunden. Das Segment leuchtet während die Bitrate high ist. | ||
| + | |||
| + | Zur Darstellung von Ziffern auf der digitalen I/O Modulanzeige des HomeLab sind die folgenden Funktionen in der Bibliothek von HomeLab enthalten: | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Einrichtung der Pins | ||
| + | // | ||
| + | static pin segment_display_latch = PIN(G, 2); | ||
| + | static pin segment_display_data_out = PIN(C, 6); | ||
| + | static pin segment_display_clock = PIN(C, 7); | ||
| + | |||
| + | // | ||
| + | // Markierung der Karte. | ||
| + | // Die Bits markieren Segmente. Ein niedriger Rang wird mit A, ein hoher mit DP gekennzeichnet. | ||
| + | // | ||
| + | static const unsigned char segment_char_map[11] = | ||
| + | { | ||
| + | 0b00111111, | ||
| + | 0b00000110, | ||
| + | 0b01011011, | ||
| + | 0b01001111, | ||
| + | 0b01100110, | ||
| + | 0b01101101, | ||
| + | 0b01111100, | ||
| + | 0b00000111, | ||
| + | 0b01111111, | ||
| + | 0b01100111, | ||
| + | 0b01111001 | ||
| + | }; | ||
| + | |||
| + | // | ||
| + | // Start der 7-Segment-Anzeige. | ||
| + | // | ||
| + | void segment_display_init(void) | ||
| + | { | ||
| + | // Set latch, data out and clock pins as output | ||
| + | pin_setup_output(segment_display_latch); | ||
| + | pin_setup_output(segment_display_data_out); | ||
| + | pin_setup_output(segment_display_clock); | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Darstellung einer Ziffer auf der 7-Segment-Anzeige. | ||
| + | // | ||
| + | void segment_display_write(unsigned char digit) | ||
| + | { | ||
| + | unsigned char map; | ||
| + | signed char i; | ||
| + | |||
| + | // Überprüfung der Ziffer | ||
| + | if (digit > 9) | ||
| + | { | ||
| + | digit = 10; | ||
| + | } | ||
| + | |||
| + | // Ziffer wie Segmentkarte. | ||
| + | map = segment_char_map[digit]; | ||
| + | |||
| + | // Latch-Signal aus | ||
| + | pin_clear(segment_display_latch); | ||
| + | |||
| + | // Senden von he Bits. Höherrangige zuerst. | ||
| + | for (i = 7; i >= 0; i--) | ||
| + | { | ||
| + | // Pin entsprechend Bitwert der Karte setzen. | ||
| + | pin_set_to(segment_display_data_out, | ||
| + | |||
| + | // Taktsignal high setzen. | ||
| + | pin_set(segment_display_clock); | ||
| + | _delay_us(1); | ||
| + | |||
| + | // Taktsignal low setzen. | ||
| + | pin_clear(segment_display_clock); | ||
| + | _delay_us(1); | ||
| + | } | ||
| + | |||
| + | // Latch-Signal ein. | ||
| + | pin_set(segment_display_latch); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Um Ziffern und den Buchstaben " | ||
| + | |||
| + | Das nachfolgende Beispielprogramm beschreibt die Nutzung der Zifferanzeige. Die zuvor beschriebene Funktion der Bibliothek wird in dem Programm erläutert. Das Programm Zählt Ziffern von 0 bis 9 mit einem Intervall von etwa einer Sekunde. Dieses wird dadurch erreicht, dass ein Modul mit einer weitaus größeren Ziffer verwendet wird. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Das Beispielprogramm der 7-Segment-LED-Anzeige des I/O-Moduls des HomeLab | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | int counter = 0; | ||
| + | |||
| + | // Einrichtung der 7-Segment-Anzeige. | ||
| + | segment_display_init(); | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Anzeige der Werte des Timers. | ||
| + | segment_display_write(counter % 10); | ||
| + | |||
| + | // Lange zählen. | ||
| + | counter++; | ||
| + | |||
| + | // Verzögerung von 1 Sekunde. | ||
| + | sw_delay_ms(1000); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Alphanumerisches LCD ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Das alphanumerische LCD ist ein Flüssigkristall-Display, | ||
| + | Wenn der Flüssigkristall seine Polarisation durch das elektrische Feld ändert, erreicht das Licht den Bildschirm oder ein Segment des Bildschirms nicht und er bleibt schwarz. | ||
| + | |||
| + | Hauptmerkmal eines alphanumerischen LCD ist die Anordnung der Segmente. Der Bildschirm ist in verschiedene Anzeigen unterteilt. Jede Anzeige hat entweder genügend Segmente um Buchstaben oder Nummern anzuzeigen oder es wird eine Matrix aus Pixeln gebildet. Eine Matrix aus 5x7 Pixeln ist beispielsweise ausreichend, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Neben dem Bildschirm hat das alphanumerische LCD auch einen Controller, welcher die Segmente des Bildschirms gemäß den Befehlen der Kommunikationsschnittstelle steuert. Ein Controller verfügt über eine vorprogrammiertes Set von Buchstaben mit einem eigenen Index für jeden Buchstaben, jede Nummer sowie jedes Symbol. Die Darstellung des Textes auf dem Bildschirm | ||
| + | |||
| + | Alphanumerische LCDs besitzen normalerweise eine passive Matrix. Hier erfolgt die Erneuerung des elektrischen Feldes der Segmente turnusmäßig. Aus diesem Grund sind Bildschirme mit einer passiven Matrix langsamer und Darum sind die Bildschirme mit passiver Matrix langsamer und bieten weniger Kontrast, als Bildschrime mit aktiver Matrix. Bei Aktivmatrix-Bildschrimen wird die Ladung jedes einzelnen Segments durch einen eigenen Transistor gesteuert. Einige LCDs haben einen reflektierenden Hintergrund, | ||
| + | |||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Am digitalen I/O Modul des HomeLab ist ein alphanumerisches, | ||
| + | |||
| + | Vor der Nutzung des Displays ist es notwendig, seine Einstellungen anzupassen. Hierzu dient die // | ||
| + | |||
| + | Der folgende Programm-Code zeigt wie das alphanumerische LCD als Uhr genutzt werden kann. Die Zeit beginnt bei 00:00:00 und nimmt etwa jede Sekunde zu. Da das Zählen der Zeit mit Hilfe einer Verzögerungsfunktion geschieht, ist das Ergebnis nicht sehr genau. Diese Ungenauigkeit wird im Rahmen der Aufgabe zu periodischen Unterbrechungen erklärt. Das Programm zählt die Sekunden und konvertiert diese in Minuten und Sekunden. Um Uhrzeit darzustellen wird die Standard-Funktion in C genutzt: // | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispiel zur Nutzung des alphanumerischen LCD des HomeLab. | ||
| + | // Die Startzeit zu Beginn des Programms wird auf dem LCD angezeigt. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | int seconds = 0; | ||
| + | char text[16]; | ||
| + | |||
| + | // Einrichtung des LCD. | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Löschen des LCD. | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Name des Programms. | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Konvertieren der Sekunden in die Zeitanzeige: | ||
| + | // hh:mm:ss | ||
| + | sprintf(text, | ||
| + | (seconds / 3600) % 24, | ||
| + | (seconds / 60) % 60, | ||
| + | | ||
| + | |||
| + | // Anzeige der Zeit am Anfang der zweiten Reihe des LCD. | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | lcd_alpha_write_string(text); | ||
| + | | ||
| + | // Anstieg der Sekunden um 1. | ||
| + | seconds++; | ||
| + | | ||
| + | // Hardwareverzögerung 1000 ms. | ||
| + | hw_delay_ms(1000); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Graphisches LCD ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | Das graphische LCD //liquid crystal display// ist ein Display zur Darstellung von Bildern und Text. Es ist ähnlich aufgebaut wie das alphanumerische LCD, mit dem Unterschied, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Monochrome graphische Displays haben normalerweise eine passive Matrix, große Farbdisplays (auch Computer-Bildschirme) eine aktive. Im Hinblick auf die Farbe des Hintergrunds und der Pixel entspricht das graphische LCD dem alphanumerischen. Auch das graphische Display verfügt über einen separaten Controller, welcher die Information über die Kommunikationsschnittstelle empfängt und das elektrische Feld für die Segmente generiert. Im Gegensatz zum alphanumerischen LCD, welches Text anzeigt, indem die Indizes der darzustellenden Zeichen gesendet werden, kann das graphische LCD keine Buchstaben eigenständig generieren - sämtliche Bilder und Texte müssen Pixel für Pixel vom Nutzer generiert werden. | ||
| + | |||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das HomeLab Kit enthält ein 84x48 Pixel großes, monochromes, | ||
| + | |||
| + | Die Funktionen für das graphische LCD sind ähnlich zu denen des alphanumerischen LCD. Zuerst muss der Bildschirm mit der Funktion // | ||
| + | |||
| + | Nachfolgend ist ein Beispiel des Zeitzählers dargestellt. Das Programm zählt Sekunden (annähernd), | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispiel für die Nutzung des graphischen LCD des HomeLab. | ||
| + | // Die Tageszeit wird ab Beginn des Programms auf dem LCD angezeigt. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | int seconds = 0; | ||
| + | char text[16]; | ||
| + | |||
| + | // Einrichten des LCD. | ||
| + | lcd_gfx_init(); | ||
| + | |||
| + | // Löschen des Displays. | ||
| + | lcd_gfx_clear(); | ||
| + | |||
| + | // Einschalten der Hintergrundbeleuchtung. | ||
| + | lcd_gfx_backlight(true); | ||
| + | |||
| + | // Anzeige des Programmnamens. | ||
| + | lcd_gfx_goto_char_xy(1, | ||
| + | lcd_gfx_write_string(" | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Sekunden in die Form der Uhrzeit konvertieren. | ||
| + | // hh:mm:ss | ||
| + | sprintf(text, | ||
| + | (seconds / 3600) % 24, | ||
| + | (seconds / 60) % 60, | ||
| + | | ||
| + | |||
| + | // Anzeige des Zeittextes. | ||
| + | lcd_gfx_goto_char_xy(3, | ||
| + | lcd_gfx_write_string(text); | ||
| + | |||
| + | // Eine Sekunde hinzufügen. | ||
| + | seconds++; | ||
| + | |||
| + | // Hardwareverzögerung von 1000 ms. | ||
| + | hw_delay_ms(1000); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Aufgaben ==== | ||
| + | |||
| + | Ziel ist es, ein Programm zu schreiben, welches die unten beschriebenen Aufgaben erüllt. | ||
| + | |||
| + | === Aufwärmübung === | ||
| + | |||
| + | * Das Programm soll von 1 bis 9 und dann zurück von 9 bis 1 auf der 7-Segment-Anzeige zählen. Die Zählperiode beträgt 1 Sekunde. | ||
| + | |||
| + | === Für Anfänger === | ||
| + | |||
| + | - Stellen Sie die Zahlen im Hexadezimalsystem zufällig auf der 7-Segment-Anzeige dar. Die Frequenz beträgt 1 Hz. | ||
| + | - Lassen Sie die äußeren 6 Segmente der 7-Segment-Anzeige periodisch im Abstand von 500 ms aufleuchten. | ||
| + | - Schreiben Sie ein Programm für das LCD, welches den Code und das zugehörige Symbol anzeigt. Verwenden Sie Codes von 0 bis 255. Jedes Code-Symbol-Paar wird 1 Sekunde lang auf dem Display angezeigt. | ||
| + | - Schreiben Sie ein Programm, mit welchem das Symbol " | ||
| + | - Stellen Sie auf dem graphischen Display 10 Zeilen Text dar. Mit den Schaltern S1 und S2 kann innerhalb des Textes hoch- und runtergescrollt werden. | ||
| + | - Erstellen Sie eine Benutzerschnittstelle über welche mit den drei Schaltern Text eingegeben werden kann. Ein Schalter wählt beispielsweise das Zeichen aus, der zweite überprüft das Zeichen und der dritte überprüft schließlich den Text. Die maximale Länge des Textes beträgt 10 Zeichen und der Text soll in umgekehrter Reihenfolge in der zweiten Reihe dargestellt werden. Sie können das lateinische Alphabet nutzen und das Display selbst auswählen. | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Stellen Sie griechische Buchstaben auf dem graphischen LCD dar. Dabei sollen folgende Zeilen angezeigt werden: “Widerstand Ω”, “∑R=∑πR²”, | ||
| + | - Schreiben Sie ein Programm, um Dezimalzahlen in Binärzahlen zu konvertieren. Verwenden Sie die Schalter S3 bis S1 zum Einfügen von Dezimalzahlen in zehn Sekunden ( S3 - Hunderter S2 - Zehner S1 - Einer). Durch vierfaches Betätigen von Schalter S3 wird so beispielsweise die Zahl 400 angezeigt. Das Zeichen für den Beginn der Eingabe und für das Ergebnis sollen in Binärzahlen ausgegeben werden. Verwenden Sie hierzu ein beliebiges LCD. | ||
| + | - Schreiben Sie eine Funktion zur Darstellung eines Rechtecks auf dem LCD. Breite, Länge sowie die Koordinaten der oberen linken Ecke sind dabe vorgegeben. Die Linienstärke beträgt 1 Pixel. Überprüfen Sie, ob das Rechteck ins Display passt. Hierzu ist es ratsam, sich mit der HomeLab Library zu befassen. | ||
| + | - Programmieren Sie ein einfaches Wurm-Spiel für das graphische LCD. Der Wurm ist 1 Pixel breit und 5 Pixel lang. Durch Betätigung der Schalter kann der Wurm sich nach rechts oder links bewegen. Er muss auf diese Weise Kollisionen mit dem Displayrand vermeiden können. Es gibt Bonuspunkte für das Einsammeln von Eiern, wodurch der Wurm wächst. Die einfachste Lösung ist, den Wurm aus dem Buchstaben " | ||
| + | - Schreiben Sie ein Programm zur Darstellung verschiedener Wetterbedingungen auf dem graphischen LCD. Nutzen Sie für sonniges Wetter ein Bild der Sonne, für Regen eine Regenwolke, für bewölkt eine Wolke und für Schnee eine Schneeflocke. Die Größe der Bilder kann variieren, wichtig ist nur, dass die Bilder sich deutlich voneinander unterscheiden. Die Bilder sollen mittels eines Schalters gewechselt werden können. | ||
| + | |||
| + | === Fragen === | ||
| + | |||
| + | - Wie viele Pins nutzt die 7-Segment Zifferanzeige (mit Punktsegment), | ||
| + | - Was bestimmt die Helligkeit der 7-Segment Zifferanzeige? | ||
| + | - Wenn die 7-Segment Zifferanzeige direkt an Port A des Controllers angeschlossen ist sodass das Segment A PA0, B PA1 ... und DP PA7 ist, wie lauten dann die Werte des PORTA Registers mit den Ziffern 0 bis 9? | ||
| + | - Was ist der Unterschied zwischen alphabetischen 4-Bit und 8-Bit LCD Controllern? | ||
| + | - Über welche Pins und wie wird die Hintergrundbeleuchtung der alphanumerischen LCDs reguliert? | ||
| + | - Welches I/O Protokoll nutzt das graphische LCD? Erläutern Sie die Bedeutung der I/O Pins. | ||
| + | - Wie können Dezimalzahlen in binäre (in Text) konvertiert werden und umgekehrt? | ||
| + | - Zeichnen Sie die Schichten aus denen ein LCD besteht mittels der //twisted nematic// Technologie. | ||
| + | - Wie werden Buchstaben auf dem graphischen LCD angezeigt? | ||
| + | - Wie unterscheidet sich ein monochromes (schwarz/ | ||
| + | ===== Sensoren ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Sensoren sind Geräte welche jede Form von physikalischen Attributen (Temperatur, | ||
| + | |||
| + | Bei analogen Sensoren bewirkt jede physikalische Änderung eine Änderung des elektrischen Wertes, i. d. R. Spannung, Stromstärke oder Widerstand. Da Mikrocontroller digitale Geräte sind, muss das analoge Signal in ein digitales umgewandelt werden, bevor es zum Controller gesendet wird. Dafür werden Analog-zu-Digital Konverter benutzt, welche normalerweise im Mikrocontroller verbaut sind. | ||
| + | |||
| + | Analoge Sensoren welche die Information digitalisieren, | ||
| + | |||
| + | ==== Potentiometer ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Potentiometer ist ein elektronisches Widerstandsbauelement mit drei Anschlüssen. Zwischen den beiden Seitenkontakten ist der Widerstand fix, zwischen Seiten- und Mittelkontakt ist er variabel. Im Grunde ist ein Potentiometer ein Spannungsteiler, | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein typisches Potentiometer besteht aus einem Widerstand mit einer leitenden Oberfläche und einem Schiebekontakt (slider). Je näher der Schiebekontakt am Rand des Widerstandes angebracht ist, desto geringer ist der Widerstand zwischen Slider und Ecke des Widerstands und umgekehrt. Ein Material mit hohem Widerstand oder einer Spule aus Widerstandsdraht kann als Widerstand fungieren. Bei einigen Potentiometern sind die Beziehungen zwischen Widerstand und Sliderposition linear oder logarithmisch. Potentiometer sind normalerweise einfache Drehpotentiometer (siehe Bild), es gibt aber auch Schiebepotentiometer. Ein spezieller Typ von Potentiometer sind digitale Potentiometer, | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Am HomeLab Modul befindet sich ein 4,7 kΩ Drehpotentiometer. Das Potentiometer ist mit der Masse und dem +5 V Potential angeschlossen, | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Data types for adjustment | ||
| + | // | ||
| + | typedef enum | ||
| + | { | ||
| + | ADC_REF_AREF = 0x00, | ||
| + | ADC_REF_AVCC = 0x01, | ||
| + | ADC_REF_2V56 = 0x03 | ||
| + | } | ||
| + | adc_reference; | ||
| + | |||
| + | typedef enum | ||
| + | { | ||
| + | ADC_PRESCALE_2 | ||
| + | ADC_PRESCALE_4 | ||
| + | ADC_PRESCALE_8 | ||
| + | ADC_PRESCALE_16 | ||
| + | ADC_PRESCALE_32 | ||
| + | ADC_PRESCALE_64 | ||
| + | ADC_PRESCALE_128 = 0x07 | ||
| + | } | ||
| + | adc_prescale; | ||
| + | |||
| + | // | ||
| + | // Starting the ADC | ||
| + | // | ||
| + | void adc_init(adc_reference reference, adc_prescale prescale) | ||
| + | { | ||
| + | // Allowing ADC to operate, selecting the frequency divider | ||
| + | ADCSRA = bit_mask(ADEN) | (prescale & 0x07); | ||
| + | |||
| + | // Selecting comparison voltage | ||
| + | ADMUX = (reference & 0x03) << REFS0; | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Converting the values of selected channel | ||
| + | // | ||
| + | unsigned short adc_get_value(unsigned char channel) | ||
| + | { | ||
| + | // Setting the channel | ||
| + | ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); | ||
| + | |||
| + | // Starting the conversion | ||
| + | bit_set(ADCSRA, | ||
| + | |||
| + | // Waiting the end of the conversion | ||
| + | while (bit_is_set(ADCSRA, | ||
| + | { | ||
| + | asm volatile (" | ||
| + | } | ||
| + | |||
| + | // Returning the results | ||
| + | return ADCW; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Die Funktion // | ||
| + | |||
| + | In den zuvor erklärten Beispielprogrammen werden die Bibliotheken des ADC und des 7-Segment-Zifferanzeige genutzt. Der 10-Bit Wert des ADC wird mit 10 multipliziert und durch 1024 dividiert um einen Wert zwischen 0 und 9 zu erhalten. Der Wert 10 kann nicht erreicht werden, weil in C nur ganzzahligewerte berechnet werden und keine gerundeten Ergebnisse. | ||
| + | Um die Genauigkeit des Ergebnisses zu erhöhen, wird eine Funktion zur Berechnung des Durchschnitts der Ergebnisse des ACSs genutzt. Daraus abgeleitet gibt das Programm auf der Anzeige einen Wert von 0 bis 9 aus, welcher der Position des Potentiometers entspricht. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm für das Potentiometer des Sensormoduls | ||
| + | // Die Position des Potentiometers wird auf der 7-Segmentanzeige dargestellt | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Auswahl des Kanals | ||
| + | // | ||
| + | // 1 = Photoresistor | ||
| + | // 2 = Thermistor | ||
| + | // 3 = Potentiometer | ||
| + | // | ||
| + | #define ADC_CHANNEL 3 | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | int value; | ||
| + | |||
| + | // Anpassung der 7-Segmentanzeige | ||
| + | segment_display_init(); | ||
| + | |||
| + | // Anpassung des ADC | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Liest viermal gerundete Werte aus dem Kanal | ||
| + | value = adc_get_average_value(ADC_CHANNEL, | ||
| + | |||
| + | // Zeigt Hunderter des angezeigten Wertes an | ||
| + | segment_display_write(value * 10 / 1024); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Thermistor ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Thermistor ist temperaturabhängiger Widerstand. Es gibt Thermistoren mit positiven und mit negativen Temperaturkoeffizienten. Der Widerstand von Thermistoren mit positiven Koeffizienten nimmt mit steigender Temperatur zu, bei Thermistoren mit negativen Koeffizienten steigt er mit sinkender Temperatur. Die dazugehörigen Abkürzungen sind PTC(// | ||
| + | |||
| + | Die Temperaturabhängigkeit des Widerstands verläuft nicht linear zu der Temperatur, was die Nutzung erschwert. Für genaue Temperaturmessungen bei größeren Temperaturschwankungen wird die exponentielle Steinhart-Hart Gleichung dritter Ordnung genutzt, da der Thermistorwiderstand nur innerhalb kleiner Temperaturbereiche linear ist. Für NTC Thermistoren gibts es folgende vereinfachte Steinhart-Hart-Gleichung mit dem Parameter B: | ||
| + | |||
| + | {{: | ||
| + | |||
| + | mit:\\ | ||
| + | * T< | ||
| + | * R< | ||
| + | * B - Parameter B. | ||
| + | |||
| + | Der Parameter B ist ein Koeffizient, | ||
| + | |||
| + | Normalerweise wird ein Spannungsteiler genutzt, um den Widerstand eines Thermistors zu messen. Dabei wird ein Widerstand durch einen Thermistor ausgetauscht wird und die Inputspannung ist konstant. Es wird die Outputspannung des Spannungsteilers gemessen, welche sich in Abhängigkeit der Widerstandsänderung des Thermistors verändert. Wenn Spannung anliegt, fließt Strom durch den Thermistor, wodurch sich dieser bedingt durch den Thermistorwiderstand aufheizt und damit den Widerstand verändert. Der durch das Aufheizen entstehende Fehler kann berechnet werden, jedoch ist es einfacher einen Thermistor zu nutzen, welcher einen hohen Widerstand hat und sich nicht so viel aufheizt. | ||
| + | |||
| + | Bei begrenzten Ressourcen und geringerem Anspruch auf Genauigkeit, | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das Sensormodul des HomeLab enthält einen NTC Thermistor mit nominellem Widerstand von 10 kΩ. Bei Temperaturen von 25 bis 50 °C ist der Parameter B des Widerstands 3900. | ||
| + | Ein Pin des Thermistors ist an die +5 V Betriebsspannung angeschlossen der andere an Kanal 2 (Pin PF2). Ein typischer 10 kΩ Widerstand ist auch am gleichen Pin des Mikrocontrollers und an die Masse angeschlossen. So entsteht zusammen mit dem Thermistor ein Spannungsteiler. Da hier ein NTC Thermistor genutzt wird, bei welchem der Widerstand sinkt wenn die Temperatur steigt, wird die Outputspannung des Spannungsteilers bei steigender Temperatur höher. | ||
| + | |||
| + | Während der Nutzung des AVR ist es nützlich, eine Tabelle mit den Temperaturwerten und den Werten des ADC zu verwenden, um die korrekte Temperatur zu finden. Es ist sinnvoll, für jede Gradzahl der gewünschten Temperaturstufe des Messbereichs den korrespondierenden ADC Wert aus der Tabelle herauszusuchen, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Tabelle zur Konvertierung von Temperaturwerten ind ADC Werte. | ||
| + | // Jedes Element des Arrays kennzeichnet ein Grad Celsius. | ||
| + | // Die Elemente beginnen bei -20 Grad und enden bei 100 Grad. | ||
| + | // Ein Array enthält 121 Elemente. | ||
| + | // | ||
| + | const signed short min_temp = -20; | ||
| + | const signed short max_temp = 100; | ||
| + | |||
| + | const unsigned short conversion_table[] = | ||
| + | { | ||
| + | 91, | ||
| + | 160, | ||
| + | 257, | ||
| + | 375, | ||
| + | 501, | ||
| + | 619, | ||
| + | 720, | ||
| + | 799, | ||
| + | 859, | ||
| + | 903, | ||
| + | 934, | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | Folgender Algorithmus kann genutzt werden um die mit den ADC Parametern korrespondierende Temperatur zu finden: | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Konvertierung der ACD Werte in Grad Celsius: | ||
| + | // | ||
| + | signed short thermistor_calculate_celsius(unsigned short adc_value) | ||
| + | { | ||
| + | signed short celsius; | ||
| + | |||
| + | // Tabelle von hinten beginnend durchgehen: | ||
| + | for (celsius = max_temp - min_temp; celsius >= 0; celsius--) | ||
| + | { | ||
| + | // Ist der Wert aus der Tabelle gleich oder höher dem gemessenen | ||
| + | // Wert, ist die Temperatur mindestens so hoch wie die mit dem Element | ||
| + | // korrespondierende Temperatur. | ||
| + | if (adc_value >= conversion_table[celsius])) | ||
| + | { | ||
| + | // Da die Tabelle mit 0 beginnt, die Werte der Elemente jedoch mit -20, | ||
| + | // muss der Wert geshiftet werden. | ||
| + | return celsius + min_temp; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Wurde der Wert nicht gefunden, wird die minimale Temperaur ausgegeben. | ||
| + | return min_temp; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Der Algorithmus sucht den Bereich aus der Tabelle in dem der ACD Wert liegt und wählt die niedrigere Nummer dieses Bereiches. Die Ranknummer markiert die Gradzahl und durch das Addieren der anfänglichen Temperatur wird eine Genauigkeit von 1°C erreicht. | ||
| + | |||
| + | Umrechnungstabelle und Funktion sind schon in der HomeLab Bibliothek enthalten, sie müssen somit nicht extra für diese Aufgabe erstellt werden. In der Bibliothek heißt die Umrechnungsfunktion // | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm des Thermistors des Sensormoduls. | ||
| + | // Die Temperatur wird auf dem LCD angezeigt. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned short value; | ||
| + | signed short temperature; | ||
| + | char text[16]; | ||
| + | |||
| + | // Einrichten des LCD | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Löschen des LCD | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Name des Programms | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Einrichten des ADC | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Auslesen der 4-fach gerundeten Spannungswerte aus dem Thermistor | ||
| + | value = adc_get_average_value(2, | ||
| + | |||
| + | // Konvertieren der ADC Werte in Grad Celsius | ||
| + | temperature = thermistor_calculate_celsius(value); | ||
| + | |||
| + | // Konvertieren der Temperatur in Text. | ||
| + | // To display the degree sign, the octal variable is 337. | ||
| + | sprintf(text, | ||
| + | |||
| + | // Anzeige des Textes am Anfang der zweiten Zeile des LCDs. | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | lcd_alpha_write_string(text); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Extra === | ||
| + | |||
| + | * {{: | ||
| + | |||
| + | ==== Fotowiderstand ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | [{{ : | ||
| + | |||
| + | Ein Fotowiderstand ist ein Sensor, dessen elektrischer Widerstand sich je nach einfallender Lichtintensität verändert. Je intensiver das Licht ist, desto mehr freie Ladungsträger werden gebildet, und umso geringer wird dadurch der Widerstand des Bauteils. Durch das keramische Basismaterial führen zwei externe Metallkontakte des Widerstands zur lichtempfindlichen Membran, dessen Widerstand abhängig von der Geometrie und den Materialeigenschaften ist. Da lichtempfindliches Material durch die schmale, kurvige Spur zwischen den Elektroden bereits einen hohen Widerstand hat, kann der niedrigste totale Widerstand schon bei durchschnittlichen Lichtintensitäten erreicht werden. Der Fotowiderstand reagiert ähnlich dem menschlichen Auge nur auf bestimmte Wellenlängen, | ||
| + | |||
| + | ^ Farbe ^ Wellenlängen (nm) ^ | ||
| + | | Violett | ||
| + | | Blau | 450 – 500 | | ||
| + | | Grün | 500 – 570 | | ||
| + | | Gelb | 570 – 590 | | ||
| + | | Orange | ||
| + | | Rot | 610 – 700 | | ||
| + | |||
| + | Der Fotowiderstand arbeitet innerhalb eines bestimmten, festgelegten Temperaturbereichs. Soll der Sensor bei anderen Temperaturen genutzt werden, müssen präzise Umrechnungen durchgeführt werden, da die Widerstandseigenschaften des Sensors abhängig von der Umgebungstemperatur sind. | ||
| + | |||
| + | Zur Kennzeichnung der Lichtintensität wird die Beleuchtungsstärke (E) genutzt. Diese zeigt die Menge Licht an, die auf eine bestimmte Oberfläche trifft. Die Maßeinheit ist Lux (lx), wobei 1 Lux dem konstanten Lichtfluss von einem 1 Lumen entspricht, welcher auf eine Oberfläche von 1m² strahlt. In der Realität fällt Licht jedoch eigentlich nie gleichmäßig auf eine Oberfläche weshalb die Beleuchtungsstärke meistens als Durchschnittswert ermittelt wird. Unten sind ein paar Beispiele von Beleuchtungsstärken dargestellt: | ||
| + | |||
| + | Vergleichswerte von Beleuchtungsstärken: | ||
| + | |||
| + | ^ Umgebung | ||
| + | | Vollmond | ||
| + | | Abenddämmerung | ||
| + | | Auditorium | ||
| + | | Klassenraum | ||
| + | | Sonnenaufgang / -untergang| 400 | | ||
| + | | OP-Saal (Krankenhaus) | ||
| + | | direktes Sonnenlicht | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das Sensormodul aus dem HomeLab verfügt über einen VT935G Fotowiderstand. Ein Pin des Widerstands ist an der +5 V Stromversorgung angeschlossen, | ||
| + | |||
| + | Der Sensor VT935G ist nicht als spezifisches Messinstrument gedacht. Er soll vielmehr dazu dienen, Informationen über die allgemeinen Lichtverhältnisse (z. B. befindet sich eine eingeschaltete Lampe im Raum oder nicht) anzugeben. Dazu muss nur der Widerstand des Sensors in einem halbdunklen Raum gemessen und ins Programm eingetragen werden. Daraufhin kann man die gemessenen Werte vergleichen und feststellen ob es heller oder dunkler ist. | ||
| + | |||
| + | Die nun folgende Aufgabe ist ein wenig komplexer, da die Beleuchtungsstärke auch in Lux gemessen wird. Hierzu werden eine Annäherungsformel sowie Gleitkomma-Variablen angewendet. In C sind Gleitkomma-Variablen //float-// und // | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Das Datenblatt des Sensors beinhaltet eine Annäherungsformel für den Zusammenhang zwischen Beleuchtungsstärke und elektrischem Widerstand. Wie im logarithmisch skalierten Graphen rechts dargestellt, | ||
| + | |||
| + | |||
| + | log(a/b) = log(a) - log(b) | ||
| + | |||
| + | Die Relation wird durch den Anstieg des Y-Faktors (Steigung der Geraden) beschrieben, | ||
| + | |||
| + | log(E< | ||
| + | E< | ||
| + | |||
| + | So erhält man die Formel zur Berechnung der Beleuchtungsstärke bei gegebenem Widerstand. Da der Widerstand nicht direkt von Microcontroller gemessen werden kann befindet sich der Fotowiderstand im Spannungsteiler. Die Output-Spannung des Spannungsteilers wird durch den ADC zu einer spezifischen Variable konvertiert. Zur Bestimmung des Widerstands muss diese Output-Spannung (U< | ||
| + | |||
| + | U< | ||
| + | |||
| + | Mit Hilfe der Formel für Spannungsteiler (siehe Kapitel über Spannungsteiler) kann der Widerstand des Fotowiderstands (R< | ||
| + | |||
| + | R< | ||
| + | |||
| + | In der folgenden Berechnung von Spannung und Widerstand, werden die gegebenen Werte eingesetzt und die Indizes entfernt: | ||
| + | |||
| + | U = 5 * (ADC / 1024) \\ \\ | ||
| + | R = (10 * 5) / U - 10 \\ \\ | ||
| + | |||
| + | Die Beleuchtungsstärke kann dann mittels der folgenden vereinfachten Konversion genutzt werden: | ||
| + | |||
| + | E = 10< | ||
| + | = 10< | ||
| + | = (18.5< | ||
| + | |||
| + | Durch die Berechnung der Konstante vor der Variable des Feldes R, bleibt folgender Ausdruck: | ||
| + | |||
| + | E = 255,84 * R< | ||
| + | |||
| + | Die dargestellten Formeln sind jedoch nur im Zusammenhang mit Fotowiderständen des HomeLab Sensor-Moduls nützlich. Wird ein Schaltkreis mit anderen Komponenten bestückt, müssen die Variablen verändert werden. | ||
| + | Nachfolgend ist der Quellcode eines Beispielprogramms dargestellt, | ||
| + | |||
| + | In diesem Beispielprogramm werden die Variablen für Spannung, Widerstand und Beleuchtungsstärke als //double// Gleitkomma-Variablen definiert. Die Variablen, welche nun als Gleitkomma-Variablen genutzt werden, müssen immer eine Dezimalstelle beinhalten (diese kann auch einfach 0 sein, so verarbeitet der Compiler es korrekt). Wird die Funktion //sprintf// genutzt, um die Gleitkomma-Variable in Text zu konvertieren, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm des Fotowiderstands aus dem Sensormodul des HomeLab | ||
| + | // Der angenäherte Wert der Beleuchtungsstärke wird auf dem LCD dargestellt. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | char text[16]; | ||
| + | unsigned short adc_value; | ||
| + | double voltage, resistance, illuminance; | ||
| + | |||
| + | // Initialisiere LCD | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Lösche LCD. | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Name des Programms | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Einrichten des ADC | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Durchschnittlichen Wert des Fotoresistors auslesen | ||
| + | adc_value = adc_get_average_value(1, | ||
| + | |||
| + | // Input-Spannung am ADC berechnen | ||
| + | voltage = 5.0 * ((double)adc_value / 1024.0); | ||
| + | |||
| + | // Widerstand des Fotoresistors im Spannungsteiler berechnen | ||
| + | resistance = (10.0 * 5.0) / voltage - 10.0; | ||
| + | |||
| + | // Beleuchtungsstärke in lux berechnen | ||
| + | illuminance = 255.84 * pow(resistance, | ||
| + | |||
| + | // Beleuchtungsstärke in Text konvertieren | ||
| + | sprintf(text, | ||
| + | |||
| + | // Darstellung auf dem LCD | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | lcd_alpha_write_string(text); | ||
| + | |||
| + | // Verzögerung 500 ms | ||
| + | sw_delay_ms(500); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Infrarot-Entfernungsmesser ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Um die Distanz zu einem Objekt zu messen, gibt es optische Sensoren, welche die Triangulation als Messmethode nutzen. Die am häufigsten verwendeten Infrarot-Entfernungsmesser werden von der Firma " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Der Output der Infrarot-Entfernungsmesser von " | ||
| + | Jeder Sensor-Typ hat seinen spezifischen Messbereich, | ||
| + | Die minimale Entfernung wird durch die Besonderheit der Sharp Sensoren eingeschränkt. So fällt der Output steil ab, sobald die Entfernung einen bestimmten Punkt unterschreitet (je nach Baureihe liegt dieser bei 4 bis 20 cm) Das hat zur Folge, dass zu einem Outputwert zwei korrespondierende Entfernungswerte existieren. | ||
| + | Dieses Problem kann vermieden werden, indem beachtet wird, dass die Distanz zwischen Objekt und Sensor nicht zu gering ist. | ||
| + | |||
| + | === Übung | ||
| + | |||
| + | Das HomeLab Sensor-Kit enthält den Infrarot-Entfernungsmesser SHARP GP2Y0A21YK. | ||
| + | Der Messbereich dieses Sensors liegt zwischen 10 cm und 80 cm. Seine Output-Spannung hängt von der Entfernung ab und erreicht bis zu 3 V. Der Entfernungssensor ist am Sensormodul angeschlossen. Die Output-Spannung wird über Kanal 0 zum ADC des AVR gesendet. Aufbauend auf den vorangehenden Übungen zu Sensoren, ist es einfach ein Programm zu schreiben, welches die Output-Spannung des Entfernungsmessers misst. Zusätzlich dazu behandelt diese Aufgabe die Umwandlung der Spannung in eine Entfernung. | ||
| + | |||
| + | Das Datenblatt des GP2Y0A21YK beinhaltet einen Graphen welcher die Relation von Output-Spannung und gemessener Entfernung darstellt. Dieser Graph verläuft nicht linear. Der Graph der inversen Werte ist jedoch annähernd linear, wodurch relativ einfach die Formel zur Umwandlung von Spannung in Entfernung gefunden werden kann. Hierzu werden Punkte des Graphens in ein Tabellenkalkulationsprogramm eingefügt und so ein neuer Graph generiert. Die meisten Programme berechnen automatisch eine Trendlinie. | ||
| + | Nachfolgend ist der Graph des GP2Y0A21YK mit der Relation der korrigierten inversen Werte der Outputspannung zu den korrigierten inversen Werten der gemessenen Distanz, inklusive einer Trendlinie abgebildet. Zur Vereinfachung wurde die Output-Spannung schon in 10-Bit +5 V Werte des ADC mit Vergleichspannung konvertiert. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Wie der Graph zeigt, überschneiden sich die blaue Trendlinie und die Punkte des Graphen fast genau. Dieses wird durch die Nutzung einer Korrektur-Konstante erreicht. Diese Konstante wird mit der " | ||
| + | Im abgebildeten Graph ist die Korrektur-Konstantet +2; das bedeutet, zu allen realen Entfernungen muss +2 hinzuaddiert werden. Daruch verläuft der Graph nahezu gleich der Trendline und es kann für die Relation zwischen Entfernung und Spannung verallgemeinert folgende Formel angenommen werden: | ||
| + | |||
| + | 1 / (d + k) = a * ADC + b | ||
| + | |||
| + | wobei | ||
| + | |||
| + | * d - Entfernung in cm. | ||
| + | * k - Korrektur-Konstante (gefunden mittels trial-and-error Methode) | ||
| + | * ADC - digitalisierter Wert der Spannung. | ||
| + | * a - lineares Element (Wert wird durch die Trendlinien-Gleichung bestimmt) | ||
| + | * b - freies Element (Wert wird durch die Trendlinien-Gleichung bestimmt) | ||
| + | |||
| + | Die Entfernung d kann durch folgende Formel dargestellt werden: | ||
| + | |||
| + | d = (1 / (a * ADC + B)) - k | ||
| + | |||
| + | Nun ist es generell möglich die Entfernung mit der Formel zu berechnen. Da jedoch Brüche dividiert werden, sind zudem Gleitkomma-Berechnungen nötig. Weiterhin muss die Formel vereinfacht und auf größere Quotienten ausgeweitet werden, da Microcontroller mit Ganzzahlen arbeiten. Durch die Division des Quotienten mit einem linearen Element erhält man folgende Formel: | ||
| + | |||
| + | d = (1 / a) / (ADC + B / a) - k | ||
| + | |||
| + | Durch Aufnahme der Korrekturkonstante sowie des linearen und freien Elements der Trendlinien-Gleichung, | ||
| + | |||
| + | d = 5461 / (ADC - 17) - 2 | ||
| + | |||
| + | Diese Formel kann mit 16-Bit Zahlen berechnet werden und ist daher vollständig für den AVR geeignet. Vor der Berechnung muss sicher gestellt sein, dass der Wert des ADC größer als 17 ist, ansonsten kann der Fall eintreten, dass durch 0 geteilt werden muss oder eine negative Distanz ausgegeben wird. | ||
| + | |||
| + | Nachfolgend ist die Funktion dargestellt, | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Die Struktur der Parameter des Infrarot-Entfernungsmessers | ||
| + | // | ||
| + | typedef const struct | ||
| + | { | ||
| + | const signed short a; | ||
| + | const signed short b; | ||
| + | const signed short k; | ||
| + | } | ||
| + | ir_distance_sensor; | ||
| + | |||
| + | // | ||
| + | // Die Parametereigenschaften des GP2Y0A21YK Sensors | ||
| + | // | ||
| + | const ir_distance_sensor GP2Y0A21YK = { 5461, -17, 2 }; | ||
| + | |||
| + | // | ||
| + | // Konvertieren der Werte des Infrarot-Entfernungsmessers in Centimeter | ||
| + | // Gibt -1 aus, wenn die Konvertierung nicht erfolgreich war | ||
| + | // | ||
| + | signed short ir_distance_calculate_cm(ir_distance_sensor sensor, | ||
| + | unsigned short adc_value) | ||
| + | { | ||
| + | if (adc_value + sensor.b <= 0) | ||
| + | { | ||
| + | return -1; | ||
| + | } | ||
| + | |||
| + | return sensor.a / (adc_value + sensor.b) - sensor.k; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Zur Durchführung der Konvertierung muss die Funktion // | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm des Infrarot-Entfernungsmessers des HomeLab | ||
| + | // Die in Centimetern gemessenen Ergebnisse werden auf dem LCD abgebildet | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned short value; | ||
| + | signed short distance; | ||
| + | char text[16]; | ||
| + | |||
| + | // External sensor selection | ||
| + | pin ex_sensors = PIN(G, 0); | ||
| + | pin_setup_output(ex_sensors); | ||
| + | pin_set(ex_sensors); | ||
| + | |||
| + | // Initialisierung des LCD | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Löschen des LCD | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Name des Programms | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Installation des ADC | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Auslesen des viermal gerundeten Wertes der Outputspannung des Sensors | ||
| + | value = adc_get_average_value(0, | ||
| + | |||
| + | // Konvertieren des ADC-Wertes in Entfernung | ||
| + | distance = ir_distance_calculate_cm(GP2Y0A21YK, | ||
| + | |||
| + | // War die Berechnung erfolgreich? | ||
| + | if (distance >= 0) | ||
| + | { | ||
| + | // Konvertieren von Entfernung in Text | ||
| + | sprintf(text, | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // Text für eine unbekannte Entfernung erzeugen | ||
| + | sprintf(text, | ||
| + | } | ||
| + | |||
| + | // Anzeige des Textes am Anfang der zweiten Zeile auf dem LCD | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | lcd_alpha_write_string(text); | ||
| + | |||
| + | // Break | ||
| + | sw_delay_ms(500); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Zusätzliches Material === | ||
| + | |||
| + | * {{: | ||
| + | * [[http:// | ||
| + | |||
| + | ==== Ultraschall-Entfernungsmesser ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Ultraschall-Entfernungsmesser bestimmt die Entfernung zu einem Objekt, indem er die Zeit misst, die ein Schall zu einem Objekt hin und zurück benötigt. Die Frequenz des Geräusches liegt im Bereich des Ultraschalls. Dies garantiert, dass die Schallwelle gebündelt gelenkt wird, da sich hochfrequenter Schall weniger in der Umgebnung zerstreut. Ein typischer Ultraschall-Entfernungsmesser besteht aus zwei Membranen. Eine Membran produziert den Schall, die andere empfängt das Echo. Im Grunde besteht er also aus einem Lautsprecher und einem Mikrophon. Der Schallgenerator generiert kurze (wenige Perioden umfassende) Ultraschallimpulse und startet den Timer. Die zweite Membran registriert die Ankunft des Echos und stoppt den Timer. Mit der Zeit des Timers ist es möglich, die zurückgelegte Entfernung des Schalls zu berechnen. Die Entfernung zu einem Objekt entspricht der Hälfte der zurückgelegten Entfernung des Schalls. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Der Ultraschall-Entfernungsmesser findet im täglichen Leben eine Vielzahl von Anwendungsmöglichkeiten. Er wird beispielsweise als Ersatz für Maßbänder auf Baustellen eingesetzt, Autos besitzen Ultraschall-Entfernungsmesser als Parksensoren. Neben der Entfernungsmessung dient er auch dazu, das bloße Vorhandensein eines Objekts im Messbereich zu erkennen, z. B. in der Gefahrenzone einer Arbeitsmaschine. Sind Ultraschalltransmitter und -empfänger getrennt, kann die Fließgeschwindigkeit des Materials zwischen ihnen bestimmt werden, da Schallwellen langsamer aufwärts fließen. | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das HomeLab enhält einen Devantech SRF04/SRF05 Ultraschall-Entfernungsmesser. Der SRF04/SRF05 ist jedoch nur ein Sensor und gibt keine direkte Information über die Distanz. Neben den Stromversorgungspins besitzt der Sensor auch einen Trigger- und einen Echo-Pin. | ||
| + | Ist der Trigger-Pin " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Um den SRF04/SRF05 mit dem AVR zu nutzen, müssen Trigger- und Echo-Pin an den AVR Pins angeschlossen werden. Zur Zeitmessung, | ||
| + | Außerdem sollte darauf geachtet werden, dass die Schallwellen sich nicht gegenseitig stören, wenn verschiedene Ultraschallsensoren gleichzeitig genutzt werden. | ||
| + | |||
| + | <code c> | ||
| + | #define ULTRASONIC_SPEED_OF_SOUND 33000 // cm/s | ||
| + | |||
| + | // | ||
| + | // Sofortige Ultraschall-Entfernungsmessung | ||
| + | // | ||
| + | unsigned short ultrasonic_instant_measure(pin trigger, pin echo) | ||
| + | { | ||
| + | // Pin-Setup | ||
| + | pin_setup_output(trigger); | ||
| + | pin_setup_input_with_pullup(echo); | ||
| + | |||
| + | // Timer 3 auf den normalen Modus setzen | ||
| + | // mit der Periode des F_CPU / 8 | ||
| + | timer3_init_normal(TIMER3_PRESCALE_8); | ||
| + | |||
| + | // Erzeugung des Aulöse-Impulses | ||
| + | pin_set(trigger); | ||
| + | |||
| + | // Timer zurücksetzen | ||
| + | timer3_overflow_flag_clear(); | ||
| + | timer3_set_value(0); | ||
| + | |||
| + | // ~10 us warte | ||
| + | while (timer3_get_value() < 18) {} | ||
| + | |||
| + | // Auslöse-Impuls beenden | ||
| + | pin_clear(trigger); | ||
| + | |||
| + | // Warten auf den Echo-Start | ||
| + | while (!pin_get_value(echo)) | ||
| + | { | ||
| + | // Timeout ? | ||
| + | if (timer3_overflow_flag_is_set()) | ||
| + | { | ||
| + | return 0; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Timer erneut zurücksetzen | ||
| + | timer3_set_value(0); | ||
| + | |||
| + | // Warten auf Beendigung des Echos | ||
| + | while (pin_get_value(echo)) | ||
| + | { | ||
| + | // Timeout ? | ||
| + | if (timer3_overflow_flag_is_set()) | ||
| + | { | ||
| + | return 0; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Konvertierung von Zeit in Entfernung: | ||
| + | // | ||
| + | return (unsigned long)timer3_get_value() * | ||
| + | ULTRASONIC_SPEED_OF_SOUND / (F_CPU / 4); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Die gegebene Funktion erlaubt dem Nutzer den Echo-und den Trigger-Pin so zu wählen, dass der Sensor dort angeschlossen werden kann wo es am günstigesten ist und genug Platz vorhanden ist. Zusätzlich erlaubt dies, die Funktion auch außerhalb von HomeLab zu nutzen. Die dargestellte Funktion ist bereits in der HomeLab Library enthalten und muss somit nicht geschrieben werden. Es gibt noch eine Sache zu beachten: Die Funktion in der Library ist streng an die Taktrate des Controller-Moduls von HomeLab gekoppelt. Die Taktrate beträgt 14,7456 MHz, wenn die Funktion mit anderen Taktraten genutzt wird, liefert sie falsche Ergebnisse. Um die Funktion mit anderen Taktraten zu nutzen sollte sie manuell programmiert werden. Der folgende Code demonstriert die Nutzung des SRF04/SRF05 Ultraschall-Entfernungsmessers mit der HomeLab Library: | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Beispielprogramm für den Ultraschall-Entfernungsmesser des HomeLab | ||
| + | // Die Entfernungsmessung wirkt blockierend. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Pins des Ultraschallsensors | ||
| + | // | ||
| + | pin pin_trigger = PIN(G, 1); | ||
| + | pin pin_echo | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | unsigned short distance; | ||
| + | char text[16]; | ||
| + | |||
| + | // Initialisierung des LCD | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON); | ||
| + | |||
| + | // Löschen des LCD | ||
| + | lcd_alpha_clear(); | ||
| + | |||
| + | // Name des Programms | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Kleine Unterbrechung | ||
| + | sw_delay_ms(100); | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Messen | ||
| + | distance = ultrasonic_measure(pin_trigger, | ||
| + | |||
| + | // War die Messung erfolgreich? | ||
| + | if (distance > 0) | ||
| + | { | ||
| + | // Konvertierung von Entfernung in Text. | ||
| + | sprintf(text, | ||
| + | } | ||
| + | // Sind während der Messung Fehler aufgetreten? | ||
| + | else | ||
| + | { | ||
| + | // Text des Fehlers. | ||
| + | sprintf(text, | ||
| + | } | ||
| + | |||
| + | // Darstellung des Textes am Anfang der zweiten Zeile des LCD | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | lcd_alpha_write_string(text); | ||
| + | |||
| + | // Kleine Unterbrechung. | ||
| + | sw_delay_ms(500); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | --- | ||
| + | | ||
| + | ==== Übungen ==== | ||
| + | |||
| + | Ziel ist es, ein ein Programm zu schreiben welches folgende Aufgaben ausführt: | ||
| + | |||
| + | |||
| + | === Aufwärmübung === | ||
| + | |||
| + | * Der Widerstand des Potentiometers soll auf dem LCD in Ohm angezeigt werden. Der nominale Wert des Widerstands beträgt 5 kΩ. | ||
| + | |||
| + | === Für Anfänger = | ||
| + | |||
| + | - Der Widerstand des Potentiometers wird im Bereich von (0 Ω…999 Ω) in Ohm dargestellt und im Bereich von (1000 Ω…5000 Ω) in kOhm. Der nominale Wert des Widerstands beträgt 5 kΩ. Das Ergebnis wird mit korrekten Einheiten und Symbolen dargestellt. | ||
| + | - Messung der Distanz zu einem Objekt. Die Distanz zu dem Objekt wird mit einem Infrarot-Entfernungsmesser gemessen wenn der Schalter S1 betätigt wird. Während der Messung blinkt eine gelbe LED. Ist das Objekt weiter als 50 cm entfernt, leuchtet eine grüne LED, ist es weniger weit entfernt, die rote. | ||
| + | - Die Distanz zu dem Objekt wird mit einem Infrarot-Entfernungsmesser gemessen. Das Ergebnis wird im binären System mit den 3 LEDs dargestellt (LED1, LED2, und LED3). Vergrößert sich die Entfernung, muss auch der angezeigte Wert größer werden. Als Skala sollte etwa 1 dm = 1 Bit verwendet werden. | ||
| + | - Der Wert des NTC Temperatursensors wird auf dem LCD in Grad angezeigt. Durch Betätigung des Schalters S2 können die Einheiten ausgewählt werden: Kelvin (K), Fahrenheit (F) und Celsius (C). Die Temperatur wird in korrekten Einheiten und Symbolen angezeigt. | ||
| + | - Mit dem Lichtintensitätssensor werden schnelle Änderungen der Lichtintensität festgestellt. (Licht an- / ausschalten). Verläuft die Änderung schnell, blinkt die rote LED für 5 Sekunden. Ändert sich die Intensität langsam, wird die Änderungsrichtung gezeigt. Die grüne LED zeigt an, dass die Lichtintensität ansteigt, die gelbe, dass sie abnimmt. | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Datenschreiber. Die Werte aller analogen Sensoren werden konstant gemessen und die minimalen und maximalen Werte werden festgehalten. Mit Betätigung von S1 kann der Nutzer die auf dem LCD angezeigten Information wählen. Angezeigt werden muss: Der Name des Sensors(kurz) und die bislang erreichten minimalen / maximalen Werte. Die Sequenz des Durchschaltens ist folgende: IR Entfernungsmesser -> Fotowiderstand -> Thermistor | ||
| + | - Entfernungsmesser. Wenn der Schalter S2 gedrückt wird, werden der Reihe nach 10 Messungen in einer Sekunde durchgeführt. Nach der Messung wird die durchschnittliche Entfernung zum Objekt in Dezimeter auf dem 7-Segment Indikator angezeigt. Bei Betätigung des Schalters S1, wird die minimale gemessene Entfernung angezeigt und durch S3 die maximale. | ||
| + | - Geschwindigkeit. Die Änderungsrate der Entfernung zu einem Objekt wird wie folgt angezeigt: langsame Änderung - grüne LED, mittlere Änderung - gelbe LED, schnelle Änderung - rote LED. Die Geschwindigkeit wird auf dem LCD dargestellt. | ||
| + | - Automatische Messreichweite. Je nach aktueller Messung werden die minimal oder maximal | ||
| + | - Durch Kombination von Infrarot- und Ultraschall-Entfernungsmesser kann die Entfernung zum Objekt, die Geschwindigkeit sowie die Richtung des Objektes bestimmt werden. Die Ergebnisse werden auf dem LCD dargestellt. | ||
| + | |||
| + | < | ||
| + | |||
| + | === Fragen === | ||
| + | |||
| + | - Wie exakt ist der ADC des ATmega128 Mikrocontrollers? | ||
| + | - Wie lange dauert ein ADC-Prozess? | ||
| + | - Welchen Inputspannungsbereich hat der ADC? Kann dieser geändert werden? Wie? | ||
| + | - Was ist der Unterschied zwischen PTC-Thermistoren und NTC-Thermistoren? | ||
| + | - Was ist der Grund eines Spannungsteilers in einem Messschaltkreises? | ||
| + | - Kombinieren Sie einen Spannungsteiler, | ||
| + | - Zusätzliche Widerstände werden an den Pins des Potentiometers angeschlossen und eine 5 V Spannung wird angelegt. Wie groß müssen die zusätzlichen Widerstände sein, damit die Spannung vom Potentiometer zwischen 1 und 2 V reguliert werden kann (von einem Ende zum anderen)? Die Stromstärke darf 10 mA nicht überschreiten. | ||
| + | - Welche Umgebungsparameter haben einen Effekt auf die Funktion des Ultraschallentfernungsmessers und warum? | ||
| + | - Welche Lichtsensivitätssensoren können in einem Robotikprojekt genutzt werden? Nennen Sie mindestens 3 grundlegende Komponenten und erklären Sie die Unterschiede. | ||
| + | - Wie kann, neben der trigonometrischen Methode, die Entfernung mittels Licht gemessen werden? Nennen Sie mindestens drei Methoden. | ||
| + | ===== Motoren ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Motoren sind Antriebsgeräte, | ||
| + | |||
| + | Es gibt viele Möglichkeiten, | ||
| + | |||
| + | ==== Gleichstrommotor ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Ein Gleichstrommotor mit permanenten Magneten wird häufig für die verschiedensten Anwendungen genutzt, bei denen kleine Ausmaße, große Kraft und ein geringer Preis entscheidend sind. Auf Grund ihrer hohen Geschwindigkeit, | ||
| + | |||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Gleichstrommotoren mit permanenten Magneten sind vom Aufbau her sehr einfache und ihre Bedienung ist relativ einfach. Aber auch wenn die Kontrolle sehr einfach ist, wird die Geschwindigkeit nicht präzise über das Steuersignal bestimmt, weil hierauf noch viele andere Faktoren, wie das Drehmoment und der Speisestrom, | ||
| + | |||
| + | Gleichstrommaschinen nutzen Gleichstrom und brauchen eigentlich keine spezielle Kontrollelektronik, | ||
| + | | ||
| + | [{{ : | ||
| + | |||
| + | Der Vierquadrantensteller besitzt vier Transistoren die den Strom lenken, um den Motor zu betreiben. Das elektrische Schaltbild des Vierquadrantenstellers ist ähnlich des Buchstaben H, daher der englische Name H-Bridge. Das Besondere am Vierquadrantensteller ist, dass man damit beide Polaritäten am Motor anlegen kann. Das Bild auf der Seite zeit das grundsätzliche Schema eines Vierquadrantenstellers am Beispiel der Schalter. Werden zwei diagonale Schalter geschlossen, | ||
| + | |||
| + | Zusätzlich zur Richtungsänderung kann der Vierquadrantensteller auch die Geschwindigkeit des Motors verändern. Dazu werden die Transistoren konstant durch Pulsweitenmodulation geöffnet und geschlossen. Damit ist die Energie, die der Motor erhält irgendwo zwischen vollem und keinem Stromdurchfluss. Die Zeit in der die Transitoren geöffnet sind, wird in der PWM-Periode Arbeitszyklus genannt, welche in % angegeben wird. Bei 0 % ist der Transistor konstant geschlossen und es fließt kein Strom. Bei 100 % ist der Transistor ist durchgehend geöffnet, und Strom fließt die ganze Zeit. Die Frequenz der PWM muss hoch genug sein, um Vibrationen der Motorwelle zu verhindern. Bei niedrigen Frequenzen produziert der Motor Geräusche, daher wird oft eine Modulationsfrequenz von über 20 kHz genutzt. Auf der anderen Seite ist die Effizienz des Vierquadrantenstellers nicht so gut bei hohen Frequenzen. Vibrationen der Motorwelle werden durch die Trägheit des Rotors und der Induktionswiderstand der Spulen reduziert. | ||
| + | |||
| + | Es gibt auch integrierte Vierquadrantensteller für niedrigere Stromstärken. Für höhere Stromstärken werden spezielle Metall-Oxid-Halbleiter-Feldeffekttransistoren verwendet. Der Vierquadrantensteller mit anderer Elektronik wird Motorcontroller oder Treiber genannt. | ||
| + | Der Teiber des Gleichstrommotors im HomeLab L293D hat 2 eingebaute Vierquadrantensteller und Ausschaltdioden. Der Motor wird mit drei digitalen Signalen gesteuert, eins davon ist das //enable// Signal, welches Funktionen einschaltet, | ||
| + | |||
| + | Beachte: Verwechslen Sie nicht RC PWM Signal und gewöhnliche PWM Signale. | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das Board der Motoren des HomeLab erlaubt den Anschluss von bis zu 4 Gleichstrommotoren. Das Schaltbild und die Anleitung für die Anschlüsse können im Kapitel " | ||
| + | Wenn beide Kontrollpins den gleichen Wert haben, wird der Motor gestoppt. Wenn verschiedene Werte vorliegen, wird der Motor in eine bestimmte Richtung gedreht. Der Status des Vierquadrantenstellers ist in der folgende Tabelle beschrieben: | ||
| + | |||
| + | ^ Input A ^ Input B ^ Output A ^ Output B ^ Result | ||
| + | | 0 | ||
| + | | 1 | ||
| + | | 1 | ||
| + | | 0 | ||
| + | |||
| + | Gleichstrommotoren können durch Änderung der dazugehörigen Treiberpins mit dem Mikrocontroller kontrolliert werden. Die speziellen Funktionen um den Motor zu steuern sind in der HomeLab Bibliothek enthalten. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Die Einrichtung von Pins als Treiberpins. | ||
| + | // | ||
| + | static pin dcmotor_pins[4][2] = | ||
| + | { | ||
| + | { PIN(B, 7), PIN(B, 4) }, | ||
| + | { PIN(D, 1), PIN(D, 0) }, | ||
| + | { PIN(D, 7), PIN(D, 6) }, | ||
| + | { PIN(D, 5), PIN(D, 4) } | ||
| + | }; | ||
| + | |||
| + | // | ||
| + | // Steuerung des gewählten DC Motors zulassen. | ||
| + | // | ||
| + | void dcmotor_init(unsigned char index) | ||
| + | { | ||
| + | pin_setup_output(dcmotor_pins[index][0]); | ||
| + | pin_setup_output(dcmotor_pins[index][1]); | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Festlegung der Funktion und Richtung des gewählten DC Motors. | ||
| + | // | ||
| + | void dcmotor_drive(unsigned char index, signed char direction) | ||
| + | { | ||
| + | pin_set_to(dcmotor_pins[index][0], | ||
| + | pin_set_to(dcmotor_pins[index][1], | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Mit dem Array // | ||
| + | |||
| + | Das folgende Beispielprogramm steuert den ersten und zweiten Gleichstrommotor so, dass sie jede Sekunde ihre Drehrichtung ändern. Die Geschwindigkeit kann gesteuert werden, wenn ein Kontrollpin mit einem PWM Signal moduliert wird. | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Testprogramm für den DC Motor aus dem DC Motorenmodul des HomeLab. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Richtungsvariable | ||
| + | signed char direction = 1; | ||
| + | |||
| + | // Einrichtung von Motor 1 und 2. | ||
| + | dcmotor_init(0); | ||
| + | dcmotor_init(1); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Ein Motor dreht sich in die eine, der andere in die entgegengesetzte Richtung. | ||
| + | dcmotor_drive(0, | ||
| + | dcmotor_drive(1, | ||
| + | |||
| + | // Unterbrechung für 1 Sekunde. | ||
| + | sw_delay_ms(1000); | ||
| + | |||
| + | // Umkehr der Richtung. | ||
| + | direction = -direction; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | --- | ||
| + | | ||
| + | ==== Servomotor ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Servomotoren werden oft in funkgesteuerten (RC) Modellen benutzt und sind sehr nützlich für kleine robotischen Anwendungen, | ||
| + | Ein RC-Servomotor verfügt über einen eingebauten Gleichstrommotor, | ||
| + | |||
| + | RC (// | ||
| + | Eine wichtige Eigenschaft des Servomotors ist das Kraft-Gewicht-Verhältnis. | ||
| + | |||
| + | Das Kontrollsignal des Servomotors ist ein speziell pulsweitenmoduliertes Signal (PWM), bei dem die Pulsweite die Position des Rotors angibt. Die Periode des Signals liegt bei 20 ms (50 Hz) und die Weite der hohen Periode ist 1 ms - 2 ms. 1 ms markiert die eine äußerste Position 2 ms die Andere. 1,5 ms markieren die Mittelposition des Servomotorrotors. | ||
| + | |||
| + | Traditionelle RC-Servomotoren sind auch bekannt als analoge Servomotoren. Dies liegt daran, dass in dem letzten Jahrzehnt so genannte digitale Servomotoren auf den Markt kamen. Der Unterschied zwischen beiden besteht darin, dass analoge RC-Servomotoren mit einem 50 Hz PWM Signal gesteuert werden, digitale RC-Servomotoren durch einen Mikrocontroller mit einem höherfrequenten Signal. Das Inputsignal ist das Gleiche, jedoch ist durch die höhere Modulationsfrequenz wird eine schnellere und präzisere Positionsbestimmung ermöglicht. | ||
| + | |||
| + | ~~CL~~ | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Auf dem Platine des HomeLab Motormoduls sind 2 Anschlüsse für RC-Servomotoren vorhanden. | ||
| + | Die PWM-Enden der Stecker sind an den Pins PB5 und PB6 am Mikrocontroller angeschlossen, | ||
| + | |||
| + | Timer 1 muss in den PWM-Produktionsmodus eingestellt werden, wobei der maximale Wert des Timers mit dem ICR Register bestimmt wird. Durch Änderung des maximales Wertes im Programm und im Taktgeber des Timers, kann die präzise PWM Frequenz zur Steuerung des Servomotors bestimmt werden. Mit dem Vergleichs-Register des Timers werden die Längen für beiden hohen Semi-Perioden des Signals bestimmt. Der Timer hat eine spezielle Vergleichseinheit, | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Der WErt des Timers (20 ms) zum ERreichen der vollen PWM-Periode. | ||
| + | // F_CPU ist die Taktrate des Mikrocontrollers, | ||
| + | // | ||
| + | // | ||
| + | #define PWM_PERIOD | ||
| + | |||
| + | // | ||
| + | // Mittlere Position der PWM des Servomotors (5 ms / 20 ms) | ||
| + | // Mittlere Position liegt bei 15/200 der vollen Periode. | ||
| + | // | ||
| + | #define PWM_MIDDLE_POS | ||
| + | |||
| + | // | ||
| + | // Faktor zur Konvertierung von Prozenten in Perioden(-100% to 100%). | ||
| + | // +1 wird addiert um sicherzustellen, | ||
| + | // | ||
| + | #define PWM_RATIO | ||
| + | |||
| + | // | ||
| + | // Einrichtung der Pins. | ||
| + | // | ||
| + | static pin servo_pins[2] = | ||
| + | { | ||
| + | PIN(B, 5), PIN(B, 6) | ||
| + | }; | ||
| + | |||
| + | // | ||
| + | // Servomotor vorbereiten. | ||
| + | // | ||
| + | void servomotor_init(unsigned char index) | ||
| + | { | ||
| + | // Pin des PWM Signals als Output. | ||
| + | pin_setup_output(servo_pins[index]); | ||
| + | |||
| + | // Einrichtung von Timer 1. | ||
| + | // Vorzähler = 8 | ||
| + | // Schneller PWM Modus, wobei TOP = ICR | ||
| + | // OUTA und OUTB auf low im Vergleich. | ||
| + | timer1_init_fast_pwm( | ||
| + | TIMER1_PRESCALE_8, | ||
| + | TIMER1_FAST_PWM_TOP_ICR, | ||
| + | TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH, | ||
| + | TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH, | ||
| + | TIMER1_FAST_PWM_OUTPUT_DISABLE); | ||
| + | |||
| + | // Festlegung der Periode durch maximalen Wert. | ||
| + | timer1_set_input_capture_value(PWM_PERIOD); | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Festlegung der Postition des Servomotors. | ||
| + | // Parameter der Position liegen zwischen -100% und +100%. | ||
| + | // | ||
| + | void servomotor_position(unsigned char index, signed short position) | ||
| + | { | ||
| + | switch (index) | ||
| + | { | ||
| + | case 0: | ||
| + | timer1_set_compare_match_unitA_value( | ||
| + | PWM_MIDDLE_POS + position * PWM_RATIO); | ||
| + | break; | ||
| + | |||
| + | case 1: | ||
| + | timer1_set_compare_match_unitB_value( | ||
| + | PWM_MIDDLE_POS + position * PWM_RATIO); | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das Beispielprogramm nutzt beschriebene Funktionen der HomeLab Bibliothek. Am Anfang des Programms wird der erste PWM-Signal Generator des Servomotors mit der // | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Testprogramm des Motormoduls des HomeLab kit. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | short position; | ||
| + | |||
| + | // Einrichtung des ADC. | ||
| + | adc_init(ADC_REF_AVCC, | ||
| + | |||
| + | // Einrichtung des Motors. | ||
| + | servomotor_init(0); | ||
| + | |||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Auslesen der Position aus dem Potentiometer und Konvertiereung der Reichweite | ||
| + | // des Servomotors. | ||
| + | position = ((short)adc_get_value(3) - (short)512) / (short)5; | ||
| + | |||
| + | // Festlegung der Position des Servomotors. | ||
| + | servomotor_position(0, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Schrittmotor ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Schrittmotoren können generell in unipolare und bipolare Schrittmotoren eingeteilt werden. | ||
| + | Unipolare Schrittmotoren haben charakteristische Windungen welche die zwei Spulen in vier unterteilen. Schrittmotoren haben keine eingebauten Bürsten oder Elektronik, d.h. jegliche Kommunikation muss extern erfolgen. Der am meisten benutzte Kommutationstyp ist der offene-Regelkreis- (" | ||
| + | |||
| + | Schrittmotoren werden oft in Applikationen genutzt, die Genauigkeit benötigen. Anders als Gleichstrommotoren haben Schrittmotoren weder Bürsten, noch Kommutatoren. Sie haben verschiedene unabhängige Spulen, welche durch externe Elektronik (Treiber) angetrieben werden. Um den Rotor anzutreiben, | ||
| + | | ||
| + | * Reluktanzschrittmotor (hohe Genauigkeit, | ||
| + | * Permanentmagnetschrittmotor (niedrige Genauigkeit, | ||
| + | * Hybrider Schrittmotor (hohe Genauigkeit, | ||
| + | |||
| + | Der Reluktanzschrittmotor verfügt über gezahnte Windungen und einen gezahnten Weicheisenrotor. Die größte Zugkraft entsteht, wenn die Zähne beider Seiten sich gegenseitig abdecken. Der Permanentmagnetschrittmotor bestitz, wie der Name schon sagt, Permanentmagneten welche sich je nach Polarität der Windung orientieren. Der hybride Schrittmotor nutzt beide Techniken. | ||
| + | |||
| + | Je nach Modell des Schrittmotors, | ||
| + | |||
| + | |||
| + | < | ||
| + | |||
| + | **Unipolare Schrittmotoren ** | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Unipolare Schrittmotoren haben fünf oder sechs Anschlüsse. Je nach Aufbau des Motors werden nur ¼ der Wicklungen aktiviert. //Vcc// Leitungen werden normalerweise an der positiven Stromquelle angeschlossen. Während der Umwandlung sind die Enden der Wicklungen 1a, 1b, 2a und 2b über Transistoren (Transistorarray der Motorplatine ULN2803) nur an die Masse angeschlossen, | ||
| + | |||
| + | **Bipolare Schrittmotoren** | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Bipolare Schrittmotoren unterscheiden sich von unipolaren, da sie die Polarität ihrer Wicklungen während der Umwandlung verändern. Die Hälfte der Wicklungen wird gleichzeitig aktiviert, daher sind sie effizenter als unipolare Schrittmotoren. Bipolare Schrittmotoren haben 4 Anschlüsse, | ||
| + | |||
| + | Die notwendige Kommutation, | ||
| + | |||
| + | |||
| + | ^ ^ | ||
| + | ^ Schritt ^ 1A ^ 2A ^ 1B ^ 2B ^ 1A ^ 2A ^ 1B ^ 2B ^ | ||
| + | ^ | ||
| + | | 1 ^ 1 | 0 | 0 | 0 ^ + | - | - | - | | ||
| + | | 2 | 0 ^ 1 | 0 | 0 | - ^ + | - | - | | ||
| + | | 3 | 0 | 0 ^ 1 | 0 | - | - ^ + | - | | ||
| + | | 4 | 0 | 0 | 0 ^ 1 | - | - | - ^ + | | ||
| + | ^ | ||
| + | | 1 ^ 1 | 0 | 0 | 0 ^ + | - | - | - | | ||
| + | | 2 ^ 1 ^ 1 | 0 | 0 ^ + ^ + | - | - | | ||
| + | | 3 | 0 ^ 1 | 0 | 0 | - ^ + | - | - | | ||
| + | | 4 | 0 ^ 1 ^ 1 | 0 | - ^ + ^ + | - | | ||
| + | | 5 | 0 | 0 ^ 1 | 0 | - | - ^ + | - | | ||
| + | | 6 | 0 | 0 ^ 1 ^ 1 | - | - ^ + ^ + | | ||
| + | | 7 | 0 | 0 | 0 ^ 1 | - | - | - ^ + | | ||
| + | | 8 ^ 1 | 0 | 0 ^ 1 ^ + | - | - ^ + | | ||
| + | |||
| + | === Übung === | ||
| + | |||
| + | Das Ziel dieser Aufgabe ist es, unter Anwendung der oben beschrieben Methode einen bipolaren Schrittmotor zu starten, welcher mit einem unipolaren Schrittmotor getauscht werden kann. Es gibt Treiber auf der Motorenplatine, | ||
| + | Zu den Enden 1A, 1B, 2A und 2B gehören die entsprechenden Pins PB0, PB1, PB2 Und PB3 am Mikrocontroller. | ||
| + | |||
| + | In der HomeLab Bibliothek gibt es die Funktion // | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Vorbereitung der Steuerung des bipolaren Schrittmotors. | ||
| + | // | ||
| + | void bipolar_init(void) | ||
| + | { | ||
| + | DDRB |= 0x0F; | ||
| + | PORTB &= 0xF0; | ||
| + | } | ||
| + | |||
| + | // | ||
| + | // Bewegung des bipolaren Schrittmotors mit Halbschritten. | ||
| + | // | ||
| + | void bipolar_halfstep(signed char dir, | ||
| + | unsigned short num_steps, unsigned char speed) | ||
| + | { | ||
| + | unsigned short i; | ||
| + | unsigned char pattern, state1 = 0, state2 = 1; | ||
| + | |||
| + | // Festlegung der Richtung +- 1 | ||
| + | dir = ((dir < 0) ? -1 : +1); | ||
| + | |||
| + | // Durchführung von Halbschritten. | ||
| + | for (i = 0; i < num_steps; i++) | ||
| + | { | ||
| + | state1 += dir; | ||
| + | state2 += dir; | ||
| + | |||
| + | // Erstellung des Musters. | ||
| + | pattern = (1 << ((state1 % 8) >> 1)) | | ||
| + | (1 << ((state2 % 8) >> 1)); | ||
| + | | ||
| + | // Output setzen. | ||
| + | PORTB = (PORTB & 0xF0) | (pattern & 0x0F); | ||
| + | |||
| + | // Pause um auf die Ausführung des Schrittes zu warten. | ||
| + | sw_delay_ms(speed); | ||
| + | } | ||
| + | |||
| + | // Anhalten des Motors. | ||
| + | PORTB &= 0xF0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Die Funktion wird durch ein Beispielprogramm demonstriert, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Das Testprogramm für den bipolaren Schrittmotor des Motormoduls | ||
| + | // des HomeLab. | ||
| + | // | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm. | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Einrichtung des Motors. | ||
| + | bipolar_init(); | ||
| + | | ||
| + | // Endlosschleife. | ||
| + | while (true) | ||
| + | { | ||
| + | // Bewegung des Rotors 200 Halbschritte in eine Richtung mit einer Geschwindigkeit von 30 ms/Schritt. | ||
| + | bipolar_halfstep(+1, | ||
| + | |||
| + | // Bewegung des Rotors 200 Halbschritte in die andere Richtung mit einer Geschwindigkeit von 30 ms/Schritt. | ||
| + | bipolar_halfstep(-1, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | ==== Aufgaben | ||
| + | |||
| + | Ziel ist es, ein Programm zu schreiben, welches die folgenden Aufgaben erfüllen kann. | ||
| + | |||
| + | === Aufwärmübung === | ||
| + | |||
| + | * Steuern des Gleichstrommotors mit dem digitalen Board. Durch Betätigung von Schalter S1 leuchtet LED1 auf und der Motor dreht sich im Uhrzeigersinn. Durch Betätigung von Schalter S3 leuchtet die LED3 auf und der Motor dreht sich gegen den Uhrzeigersinn. Durch Betätigung von Schalter S2 leuchtet LED2 auf und der Motor wird gestoppt. | ||
| + | |||
| + | === Für Anfänger === | ||
| + | |||
| + | - Roboter: Durch Nutzung von zwei Gleichstrommotoren und Berührungssensoren wird die Bewegung eines Roboters simuliert. Berührungssensoren sind die Schalter am digitalen Board (S1…S3). Die Motoren werden durch die Betätigung der Schalter gesteuert. S1 stoppt den linken Motor für zwei Sekunden und startet dann beide Motoren mit voller Geschwindigkeit. S2 stoppt den rechten Motor für zwei Sekunden und startet dann beide Motoren mit voller Geschwindigkeit. Wenn beide Schalter betätigt werden drehen beide Motoren rückwärts, | ||
| + | - Servomotor: Der Servomotor wird mit den Schaltern des digitalen Boards kontrolliert. Wenn S1 gedrückt wird macht der Servomotor einen Schritt nach rechts, bei S3 einen Schritt nach links und S2 bewegt den Servomotor wieder in die ursprüngliche Position (Mitte). Die Position des Motors wird direkt auf dem 7-Segment Display dargestellt (jede Nummer steht für 10° Drehung, Mittelposition = 5) | ||
| + | - Radar: Die Funktion eines Radars wird simuliert. Um ein Objekt, welches näher als 0.5 Meter ist, zu identifizieren, | ||
| + | - Schrittmotor: | ||
| + | - Alle drei Motorentypen werden angeschlossen. Durch Betätigung eines Schalters wird ein bestimmter Motor gestartet und angehalten. S1 steuert den Gleichstrommotor, | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Der Gleichstrommotor beschleunigt wenn S1 gedrückt wird und hält die momentane Geschwindigkeit, | ||
| + | - Ein Objekt verfolgen: Durch das Nutzen des Ultraschall-Entfernungsmessers, | ||
| + | - der Schrittmotor hält die letzte Position des Motors nach Änderung jeder Sequenz. Wenn eine neue Sequenz aktiviert wird, nutzen Sie eine Variable, so dass die Bewegung exakt von der letzten Position des Motors fortgeführt wird. | ||
| + | - Beschleunigung: | ||
| + | - Entwerfen Sie einen PID-Regulator für einen Gleichstrommotor. Achtung! Diese Aufgabe benötigt einen Motor mit Feedback. Diese Aufgabe kann daher auch theoretisch gelöst werden. | ||
| + | |||
| + | ==== Fragen ==== | ||
| + | |||
| + | - Welcher Vierquadrantensteller wird genutzt? Nach welchem Prinzip funktioniert er? | ||
| + | - Wie wird die Position der Achse eines RC-Servomotors bestimmt? | ||
| + | - Was ist der Hauptunterschied zwischen unipolaren und einem bipolaren Schrittmotoren? | ||
| + | - Wie können Halbschritt und Mikroschrittmodi eines Schrittmotors genutzt werden? Nennen Sie ein Beispiel. | ||
| + | - Wie kann die Rotationsgeschwindigkeit eines DC Motors gesteuert werden? Nennen Sie ein Beispiel. | ||
| + | - Welcher PWM-Arbeitszyklus wird benötigt um eine Gleichstrommotorrotation mit 70% der nominalen Geschwindigkeit zu erreichen? | ||
| + | - Wie wird die Richtung der Motorrotation bestimmt, wenn ein Encoder genutzt wird? | ||
| + | - Wie kann ein Gleichstrommotor elektronisch gebremst werden? | ||
| + | - Was passiert, wenn das Schema der Stromwendung eines Schrittmotors sich zu schnell ändert? | ||
| + | - Ist dynamisches Bremsen möglich? Wenn ja, wie? | ||
| + | |||
| + | ===== Datenschnittstellen ===== | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Mit Microcontrollern können Antriebe gesteuert werden, Werte von Sensoren ausgelesen werden und viel mehr. Diese Geräte müssen dazu jedoch immer mit dem Mikrocontroller verbunden sein; es ist somit nicht möglich, durch einfache Signale zu kommunizieren. Das liegt darin begründet, dass zu viele Steuerungssignale zur Steuerung der Schnittstelle benötigt werden oder, dass zu viele Daten gesendet werden müssen. Daher wurden zahlreiche Standards von Datenschnittstellen für Mikrocontroller oder andere Elektronik entwickelt. Die Standards bestimmen die elektrischen Parameter der Signale und die Übertragungsregeln für die Signale (das Protokoll). | ||
| + | |||
| + | Ein einfaches Beispiel eines Protokolls ist der Morse Code, womit Informationen durch Nutzung von Pieptönen und Pausen in verschiedenen Abständen übertragen werden. Digitale Datenübertragungsprotokolle arbeiten ähnlich. Dort werden die Informationen als Bit Werte gesendet und je nach Schnittstelle Angepasst an versschiedene Bedürfnisse wurden diverse Schnittstellen zur Datenübertragung entwickelt. Da die Datenmengen jedoch stetig ansteigen, werden immer wieder neue Methoden entwickelt. Bei elektronischen Komponenten ist die Situation dahingehend etwas stabiler. Die I²C, SPI und UART Schnittstellen werden schon sehr lange verwendet. Traditionellere Schnittstellensysteme für die Übertragung innerhalb eines Systems sind RS-232, Rs-485, LIN and CAN, aber viele Mikrocontroller werden schon mit USB, Ethernet und kabellosen ZigBee Schnittstellen produziert. Dieses Kapitel konzentriert sich auf die RS-232 Schnittstelle. | ||
| + | |||
| + | ==== RS-232 ==== | ||
| + | |||
| + | // | ||
| + | |||
| + | === Theorie === | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die RS-232 ist ein Standard unter den physischen Datenschnittstellen und wird zur Übertragung von Binärdaten genutzt. Dieser Standard wird überwiegend für serielle Anschlüsse von Computern verwendet, welche gewöhnlich als " | ||
| + | |||
| + | Die RS-232 Schnittstelle wird hauptsächlich in Verbindung mit dem UART Datenübermittlungsmodul genutzt. Diese UART-Hardware verfügt über ein standardisiertes Protokoll, legt jedoch keine Stecker oder andere Dinge fest. Die RS-232 Schnittstelle erweitert somit das UART Modul. UART ist ein Peripheriemodul des Mikrocontrollers, | ||
| + | |||
| + | Die Bezeichnung UART steht für " | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die Datenübertragung erfolgt über den Rahmen der UART-Schnittstelle, | ||
| + | | ||
| + | Zusätzlich zur Rahmenstruktur gibt es einen weiteren wichtigen Parameter - die // | ||
| + | |||
| + | Darüber hinaus ist es wichtig zu wissen, dass der RS-232 Standard zusätzlich zu den Datensignalen (RX, TX) auch über Datenflusskontrollpins DTR, DCD, DSR, RI, RTS undCTS verfügt, welche zur Kontrolle der Kommunikation zwischen den Geräten dienen. Sie können zum Beispiel genutzt werden, um festzustellen ob das Gerät zum Empfang von Daten bereit ist oder nicht. Da die RS-232 Schnittstelle ursprünglich darauf abzielt, Computer an ein Modem anzuschließen, | ||
| + | |||
| + | === Praktisches Beispiel === | ||
| + | |||
| + | Die Platine des Controllermoduls ist mit einem RS-232 male-Stecker ausgerüstet. Darüber kann der Controller an einen Computer oder einen anderen Controller angeschlossen werden. Um ihn an einen Computer anzuschließen, | ||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Anschluss des Controllermoduls des HomeLab an einen Computer über die RS-232 Schnittstelle. | ||
| + | // Im Beispiel wird ein digitales Input-Output-Modul mit LCD Display verwendet. | ||
| + | // Der im Terminal des Computers eingegebene Text wird auf dem LCD Display angezeigt. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung der USART Schnittstelle. | ||
| + | // | ||
| + | usart port = USART(0); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | char c; | ||
| + | unsigned char row = 1; | ||
| + | |||
| + | // Installation der USART Schnittstelle. | ||
| + | usart_init_async(port, | ||
| + | USART_DATABITS_8, | ||
| + | USART_STOPBITS_ONE, | ||
| + | USART_PARITY_NONE, | ||
| + | USART_BAUDRATE_ASYNC(9600)); | ||
| + | |||
| + | // Installation des LCD. | ||
| + | lcd_alpha_init(LCD_ALPHA_DISP_ON_BLINK); | ||
| + | |||
| + | // Anzeige eines Begrüßungstextes auf dem Display. | ||
| + | lcd_alpha_write_string(" | ||
| + | |||
| + | // Cursor an den Beginn der zweiten Reihe setzen. | ||
| + | lcd_alpha_goto_xy(0, | ||
| + | |||
| + | // " | ||
| + | usart_send_string(port, | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Zeichen aus der seriellen Schnittstelle lesen. | ||
| + | if (usart_try_read_char(port, | ||
| + | { | ||
| + | // Befassen wir uns mit dem Zeichen zur Änderung der Reihe? | ||
| + | if (c == ' | ||
| + | { | ||
| + | // Änderung der Reihe. | ||
| + | row = 1 - row; | ||
| + | |||
| + | // Vorherige Nachricht aus der Reihe löschen. | ||
| + | lcd_alpha_clear_line(row); | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // Ausgabe des Zeichens auf dem Display. | ||
| + | lcd_alpha_write_char(c); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Windows XP OS beinhaltet das Programm HyperTerminal. Dieses Programm kann über das //Start// Menü geöffnet werden, indem // | ||
| + | ==== ZigBee ==== | ||
| + | |||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ==== Aufgabe ==== | ||
| + | |||
| + | Ziel ist es ein Programm zu schreiben, welches die folgenden Aufgaben erfüllt. | ||
| + | |||
| + | === Aufwärmübung === | ||
| + | |||
| + | * Es wird eine Nummer an den Computer gesendet, diejede Sekunde größer wird. Die Nummer muss in Textform sein und mit einem Reihenänderungszeichen enden (\n). | ||
| + | |||
| + | === Für Anfänger === | ||
| + | |||
| + | - Es wird auf die Befehle (in Buchstaben), | ||
| + | " | ||
| + | - Wenn ein Schalter betätigt wird, wird der Name dieses Schalters (S1, S2, S3) am Computer über dieRS-232 Schnittstelle empfangen. | ||
| + | |||
| + | === Für Fortgeschrittene === | ||
| + | |||
| + | - Kommunikation zwischen zwei RS-232 Controllern. Wird ein Schalter betätigt, sendet der eine Controller dem Anderen die Nummer des Schalters. Wenn die Nummer empfangen wurde, wird der Status der zugehörigen LED verändert.' | ||
| + | - Erstellen Sie ein " | ||
| + | |||
| + | ==== Fragen==== | ||
| + | |||
| + | - Beschreiben Sie das UART Paket. | ||
| + | - Was ist die Baud-Rate? | ||
| + | - Was ist der Unterschied zwischen Voll/ | ||
| + | - Finden Sie mindestens 5 Sensoren, welche die serielle Schnittstelle nutzen. | ||
| + | - Nennen Sie den Unterschied zwischen UART und USART Schnittstelle. Welche ist schneller? | ||
| + | - Wie funktioniert die SPI Schnittstelle? | ||
| + | - Nennen Sie Schnittstellen, | ||
| + | - Nennen Sie verschiedene Archtiekturen und erklären Sie ihre Unterschiede. | ||
| + | - Auf welchem Spannungslevel finden RS-232 und UART Verbindungen statt? | ||
| + | - Wie lange benötigt, es 1MiB bei einer Baud-Rate von 9600 dps , mit 8 Daten-Bits, einem Stop-Bit und ohne Paritätskontrolle, | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | --- | ||
| + | | ||
| + | ====== Beispielprojekte ====== | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Das Beispielprojekt in diesem Kapitel enthält eine Anleitung zur Vorbereitung einer Projektdokumentation und erläutert, welche Themen behandelt werden sollten sowie was zu den einzelnen Themen geschrieben werden sollte. Es ist sehr hilfreich, eine Dokumentation eines typischen Projekts als Beispiel zu nehmen. Leider ist die gesamte Projektdokumentation aufgrund des Bildmaterials zu umfangreich und würde den Rahmen dieses Buches sprengen. Dennoch enthält das Beispielprojekt alle wichtigen Aspekte. So werden beispielsweise nur wichtige Details einer Zeichnung oder nur ein PCB eines elektronischen Plans gezeigt. Dennoch sollte eine tatsächliche Dokumentation Zeichnungen und Pläne für alle erstellten Details enthalten. Das Beispielprojekt soll auch die Lehrer dahin gehend unterstützen, | ||
| + | ===== Bericht ===== | ||
| + | |||
| + | Um ein einfaches mechatronisches Gerät herzustellen, | ||
| + | Am Ende des Projekts soll ein Bericht erstellt werden. Es ist eine Dokumentation welche mindesten die folgenden Punkte enthalten soll: | ||
| + | |||
| + | |||
| + | * **Titelseite** | ||
| + | * **Zusammenfassung** | ||
| + | * **Zusammenfassung (in Fremdsprache / Englisch)** | ||
| + | * **Inhaltsverzeichnis** | ||
| + | - **Ursprüngliche Aufgabe** | ||
| + | - **Systemvoraussetzungen und Einschränkungen** | ||
| + | - **Modell des Systems** \\ Struktur und Funktionalität eines Systems als Blockdiagramm. Zusätzlich können eine Anleitung zur Nutzung des Anwendungsfalldiagramms, | ||
| + | - **Designlösungen** \\ Mindestens drei verschiedene Konzeptlösungen für diese Aufgabe. Geeignet sind handgezeichnete Diagramme, Zeichnungen etc. Dokumentation mit Kommentaren. | ||
| + | - **Mechanik** \\ Am Besten ein 3D Modell mit Zeichnungen von wichtigen Verbindungen und Bauanweisungen. Falls eine Verbindung spezielle Anweisungen benötigt, dann auch Bauanleitungen und Zeichnungen hinzufügen. Wenn möglich eine Animation der Funktionen des Systems beifügen. | ||
| + | - **Elektronik** \\ Darstellung aller genutzten Module in einem Blockdiagramm (Controller, | ||
| + | - **Control System** \\ Kontrollalgorhytmus und Quellcode. Falls selbst-erstellte Funktionen genutzt werden, eine Tabelle der Funktionen und Parameter, usw. angeben. | ||
| + | - **Gebrauchsfertige Lösung** \\ Beschreibung und Bilder | ||
| + | - **Wirtschaftliche Rechnung** \\ Auflistung von Komponenten wie Kosten, geschätzte, | ||
| + | - **Projektmanagement** \\ Zeitplan des Projekts, die Ressourcenbelegung, | ||
| + | - **Zusammenfassung und Fazit** \\ Was war schwer, was würden Sie anders machen, was wurde mit dem Projekt erreicht etc. Die Zusammenfassung umfasst eine kleine Beschreibung der Arbeit, aufgetretene Probleme werden genannt und das Ergebnis der Arbeit wird dargestellt. Darüber hinaus ist es sinnvoll, die eigene Meinung bezüglich der Notwendigkeit des Projekts hinzuzufügen. Außerdem bezüglich des Nutzens für die Projektmitgliedern bringt, dazu was in Zukunft anders gemacht werden sollte, was man gelernt hat und was den Leitern und Organisatoren des Projekts vorschlagen werden sollte. | ||
| + | * **Genutzte Quellen und Materialien** | ||
| + | * **Anhang** | ||
| + | |||
| + | Das folgende Beispielprojekt zeigt, wie eine Dokumentation und ein Bericht eines Projekts erstellt werden. Aufgrund des begrenzten Umfangs dieses Buches kann der Bericht leider nur in gekürzter Fassung dargestellt werden, er stellt aber immer noch die verschiedenen Aspekte einer Dokumentation dar. | ||
| + | ===== Mobile Roboterplattform ===== | ||
| + | |||
| + | Der mobile Roboter ist eine der populärsten Robotorkonstruktionen. Sehr verbreitet sind Sumoroboter, | ||
| + | |||
| + | Nachfolgend werden eine Dokumentation eines typischen Projekts für eine mobile Roboterplattform sowie die verschiedenen Projektphasen dargestellt. | ||
| + | |||
| + | === Ursprüngliche Aufgabe === | ||
| + | |||
| + | Planen und konstruieren Sie eine multifunktionale mobile Roboterplattform mit einfacher Navigationsfunktion unter der Verwendung von HomeLab Komponenten. Die Roboterplattform muss eine einfach zu ändernde operationale Funktion besitzen, wenn sie mit verschiedenen Gadgets ausgerüstet wird: | ||
| + | * Manipulator | ||
| + | * Radar | ||
| + | * Kamera | ||
| + | Der Roboter muss sich in geschlossenen Räumen auf flachen Böden bewegen können. | ||
| + | |||
| + | == Voraussetzungen == | ||
| + | |||
| + | * Maximale Abmessung: 20 cm x 20 cm x 20 cm | ||
| + | * maximales Gewicht: 2 kg | ||
| + | * Höchstgeschwindigkeit: | ||
| + | * volle Selbstständigkeit | ||
| + | |||
| + | == Einschränkung == | ||
| + | |||
| + | * Muss überwiegend aus HomeLab Komponenten bestehen | ||
| + | * Kostengrenze: | ||
| + | |||
| + | < | ||
| + | |||
| + | === Grundlegendes Modell des Systems | ||
| + | |||
| + | Das grundlegende Modell des System wird mit einem Blockdiagramm dargestellt. Es beschreibt die Struktur, das Verhalten und andere wichtige Aspekte des Systems. Als Beispiel ist nachfolgend das hierarchische Modell des System abgebildet. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | === Designlösungen === | ||
| + | |||
| + | Für diese Aufgabe hat das Team eine Brainstorming-Methode verwendet und drei vom Konzept völlig unterschiedliche Vorschläge erstellt. Es wurde eine Evaluationsmatrix erstellt und so die optimale Konstruktion gefunden. Der größte Unterschied der drei Lösungen liegt im Bewegungsschema. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | < | ||
| + | |||
| + | Vereinfachte Evaluationsmatrix: | ||
| + | |||
| + | ^ Funktion/ | ||
| + | |Kosten | ||
| + | |Komplexität im Bau | 2 | 4 | 7 | 0,7 | | ||
| + | |Beweglichkeit | ||
| + | |Permittivität | ||
| + | |Anwendbarkeit in Homelab | 5 | 4 | 5 | 0,9 | | ||
| + | |Gewicht | 5 | 6 | 7 | 0,8 | | ||
| + | ^Total (mit Gewichtungsfaktor) ^ 19^27^ 28^ ^ | ||
| + | |||
| + | Die Evaluationsskala umfasst Werte von 1 bis 10 und der Gewichtungsfaktor liegt zwischen 0 und 1. Der Gewichtungsfaktor wird nach den Anforderungen und Einschränkungen des Systems ausgewählt. So ist beispielsweise Lösung 2 beweglicher auf unebenen Boden, dieses war jedoch nicht in der ursprünglichen Aufgabe gefordert, daher ist der Gewichtungsfaktor niedrig. | ||
| + | |||
| + | Basierend auf der Auswertung, ist die optimale Lösung für die gestellte Aufgabe eine Plattform auf zwei Rädern mit zwei separaten Motoren. Die weitere Arbeit besteht in der Entwicklung der gewählten Lösung in ein reales System. | ||
| + | < | ||
| + | |||
| + | === Mechanik === | ||
| + | |||
| + | Die Mechanik wurde so einfach wie möglich gehalten, wobei dem Prinzip der Modularität gefolgt wurde. Front- und Heckstossstange sind identische Module. Die Elektronik beseteht aus drei Modulen, welche übereinander platziert werden und mit einfachen Flachbandkabeln verbunden werden. Darüber hinaus wird so sicher gestellt, dass die Module relativ einfach ausgewechselt werden können. | ||
| + | Die Motoren entstammen dem HomeLab kit: Motoren mit einem integrierten Drehzahlminderer und Coder, welche direkt mit den Antrieb des Motors verbunden sind. Es wurden Modellflugzeugräder benutzt, da diese sehr leicht und robust sind. Um die Konstruktion zu vereinfachen sind Boden und Dachplatte identisch. Die Platten haben Löcher, damit unterschiedliche Geräte an der Dachplatte angeschlossen werden können. Neben der Elektronik passt auch eine Batterie problemlos zwischen den Platten. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | Die Stoßstangen des Roboters werden separat geplant und sind mit Berührungs- und Linienfolgesensoren ausgestattet. Die Stoßstange wird aus PCBs hergestellt und verfügt dadurch über Elektrizität. Die Linienfolgesensoren werden direkt auf die Stoßstange der Bodenplatte gelötet. Berührungssensoren (Mikroschalter) werden zwischen den Stoßstangenplatten platziert und mit einem Gummistück an der Front geschützt. Das Gummistück absorbiert den Aufprall und ermöglicht gleichzeitig zu identifizieren, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | === Elektronik === | ||
| + | |||
| + | Die Elektronik des Systems ist in einem Prinzipsschema und Schaltplan mit PCB-Aufbau-Plan beschrieben. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | < | ||
| + | |||
| + | Als Beispiel werden die Schaltpläne der Linienfolgesensoren sowie die dazugehörigen PCB-Aufbau Pläne der Stoßstange des Roboters gezeigt. | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | < | ||
| + | |||
| + | === Kontrollsystem === | ||
| + | |||
| + | Das Kontrollsystem des Roboters, leitet sich von einem Verhaltensmodell ab und ist an Funktionalität, | ||
| + | Aus dem Verhaltensmodell des Systems wird ein spezifisches Kontrollprogramm entworfen, welches wiederum die Basis für den Softwareprogrammcode ist. | ||
| + | Alle drei Ebenen (Verhaltensmodell-Algorihtmus-Quellcode) müssen miteinander vereinbar sein. | ||
| + | |||
| + | == Algorithmus == | ||
| + | |||
| + | Der Algorithmus beschreibt die Kontrolllogik des System und wird als Blockdiagramm dargestellt. Einige Elemente und Beschreibungen der Verhältnisse genügen, um einen einfachen Algorithmus zu erstellen. Wenn der Algorithmus für den Roboter richtig zusammengestellt ist, kann daraus sehr einfach ein Kontrollprogramm erstellt werden. | ||
| + | Grundsätzlich werden zwei verschiedene Objekte in einem Algorithmus genutzt: ein Rechteck mit runden Ecken, zur Darstellung einer Aktivität sowie ein kleiner Diamant zur Kontrolle einer Bedingung, gefolgt von einem Start weiterer Aktivitäten, | ||
| + | |||
| + | Bedeutung der im Algorithmus verwendeten Symbole: | ||
| + | |||
| + | ^Symbol^Bedeutung^0^1^-1^ | ||
| + | |M1|linker Motor|Stop|rotiert im Uhrzeigersinn|rotiert gegen den Uhrzeigersinn| | ||
| + | |M2|rechter Motor|stop|rotiert im Uhrzeigersinn|rotiert gegen den Uhrzeigersinn| | ||
| + | |F|erster mittlerer Berührungssensor|kein Signal|Signal| | | ||
| + | |FR|erster rechter Berührungssensor|kein signal|Signal | | | ||
| + | |FL|erster linker Berührungssensor|kein signal|Signal | | | ||
| + | |d|Bezug| | | | | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | == Quellcode | ||
| + | |||
| + | Einfache Navigation | ||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // Definieren der Stoßstangenpins | ||
| + | pin front = PIN(C, 0); | ||
| + | pin frontleft | ||
| + | pin frontright = PIN(C, 2); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Starten von Motor 0 und 1 | ||
| + | dcmotor_init(0); | ||
| + | dcmotor_init(1); | ||
| + | |||
| + | // Sensorpins als Inputs | ||
| + | pin_setup_input_with_pullup(front); | ||
| + | pin_setup_input_with_pullup(frontleft); | ||
| + | pin_setup_input_with_pullup(frontright); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Motorstart im Uhrzeigersinn | ||
| + | dcmotor_drive(0, | ||
| + | dcmotor_drive(1, | ||
| + | | ||
| + | // Kontrolle des mittleren Sensorsignals | ||
| + | if (pin_get_value(front)) | ||
| + | { | ||
| + | // Umkehr der Motoren | ||
| + | dcmotor_drive(0, | ||
| + | dcmotor_drive(1, | ||
| + | |||
| + | // Pause 1 Sekunde | ||
| + | sw_delay_ms(1000); | ||
| + | |||
| + | // Start des linken Motors im Uhrzeigersinn | ||
| + | dcmotor_drive(0, | ||
| + | |||
| + | // Pause 2 Sekunden | ||
| + | sw_delay_ms(2000); | ||
| + | } | ||
| + | |||
| + | // Kontrolle des linken Sensorsignals | ||
| + | else if (pin_get_value(frontleft)) | ||
| + | { | ||
| + | // Umkehr des rechten Motors | ||
| + | dcmotor_drive(1, | ||
| + | |||
| + | // Pause 2 Sekunden | ||
| + | sw_delay_ms(2000); | ||
| + | } | ||
| + | |||
| + | // Kontrolle des rechten Sensorsignals | ||
| + | else if (pin_get_value(frontright)) | ||
| + | { | ||
| + | // Umkehr des linken Motors | ||
| + | dcmotor_drive(0, | ||
| + | |||
| + | // Pause 2 Sekunden | ||
| + | sw_delay_ms(2000); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | |||
| + | === Gebrauchsfertige Lösung === | ||
| + | |||
| + | Die in diesem Projekt gebaute Roboterplattform besteht zum größten Teil aus Plastik, außer der Motorbefestigung, | ||
| + | Als zweite Lösung wurde ein intelligentes Kameramodul installiert, | ||
| + | |||
| + | [{{ : | ||
| + | [{{ : | ||
| + | |||
| + | < | ||
| + | |||
| + | === Kostenkalkulation === | ||
| + | |||
| + | Die Kostenkalkulation enthält die Kosten für die Komponenten und die Produktion des Roboters | ||
| + | |||
| + | Tabelle der Komponentenkosten | ||
| + | |||
| + | ^Komponent^Marke^Anzahl^Preis^Kosten^ | ||
| + | |Motor|M LE149.6.43|2|500.-|1000.-| | ||
| + | |Mikrocontroller|uC ATmega128|1|900.-|900.-| | ||
| + | |Motorenantriebsplatine|Actuator Board v1.2|1|700.-|700.-| | ||
| + | |Power plate|TP|1|500.-|500.-| | ||
| + | |Linienfolgesensoren|LFS QRD1114|8|30.-|240.-| | ||
| + | |Berührungssensoren|TS Microswitch|8|25.-|200.-| | ||
| + | |Gehäuseblech|ABS |4|50.-|200.-| | ||
| + | |PCB Rohteil| |2|50.-|100.-| | ||
| + | |Motorenbefestigungsprofil|Al-L |2|10.-|20.-| | ||
| + | |Reifen|60/ | ||
| + | |Batterie|NI-MH 9,6 V|1|350.-|350.-| | ||
| + | |Kabel| |10|20.-|200.-| | ||
| + | |Muttern| |1|50.-|50.-| | ||
| + | |Weiteres Zubehör| |1|100.-|100.-| | ||
| + | ^ Total ^ ^ ^ ^ 4620.- ^ | ||
| + | Kosten in EEK. | ||
| + | |||
| + | Geschätzte Arbeits- und Produktionskosten für ein einzelnes Modell. | ||
| + | |||
| + | ^Arbeit^Zeit (h)^Preis^Kosten ^ | ||
| + | |Fräsen der Bauteile|1|300.-|300.-| | ||
| + | |Fräsen der PCBs (Stoßstangen)|0, | ||
| + | |Bau des Roboters|0, | ||
| + | |Bau der Stoßstangen (löten der Komponenten)|1|300.-|300.-| | ||
| + | |Programmierarbeit|5|300.-|1500.-| | ||
| + | |Erstellen der Dokumentation|3|250.-|750.-| | ||
| + | ^Total^ 11 ^ ^ 3225.- ^ | ||
| + | |||
| + | Vorraussichtliche Kosten des Roboters **7845.-** | ||
| + | |||
| + | Die Kostenkalkulation des Roboters basiert auf geschätzten, | ||
| + | |||
| + | === Projektmanagement === | ||
| + | |||
| + | Das mechatronische System (Roboter) ist in Gruppenarbeit mit straffem Zeitplan und Budget entstanden, und besitzt damit die wichtigsten Eigenschaften eines Projektes. | ||
| + | Die Schlüsselaktivitäten des Projekts waren: Erstellung des Zeitplans, Planung und Management der Gruppenarbeit, | ||
| + | |||
| + | [{{ : | ||
| + | |||
| + | === Fazit === | ||
| + | |||
| + | Die Kostenrechnung hat gezeigt, dass die Produktionkosten des Roboters sehr hoch sind, besonders wenn man nur mit einem Exemplar rechnet. Die Kosten blieben jedoch im anfänglich gesetzten Rahmen. Die Prouktionskosten könnten durch Optimierung des Materials und der Komponeten sowie durch gleichzeitige Fertigung mehrerer Roboter wesentlich reduziert werden. | ||
| + | Während des Projekts ist deutlich geworden, wie ein mechatronisches System geplant, gebaut und getestet wird. | ||
| + | |||
| + | Am Ende der Arbeit ist eines klar geworden: Damit der Roboter richtig funktioniert, | ||
| + | Unterschiedliche Module funktionieren nicht immer einwandfrei zusammen, auch wenn dieses in einzelnen Experimenten klappt. Dadurch wird deutlich, dass die Integration von Modulen in ein System eine echte Herausforderung darstellt, und hierfür mehr Zeit und Ressourcen eingeplant werden sollten. | ||
| + | |||
| + | Abschließend hoffen wir, dass das Projekt sehr interessant und lehrreich war und einen Einblick in das Design und die Konstruktion von integrierten Systemen geben konnte. | ||
| + | |||
| + | === Genutzte Quellen und Materialien === | ||
| + | |||
| + | - Allgemeines Benutzerhandbuch des HomeLab http:// | ||
| + | - Datenblatt des ATmega128 | ||
| + | - Dudziak, R., Köhn, C., Sell, R., Integrated Systems & Design, TUT Press, 2008 | ||
| + | - Friendenthal, | ||
| + | - Perens, A. Project Management, Külim, 1999 | ||
| + | - Bräunl, T. Embedded Robotics, Springer-Verlag, | ||
| + | ====== Ausblick ====== | ||
| + | |||
| + | Wenn Sie am Ende dieses Buches angelangt sind, haben Sie einige Kenntnisse sowie praktische Fähigkeiten in Bezug auf das Programmieren von Mikrocontrollern und den Umgang mit diversen Geräten erlangt, selbst wenn Sie nicht alle Übungsbeispiele absolviert haben. Wir hoffen, dass dieses Buch Sie bei der Bewältigung von Problemen sowie der Erlangung theoretischen Hintergrundwissens unterstützen konnte. Der nächste Schritt wäre nun, eigene intelligente Geräte zu entwickeln, die Ihren Interessen oder Bedürfnissen angepasst sind. Schüler und Studenten können sich darüber hinaus nach Robotikwettbewerben umsehen. Auf jeden Fall können Sie das erworbene Wissen dazu nutzen, Ihren Alltag einfacher und mit mehr Freude zu gestalten. Sie können einfache Sicherheitssysteme für Ihr Ferienhaus oder Ihre Garage entwickeln, die mit verschiedenen Sensoren arbeiten, um Einbrecher aufzuspüren und den Eigentümer zu warnen. Bei Problemen, fragen Sie um Hilfe. Dieses Buch wird sich ständig in seiner elektronischen Form weiter entwickeln. Es ist Teil eines Robotik-Studienkonzepts, | ||
| + | |||
| + | **Für Lehrer:** Registrieren Sie sich auf unserer Homepage und teilen Sie uns kurz mit, dass Sie Lehrer sind. Daraufhin werden Sie Zugriff auf die Lösungen der Übungsaufgaben sowie Antworten auf die Fragen am Ende jedes Übungsabschnittes erhalten. | ||
| + | |||
| + | {{ : | ||
| + | Homepage: \\ | ||
| + | http:// | ||
| + | |||
| + | --- | ||
| + | | ||