This is an old revision of the document!


Registers

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.

Essence

Tape player's buttons

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. Für die, die sich nicht mehr erinnern, der Rekorder hat/hatte sechs Knöpfe, von links nach rechts:

  • Record
  • Rewind
  • Play
  • Fast forward
  • Stop
  • 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.

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. Zum Beispiel ein Bit mit dem Wert 1 kann bedeuten der Schalter ist an und 0, dass der Schalter aus ist.

Register's “buttons” and bit values

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.

Usage

Um auf 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. Binäre Werte werden an einem 0b(leading zero) erkannt, so dass der Compiler das numerische System erkennt

  REG = 0b01100001;
  unsigned char reg = REG;

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.

Hexadecimal numbers

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 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. 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.

Negation, logical multiplication, logical addition and exclusive disjunction

 

  • 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 “~”.
  • 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 “&”.
  • 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 “|”.
  • 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 “^”.

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

Setting a single bit high

Setting a single bit high

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

  // Let's suppose REG = 0x0F
  REG = REG | 0x11; // First method
  REG |= 0x11;      // Second method
  // Now REG = 0x1F

Setting a single bit low

Setting a single bit low

To set one or more bits in a register low (0) a logical multiplication operation is needed. One operand of the operation must be the register and the other a bitmask, in which the only low bit is the one that needs to be set low in the register. Below is the C code for the operation shown on the right:

  // Let's suppose REG = 0x0F
  REG = REG & 0xFE; // First method
  REG &= 0xFE;      // Second method
  // Now REG = 0x0E

 

Inverting a single bit

Inverting a single bit

To invert one or more bits in a register an exclusive disjunction operation is required. One of the operands of the operation must be the register and the other a bitmask, where the only high bit is the one that needs to be inverted in the register. Below is the C code for the operation shown on the right:

  // Let's suppose REG = 0x0F
  REG = REG ^ 0x11; // First method
  REG ^= 0x11;      // Second method (use only one per inversion)
  // Now REG = 0x1E

Inverting the whole register

Inverting all bits

To invert all bits in a register a negation operation is used. This operation is unary, which means it has only one operand. Below is the C code for the operation shown on the right:

  // Let's suppose REG = 0x0F
  REG = ~REG;
  // Now REG = 0xF0

Reading the value of a single bit

Reading the value of a bit

To read one or more bits from a register the same operation is required as was used for setting a bit low - logical multiplication. One of the operands of the operation must be the register and the other a bitmask, where the only high bit is the one that needs to be read from the register. Below is the C code for the operation shown on the right:

  // Let's suppose REG = 0x0F
  unsigned char x = REG & 0x01;
  // Now x = 0x01

 

Shifting a bit

Many programming languages actually have a few additional bitwise operations, which make it easier for the programmers. These are bit shifting operations that shift bits left or right in a binary number. The main value of shift operations in dealing with registers is their ability to convert bit ranks to bitmasks and vice versa.

Shift left

The image on the right shows a shift left operation. Although bit shifting is not a logical operation and has no corresponding symbol, in C it is marked as “«”. Shift left is used to transform a bit rank to a bitmask. For example, to get the mask for the 6th bit (NB! rank 5), number 1 has to be shifted left 5 times. The example operation looks like this in C:

REG = 0x01 << 5;
// Now REG = 0x20
Shift right

Shift right operation works similarly to shift left operation. It is marked as “»” in C. Right shift is used to get the logical value of a bit from a bitmask. A leading example showed how to read the value of a single bit. Let's suppose the bit to read is not of the lowest rank, but for example of rank 5. In this case, the result would be either 0x20 or 0x00, but sometimes a result of 1 or 0 is needed and that is when the right shift comes to the rescue. The example operation on the right looks like this in C:

// Let's suppose REG = 0x20
unsigned char x = REG >> 5;
// Now x = 0x01 (or simply 1)

If a bit is shifted right from the lowest rank or left from the highest rank by the bit shifting operation, it disappears. Some programming languages also have rotating bit shift operations, where the bit doesn't disappear, but moves from the lowest rank to the highest or vice versa. C doesn't have that kind of bit shift operations, but they can be written by the programmer if needed.

All bit operations work with not only registers, but with variables and constants as well. The latter can of course only be used as operands and not the result.

AVR registers

To do anything actual with the microcontroller's registers, one needs to know how to use that particular microcontroller. Each microcontroller comes with one or several datasheets, which describe the whole structure and functionality or the microcontroller. The datasheet also describes the registers. The following will help understand the register descriptions in AVR datasheets.

One of AVRs registers from its datasheet

The image shows ATmega128 microcontroller's UCSRnA register, which stands for “USART Control and Status Register A”. This register is used to configure AVR's USART module and read its states. All AVR register names are written in capital letters, but as the reader might notice, the register name contains also a lower case n. A lower n is used to mark some module's index. Since ATmega128 has 2 almost identical USART modules, they are not described twice, but only once and the n must be read as 0 or 1 by the user. Therefore ATmega128 has registers UCSR0A and UCSR1A.

The content of the register is marked by an 8-slot box with a bold line around it. Each slot marks one bit. Bit ranks are marked above the box - increasing from right to left. Since AVR is an 8-bit microcontroller, most of the registers are 8-bit as well. There are some exceptions, a few registers are 16-bit, but they actually consist of two 8-bit registers. Like each register has a name, each bit in the register has also a name - just like the buttons on a tape player. Each bit is described in the datasheet. Bit names are abbreviations as well and the lower n must be substituted with the module's index, just like with register names. Some registers don't use all 8 bits, in this case the bit's slot is marked with a hyphen.

Below the register's bits are two lines, which state whether the bit is readable (R), writable (W) or both (R/W). For example, the status bits can't be overwritten and even if it's attempted in the program, the bit will remain unchanged. If the bit is marked as writable, reading it will always result in one specific value stated in the datasheet. The second line specifies the default value of the bit, which it has after the reset of the microcontroller.

While AVR register names point to an actual memory slot address, the bit names hold the rank number of the corresponding bit. Therefore it is necessary to transform the names to bitmasks using a shift operation, in order to manipulate with bits in a register. The following code contains a few example lines for using the USART 0 module's register.

  // Set TXC0 bit high
  UCSR0A |= (1 << TXC0);
 
  // Set U2X0 bit low
  UCSR0A &= ~(1 << U2X0);
 
  // Read the value of UDRE0 bit(mask)
  unsigned char u = (UCSR0A & (1 << UDRE0));
 
  // At this point u value is either 0 or 32,
  // which enables using it in a logical operation
  if (u)
  {
     // Invert MPCM0 bit
     UCSR0A ^= (1 << MPCM0);
  }
 
  // Sometimes it is necessary to acquire a specific 0 or 1 value,
  // so the read bit needs to be shifted right
  u >>= UDRE0;
 
  // Now the value of u is either 0 or 1
de/avr/registers.1277919087.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0