| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| de:avr:registers [2010/08/13 13:37] – Wember | de:avr:registers [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
|---|
| ====== Register ====== | ====== Register ====== |
| |
| Eins der schwersten Dinger die ein Anfänger verstehen kann im Bereich des Microcontrollers ist normalerweise das Register. Wenn man mit Microcontroller arbeitet ist es unmöglich darum zu kommen ohne zu wissen was Register sind. Dieses Buch ist da nicht anders, daher wird vom Leser erwartet sich mit dem Konzept der Register vertraut zu machen, der folgende Text versucht das mit möglichst einfachen Ausdrücken zu beschreiben, damit selbst ein Anfänger eine Idee davon bekommen kann was ein Register ist. | Typischerweise ist das Register eines der Bestandteile eines Mikrocontrollers, die ein Anfänger nur mühsam versteht. Im Umgang mit Mikrocontrollern ist es jedoch unumgänglich diese Komponente zu kennen. Auch für die weitere Arbeit mit diesem Buch ist der Leser dazu angehalten, sich das Konzept des Registers anzueignen. Daher wird es im nun folgenden Text auf eine möglichst verständliche Weise erklärt, sodass auch ein Anfänger ein Gespür für das Register bekommt. |
| |
| ===== Essence ===== | ===== Essence ===== |
| |
| [{{ :images:logic:tape_buttons.jpg?240|Tape player's buttons}}] | [{{ :images:logic:tape_buttons.jpg?240|Tasten eines Kassettenrekorders}}] |
| |
| Ein Register ist wie ein Feld von Knöpfen an einem Haushaltsgerät. Es hat Schalter welche An und Aus geschaltet werden könne. Als bestes Beispiel ist der Videorekorder. | 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: |
| Für die, die sich nicht mehr erinnern, der Rekorder hat/hatte sechs Knöpfe, von links nach rechts: | |
| |
| |
| * Record | * Aufnahme |
| * Rewind | * Zurückspulen |
| * Play | * Abspielen |
| * Fast forward | * Vorspulen |
| * Stop | * Stopp |
| * Pause | * Pause |
| |
| Jeder Knopf macht etwas bestimmtes, aber nur wenn er korrekt benutzt wird. Zum Beispiel der Stopknopf macht nichts, außer die Kassette spielt grade – nur dann wird der Knopf etwas bewirken und stoppt die Wiedergabe. Vor- und Zurückspul-Knöpfe, können jederzeit gedrückt werden, weil das Band in beide Richtungen gedreht werden kann, egal ob das Gerät grade abspielt oder gestoppt ist. Manche haben vielleicht versucht mehrere Knöpfe auf einmal, vielleicht sogar alle auf einmal zu drücken – in diesem Fall hat der Rekorder vielleicht was unvorhergesehendes getan, oder ist sogar kaputt gegangen. | 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. |
| |
| Microcontroller Register verhalten sich wie Knöpfe an einem Videorekorder – jeder Knopf mach etwas Bestimmtes, wenn er richtig benutzt wird. Drückt man den falschen Knopf , wird ein Microcontroller wahrscheinlich nicht kaputt gehen, aber er wird definitiv nicht funktionieren. In Wirklichkeit gibt es keine Knöpfe in den Register, sondern eine Menge an Transistoren, welche den Strom an- und ausstellen. Einfache Microcontroller haben acht Transistor-basierende Schalter in einem Register. Ein Register kann als 8-Bit Nummer gesehen werden, wo jeder Bit durch den Status eines der acht Schalter repräsentiert wird. | 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, aber er wird nicht funktionieren. Tatsächlich gibt es keine Tasten im Register sondern stattdessen eine Vielzahl von Transistoren, welche die Stromversorgung ein- und ausschalten. Einfachere Mikrocontroller haben 8 transistorbasierte Schalter in einem einzigen Register. Unter einem Register kann man sich eine 8-Bit Zahlenfolge vorstellen, wobei jedes Bit durch den Status eines dieser Schalter gekennzeichnet wird. Zum Beispiel kann ein Bit-Wert von 1 bedeuten, dass der Schalter an ist, ein Wert von 0 hieße dann, dass er aus ist. |
| Zum Beispiel ein Bit mit dem Wert 1 kann bedeuten der Schalter ist an und 0, dass der Schalter aus ist. | |
| |
| | [{{ :images:logic:register_buttons_and_bits.png?240|"Tasten" des Registers und Bitwerte}}] |
| |
| [{{ :images:logic:register_buttons_and_bits.png?240|Register's "buttons" and bit values}}] | Da der Status eines Registerschalters einfach durch eine Nummer abgebildet werden kann, lässt sich ein Register mit einem Speicher vergleichen, der Daten in Form genau einer Zahl speichern kann. Durch diesen Vergleich wird deutlich, dass Register tatsächlich Speicherslots sind. Der Unterschied zwischen einem Register und einem Speicherslot besteht darin, dass letzterer lediglich Informationen speichert, während die Informationen in einem Register tatsächlich etwas steuern. So sorgt zum Beispiel der Binärwert 01100001 in einem Register dafür, dass drei imaginäre Tasten betätigt werden wodurch eine Funktion ausgelöst wird. |
| |
| Da der Status der Registerschalter einfach als Nummer dargestellt werden kann und vice versa, kann ein Register mit einem Speicher verglichen werden, der Daten in der Größe einer Nummer halten kann. Mit diesem Vergleich wird deutlich, dass Register eigentlich SpeicherSlots sind. Der Unterschied zwischen Register und Speicher-Slot ist der, dass im Speicher-Slot nur etwas gespeichert wird, aber im Register die Information etwas kontrolliert. | |
| Zum Beispiel der Binärwert 01100001 wird in ein Register geschrieben dann werden drei imaginäre Knöpfe gedrückt und etwas Bestimmtes passiert. | |
| |
| |
| An einem Videorekorder ist es möglich jeden Knopf einzeln zu drücken, aber in einem Register ist es schwieriger den Wert eines „Schalters“ oder Bit zu ändern. Normalweise ist es notwendig den gesamten Inhalt des Register zu ändern. Bevor wir zum Ändern des Bit kommen, sollte man wissen, dass es im Microcontroller eine Menge Register gibt. Einige Teile eines Microcontroller benötigen mehr als zehn Register um kontrolliert zu werden. | |
| Die Vielfalt der Register bedeutet, dass es einen Weg geben muss, zwischen verschiedenen Registern zu unterscheiden. Das wird gemacht, in dem Man den Registern Namen gibt. | |
| Ein Register heißt z.B. PORTB. | |
| Eigentlich machen diese Namen es nur einfacherer für die Entwickler, jeder Name hat eine eigene numerische Addresse. | |
| |
| | Während es bei einem Kassettenrekorder möglich ist, jeden Knopf einzeln zu betätigen, ergeben sich bei einem Register Schwierigkeiten, wenn nur der Wert eines Schalters oder Bits geändert werden soll. Hier ist es gewöhnlich notwendig, den gesamten Inhalt der Registers zu ändern. Bevor jedoch detaillierter auf die Thematik der Bit-Veränderung eingegangen wird, muss zunächst klargestellt werden, dass ein Mikrocontroller mehrere Register enthält. Die Vielzahl der Register führt dazu, dass diese voneinander unterscheidbar gemacht werden müssen, was durch Kennzeichnung mit einem Namen geschieht, wie zum Beispiel „PORTB“. Hierdurch wird dem Entwickler die Arbeit erleichtert, da jedem Namen auch eine eigene numerische Adresse zugewiesen wird. |
| |
| ===== Gebrauch ===== | ===== Gebrauch ===== |
| |
| Um in ein Register zu schreiben, oder den Wert abzulesen, muss er mit einer Variable in C adressiert sein. Das folgende Beispiel demonstriert, wie man einen Binären Wert auf einen imaginären Register REG schreibt und dann die Variable //reg// ausliest. | Zur Programmierung eines Registers oder auch dazu, um Werte aus diesem abzulesen muss er als Variable in C deklariert werden. Das folgende Beispiel veranschaulicht, wie ein Binärwert einem imaginären Register REG zugewiesen wird und dann in der Variable //reg// abgelegt wird. Binärwerte werden an einem vorangestellten 0b (leading zero) erkannt, sodass der Compiler das binäre Zahlensystem erkennt. |
| Binäre Werte werden an einem 0b(leading zero) erkannt, so dass der Compiler das numerische System erkennt | |
| |
| <code c> | <code c> |
| </code> | </code> |
| |
| Es gibt nichts Schwieriges im Schreiben und Lesen von Register Werten, aber es wird ein wenig kniffelig, wenn man nur ein Bit ändern will. Um Bits zu ändern, muss man wissen wie binäre Rechnen funktioniert und unterschiedliche numerische System nutzt. Es ist zwar nicht verboten nur mit binären Nummern zu arbeiten, aber es kann sehr umständlich werden, weil binäre Nummern doch sehr lang werden, und das ist der Grund warum viele Menschen die kürzeren Hexadezimalzahlen nutzen. | 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. |
| |
| [{{ :images:logic:logic_hexadecimal.png?209|Hexadecimal numbers}}] | [{{ :images:logic:logic_hexadecimal.png?209|Hexadezimalzahlen}}] |
| |
| In Hexadezimal, gibt es nicht nur 0 und 1 wie im Binären, oder 0-9 wie im Dezimalsystem, sondern es geht von 0 bis F. Eine Hexadezimale Zahl besteht aus 4 Bits. Die Tabelle recht zeigt die Binärzahlen und ihre Hexadezimale Umrechnung. Binäre Zahlen werden zu hexadezimalen Zahlen konvertiert, in dem man 4 Bits auf einmal liest, und am niedrigsten Glied beginnt. Glieder werden von rechts nach links gelesen und starten bei 0, z.B. das niedrigstesten gegliederte (Glied/Rank 0) Bit ist 0 und das höchste (Glied/rank 3) ist 1. | Im Hexadezimalsystem gibt es nicht nur die Ziffern 0 und 1 wie im binären System oder 0 bis 9 gemäß dem Dezimalsystem, sondern stattdessen 0 bis F. Eine Hexadezimalzahl besteht aus vier Bits. Die Abbildung auf der rechten Seite veranschaulicht die Binärzahlen und deren zugehörige Hexadezimalwerte. Binärzahlen werden in Hexadezimalzahlen umgewandelt indem vier Bits zugleich, beginnend bei dem niedrigsten, gelesen werden. Die Bitfolge wird von links nach rechts gelesen und startet bei 0. So ist zum Beispiel das niederwertigste Bit (an Stelle 0) 0 und das mit dem höchsten Wert (an Stelle 3) 1. Im vorangehenden Beispiel ist der Binärwert der Registers 01100001, der im Hexadezimalsystem 61 entspricht und in C als 0x61 (leading zero) geschrieben wird. |
| Im vorhergegangen Beispiel war 01100001 der Binärwert des Registers, welches 61 in hexadezimal ist und wird 0x61 (leading zero) in C geschrieben. | |
| |
| Um ein einzelnes Bit in einer Nummer (Register, Variable oder wo auch immer) ist es notwenig Binäre Operationen zu nutzen. Eine binäre Operation ist eine Operationen zwischen zwei binären Zahlen, wo jeder Bit einer Zahl Objekt einer eigenen logischen Operation ist. | 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, wobei jedes Bit der Zahlen durch eine eigene logische Operation abgebildet wird. Mikrocontroller unterstützen generell vier unterschiedliche Binäroperationen. Der folgende Abschnitt beschreibt die logische Operation hinter diesen vier Binäroperationen mit einzelnen sowie mehreren Bits. |
| Normalweiser unterstützen Microcontroller vier Binäroperationen, jede mit vielen unterschiedlichen Namen. Der folgende Abschnitt beschreibt die logische Operation hinter den vier binären Operationen mit einem oder mehreren Bits. | |
| |
| [{{ :images:logic:logic_all_4.png?550 |Negation, logical multiplication, logical addition and exclusive disjunction }}] | [{{ :images:logic:logic_all_4.png?550 |Negation, logische Multiplikation, logische Addition und exklusive Disjunktion }}] |
| |
| ~~PB~~ | <pagebreak> |
| |
| * **Negation / Inversion** \\ Negation changes the bit's value to its opposite, a 0 becomes a 1 and vice versa. In C, negation is marked with "~". | * **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 "~" vorgenommen. |
| * **Logical multiplication / Conjunction** \\ When multiplying two bits, the answer is 1 if both bits are 1 and in any other case 0. In C, logical multiplication is marked with "&". | * **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 "&" dargestellt. |
| * **Logical addition / Disjunction** \\ When adding two bits, the answer is 1 if at least one of the bits is 1 and 0 if both bits are 0. In C, logical addition is marked with "|". | * **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 "|" die Logische Addition. |
| * **Exclusive disjunction / Exclusive OR / XOR** \\ Exclusive OR operation will return 1 if the two bits differ from each other (one is 1 and the other 0), otherwise the answer is 0. In C, exclusive disjunction is marked with "^". | * **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 "^" dargestellt. |
| |
| Dies ist alles was man wissen muss um ein einzelnes Bit zu ändern. Die Theorie ist wahrscheinlich nicht genug und daher gibt’s ein paar typische Beispiele mit Registern in den nächsten Absätzen | Man benötigt nicht mehr als diese vier Operationen, um einzelne Bits zu ändern. Da die Theorie allein vermutlich nicht ausreichen mag, enthalten die folgenden Abschnitte einige Anwendungsbeispiele. |
| |
| ~~CL~~ | ~~CL~~ |
| |
| ==== Setting a single bit high ==== | ==== Ein einzelnes Bit "high" setzen ==== |
| |
| [{{ :images:logic:op_bit_set.png?230|Setting a single bit high}}] | [{{ :images:logic:op_bit_set.png?230|Ein einzelnes Bit "high" setzen}}] |
| |
| Um einen oder mehrere Bits in einem Register high (1) zu setzen, ist eine logische Addition notwendig. Eine der Rechengrößen muss der Register sein und der andere eine binäre Zahl, wobei nur der high Bit der ist, der im register auf high gesetzt werden muss. Diese binäre Zahl nennt sich Bitmask. Unterhalb ist der C-Quellcode für die Operation auf der rechten Seite. | 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~~ | ~~CL~~ |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x0F | // Annahme REG = 0x0F |
| REG = REG | 0x11; // First method | REG = REG | 0x11; // Erste Methode |
| REG |= 0x11; // Second method | REG |= 0x11; // Zweite Methode |
| // Now REG = 0x1F | // Ergebnis REG = 0x1F |
| </code> | </code> |
| |
| ==== Setting a single bit low ==== | ==== Ein einzelnes Bit “low” setzen ==== |
| |
| [{{ :images:logic:op_bit_clear.png?229|Setting a single bit low}}] | [{{ :images:logic:op_bit_clear.png?229|Ein einzelnes Bit “low” setzen}}] |
| |
| Um ein oder mehrere Bits in einem register low (0) zu setzen, wird eine logische multiplikationsoperation benörtigt. Ein Operand der Operation muss der Register sein, der andere die Bitmaske, in welcher der einzige low Bit der sein muss | 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. |
| Unterhalb ist der C- Code für die Operation welche zur Rechten gezeigt wird: | |
| |
| ~~CL~~ | ~~CL~~ |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x0F | // Annahme REG = 0x0F |
| REG = REG & 0xFE; // First method | REG = REG & 0xFE; // Erste Methode |
| REG &= 0xFE; // Second method | REG &= 0xFE; // Zweite Methode |
| // Now REG = 0x0E | // Ergebnis REG = 0x0E |
| </code> | </code> |
| |
| ~~PB~~ | <pagebreak> |
| |
| ==== Ein Bit invertieren ==== | ==== Ein einzelnes Bit invertieren / umkehren ==== |
| |
| [{{ :images:logic:op_bit_invert.png?229|Inverting a single bit}}] | [{{ :images:logic:op_bit_invert.png?229|in einzelnes Bit invertieren}}] |
| |
| Um ein oder mehrere Bits in einem Register zu invertieren ist eine exklusive Trennungsoperation nötig. Einer der Operanden der Operation muss das Register sein, der andere die Bitmaske, wo das einzige High Bit das ist, was im Register invertiert werden soll. | 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: |
| Der C-code für die Operation für die Operation rechts ist: | |
| |
| ~~CL~~ | ~~CL~~ |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x0F | // Annahme REG = 0x0F |
| REG = REG ^ 0x11; // First method | REG = REG ^ 0x11; // Erste Methode |
| REG ^= 0x11; // Second method (use only one per inversion) | REG ^= 0x11; // Zweite Methode (nur eine pro Inversion verwenden) |
| // Now REG = 0x1E | // Ergebnis REG = 0x1E |
| </code> | </code> |
| |
| ==== Das ganze Register invertieren ==== | ==== Das gesamte Register invertieren ==== |
| |
| [{{ :images:logic:op_reg_invert.png?229|Inverting all bits}}] | [{{ :images:logic:op_reg_invert.png?229|Invertieren aller Bits}}] |
| |
| um alle Bits in einem Register zu invertieren wird eine Inversionsoperation genutzt. | 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: |
| Diese Operation ist unär, das bedeutet es hat nur einen Operanden. Unterhalb ist der C-Code für die Operation rechts: | |
| |
| |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x0F | // Annahme REG = 0x0F |
| REG = ~REG; | REG = ~REG; |
| // Now REG = 0xF0 | // Ergebnis REG = 0xF0 |
| </code> | </code> |
| |
| ==== Den Wert eines einzelnen Bits lesen ==== | ==== Den Wert eines einzelnen Bits auslesen ==== |
| |
| [{{ :images:logic:op_bit_get.png?229|Reading the value of a bit}}] | [{{ :images:logic:op_bit_get.png?229|Den Wert eines Bits auslesen}}] |
| |
| Um einen oder mehrere Bits aus ein Register zu lesen, muss man die gleiche Operation nutzen, als wenn man ein Bit low setzen möchte - logische multiplikation. Einer der Operanden der Operation ist das Register und der andere ist die Bitmaske, wo der einzige hohe Bit der ist, den man auslesen möchte. Unterhalb ist der C-Code für die Operation rechts: | 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. |
| |
| |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x0F | // Annahme REG = 0x0F |
| unsigned char x = REG & 0x01; | unsigned char x = REG & 0x01; |
| // Now x = 0x01 | // Ergebnis x = 0x01 |
| </code> | </code> |
| |
| ~~PB~~ | <pagebreak> |
| |
| ==== ein Bit schieben ==== | ==== Ein Bit verschieben ==== |
| |
| Viele Programmiersprachen haben ein paar zusätzliche Bitwise Operationen, welche es einfacher für Programmierer machen. Diese sind Bitshift Operationen die Bits nach links oder rechts in einer binären Nummer schieben. Der wichtigste Nutzen für Shiftoperationen ist, wenn man mit Register arbeitet und man Bitranks zu Bitmasken konvertieren will oder anders herum. | Viele Programmiersprachen verfügen mittlerweile über einige zusätzliche Bitoperationen, was die Programmierarbeit erleichtert. Hierzu gehören die Operationen, welche die Bits einer Binärzahl nach rechts oder links verschieben. Im Umgang mit Registern liegt der größte Vorteil dieser Operationen darin, dass Bitfolgen zu Bitmasken konvertiert werden können und umgekehrt. |
| |
| [{{ :images:logic:op_bit_shift_left.png?241|Shift left}}] | [{{ :images:logic:op_bit_shift_left.png?241|Linksshift}}] |
| |
| Das Bild rechts zeigt eine Linksshiftoperation. Auch wenn das Schieben von Bits keine logische Operation ist und kein dazugehöriges Symbol hat, wird es in C mit "<<" dargestellt. | 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 "<<" gekennzeichnet. Eine Linksshiftoperation wird genutzt, um eine Bitfolge in eine Bitmaske umzuwandeln. Um beispielsweise die Maske für das sechste Bit (Rang 5) zu erhalten, muss das erste Bit um fünf Stellen nach links verschoben werden. In C wird diese Operation wie folgt geschrieben: |
| Ein Linksshift wird genutzt um einen Bit Rank in einer Bitmaske zu transformieren. Zum Beispiel um die Maske für das 6. Bit (Rank 5) zu bekommen muss Nummer 1 5mal nach links geschoben werden. | |
| Die Beispiel Operation sieht in C wie folgt aus: | |
| |
| ~~CL~~ | ~~CL~~ |
| <code c> | <code c> |
| REG = 0x01 << 5; | REG = 0x01 << 5; |
| // Now REG = 0x20 | // Ergebnis REG = 0x20 |
| </code> | </code> |
| |
| [{{ :images:logic:op_bit_shift_right.png?241|Shift right}}] | [{{ :images:logic:op_bit_shift_right.png?241|Rechtsshift}}] |
| |
| Rechtsshiftoperation funktioniert ähnlich wie die Linksshiftoperation. Es wird in C mit ">>" dargestellt. Rechtsshift wird benutzt um den logischen Wert eines Bit von der Bitmaske zu bekommen. Ein Beispiel hat gezeigt wie man den Wert eines Bit ließt. Wenn das Bit, dass man lesen möchte, aber nicht den niedrigsten Rank hat, sondern zum Beispiel Rank 5, dann würde das Ergebnis 0x20 oder 0x00 sein, aber manchmal brauch man ein Ergebnis von 1 oder 0. Dann nutzt man einen Rechtsshift. Die Beispieloperation rechts sieht in C wie folgt aus: | Der Rechtsshift funktioniert auf die gleiche Weise und wird in C durch ">>" dargestellt. Rechtsshiftoperationen dienen dazu, den logischen Wert eines Bits aus der Bitmaske zu erhalten. An einem vorherigen Beispiel wurde bereits gezeigt, wie der Wert eines einzelnen Bits gelesen werden konnte. Ist dieses Bit nun nicht das niederwertigste, sondern zum Beispiel eines mit dem Rang 5, wäre das Ergebnis entweder 0x20 oder 0x00. Allerdings wird manchmal ein Ergebnis von 1 oder 0 benötigt und genau hier kommt die Rechtsshiftoperation zur Anwendung. Der Rechtsshift aus dem Beispiel rechts sieht in C folgendermaßen aus: |
| |
| ~~CL~~ | ~~CL~~ |
| |
| <code c> | <code c> |
| // Let's suppose REG = 0x20 | // Annahme REG = 0x20 |
| unsigned char x = REG >> 5; | unsigned char x = REG >> 5; |
| // Now x = 0x01 (or simply 1) | // Ergebnis x = 0x01 (or simply 1) |
| </code> | </code> |
| |
| Wenn ein Bit vom niedrigsten Rank nach rechts geschoben wird, oder vom höchsten Rank nach links, dann verschwindet es. Eine Programmiersprachen haben rotierende Bitshift Operationen, wo das Bit nicht verschwindet, sondern vom niedrigsten zum höchsten Rank wandert, oder umgekehrt. C hat diese Operation nicht, aber sie kann vom Programmierer selbstgeschrieben werden, falls man sie brauch. | 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, bei denen ein Bit nicht verschwindet, sondern vom niedrigsten zum höchsten Rang wandert oder umgekehrt. In C gibt es diese Operationen nicht, sie können jedoch bei Bedarf vom Programmierer selbst geschrieben werden. |
| |
| Alle Bitoperationen funktionieren nicht nur mit Registern, sondern auch mit Variablen und Konstanten. Die Konstanten können natürlich nur als Operanden genutzt werden. | Sämtliche Bitoperationen sind nicht nur mit Registern durchführbar, sondern auch mit Variablen und Konstanten. Letztere können jedoch ausschließlich als Operanden, nicht als Ergebnis genutzt werden. |
| |
| ===== AVR Register ===== | ===== AVR Register ===== |
| |
| Um etwas mit einem Register eines Microcontrollers zu machen, muss man wissen wir man diesen Microcontroller benutzt. Jeder Microcontroller kommt mit einem oder mehreren Datenblättern, welche die Struktur und Funktionalität des Microcontrollers beschreiben. Das Datenblatt beschreibt also die Register. Der folgende Absatz wird behilflich sein, die Registerbeschreibung im AVR Datenblatt zu verstehen. | 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, welche seine Struktur und Funktionalität beschreiben. Dieses Datenblatt enthält auch Informationen über die Register. Der folgende Abschnitt dient dazu, die Registerbeschreibungen der AVR Datenblätter zu verstehen. |
| | |
| | [{{ :images:logic:avr_example_register.png?580 |Eines der AVR Register, Datenblattansicht}}] |
| |
| [{{ :images:logic:avr_example_register.png?580 |One of AVRs registers from its datasheet}}] | 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, jedoch enthält der Name auch ein kleines n, welches den Index des Moduls kennzeichnet. Der ATmega128 verfügt über zwei nahezu identische USCART Module, die jedoch nicht getrennt beschrieben werden, sodass der Nutzer das n als 0 oder 1 lesen muss. Aus diesem Grund hat der ATmega128 die Register USCR0A und UCSR1A. |
| |
| Das Bild zeigt das UCSRnA Register des ATmega128 Microcontrollers. UCSRnA bedeutet "USAR Control und Status Register A". Das Register wird benutzt um das USART Modul des AVRs zu konfigurieren und den Status auszulesen. Alle AVR register namen werden in Grossbuchstaben geschrieben, aber es sollte auffallen dass auch ein kleines n im Namen ist. Ein kleines n markiert den Index eines Moduls. Da der ATmega128 zwei fast identische USART Module hat, werden sie nicht beide beschrieben, aber das n muss als 0 oder 1 vom Nutzer gelesen werden. | 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. Es gibt auch Ausnahmen, so sind einige Register 16-Bit groß, aber tatsächlich bestehen sie aus zwei 8-Bit Registern. So wie jedes Register einen Namen hat, hat auch jedes Bit innerhalb des Registers einen Namen – so wie die Tasten an einem Kassettenrekorder. Jedes Bit wird im Datenblatt beschrieben. Wie Registernamen sind Bitnamen ebenfalls Abkürzungen und das kleine n entspricht jeweils dem Modulindex. Einige Register nutzen weniger als 8 Bit, in diesem Fall ist das Feld eines solchen Bits mit einem Trennstrich markiert. |
| Daher hat der ATmega128 die register UCSR0A und UCSR1A. | |
| |
| Der Inhalt des Registers wird durch eine 8-Slot Box mit einer dicken Linie herum markiert. | 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, auch wenn das mit dem Programm versucht wurde. Durch Auslesen eines beschreibbaren Bits wird stets ein spezifischer Wert ausgegeben, der im Datenblatt angegeben ist. In der zweiten Zeile wird der Standardwert dargestellt, den das Bit nach dem Reset des Mikrocontrollers hat. |
| Jeder Slot markiert ein Bit. Bit Ranks weden über der Box markiert - aufsteigend von rechts nach links. Da der AVR ein 8-Bit Microcontroller ist, sind die meisten Register 8-Bit. | |
| Es gibt einige Ausnahmen, es gibt 16-Bit Register, aber das sind eigentlich zwei 8-Bit register. So wie jedes Register einen Namen hat, so hat auch jedes Bit im Register einen Namen - genau wie Knöpfe am Videorekorder. Jedes Bit wird im Datenblatt beschrieben. Bitnamen sind Abkürzungen und die kleinen n müssen mit dem Modulindex übereinstimmen, genau wie bei den Registernamen. Einige Register nutzen weniger als 8-Bit, dann werden die Bitslots mit einem Trennungsstrich markiert. | |
| |
| Unter den Register Bits sind zwei Linien, welche anzeigen ob das Bit Lesbar (R), Beschreibbar (W) oder beides ist (R/W). Zum Beispiel, die Stautsbits können nicht überschrieben werden, und selbst wenn es im Programm versucht wird, wird das Bit unverändert bleiben. Wenn das Bit als beschreibbar markiert wurde, wird das auslesen immer in einem spezifischen Wert der im Datenblatt angegeben wird enden. Die zweite Linie gibt den Standardwert des Bit, der Wert den es nach einem Reset des Microcontrollers hat. | 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. |
| |
| Während AVR Registernamen zu einer tatsächlichen Speicherslot Adresse zeigen, haben die Bitnamen die Ranknummer des jeweiligen 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> | <code c> |
| // Set TXC0 bit high | // Setze TXC0 Bit high |
| UCSR0A |= (1 << TXC0); | UCSR0A |= (1 << TXC0); |
| |
| // Set U2X0 bit low | // Setze U2X0 Bit low |
| UCSR0A &= ~(1 << U2X0); | UCSR0A &= ~(1 << U2X0); |
| |
| // Read the value of UDRE0 bit(mask) | // Lies den Wert aus UDRE0 Bit(Maske) |
| unsigned char u = (UCSR0A & (1 << UDRE0)); | unsigned char u = (UCSR0A & (1 << UDRE0)); |
| |
| // At this point u value is either 0 or 32, | // An dieser Stelle ist der Wert entweder 0 oder 32, |
| // which enables using it in a logical operation | // wodurch die Nutzung in einer logischen Operation aktiviert wird |
| if (u) | if (u) |
| { | { |
| // Invert MPCM0 bit | // Invertiere MPCM0 Bit |
| UCSR0A ^= (1 << MPCM0); | UCSR0A ^= (1 << MPCM0); |
| } | } |
| |
| // Sometimes it is necessary to acquire a specific 0 or 1 value, | // Manchmal ist es notwendig einen spezifischen 1 oder 0 Wert zu erhalten |
| // so the read bit needs to be shifted right | // Dazu muss das Bit nach rechts verschoben werden |
| u >>= UDRE0; | u >>= UDRE0; |
| |
| // Now the value of u is either 0 or 1 | // Nun ist der Wert entweder 0 oder 1 |
| </code> | </code> |
| |