This is an old revision of the document!


Регистры

Зачастую для начинающих «регистр» является наиболее сложно усваиваемой частью у микроконтроллеров. К сожалению, без этого понятия никак не обойтись, если есть желание заниматься микроконтроллерами. Для того, чтобы читатель смог ознакомиться с понятием регистра, данный материал упрощён до уровня начинающего.

Суть

Кнопки кассетного выключателя

Регистры можно сравнить с кнопочной панелью какого-либо домашнего устройства, где есть выключатели, которые можно включать и выключать. К примеру, кассетный магнитофон, который имел 6 кнопок:

  • Запись
  • Перемотка назад
  • Воспроизведение
  • Перемотка вперед
  • Стоп
  • Пауза

Каждая кнопка имеет свое предназначение, но только при правильном использовании. К примеру, кнопка «Стоп» не делает ничего раньше того, как запустить играть кассету, только после этого она сможет что-либо сделать – останавливает игру кассеты. Кнопки перемотки «Вперед» или «Назад» можно в любой момент нажимать, т.к. лента начнет крутиться как во время игры кассеты, так и во время стопа. Запись магнитофона начнется только в том случае, если нажать кнопку «Запись» вместе с кнопкой «Воспроизведение».

У регистров микроконтроллера, также как и у кнопок кассетного магнитофона, есть свои определенные функции. Конечно, в регистрах таких кнопок, как у магнитофона нет, но существует множество транзисторов, которые включают и выключают электричество. У простейших микропроцессоров регистр состоит из электрических выключателей основанных на 8 транзисторах. Регистр можно рассмотреть на примере 8-битной системе счисления, где каждый бит указывает на состояние кнопки. К примеру, значение бита 1 указывает на включенную кнопку, а 0 – на выключенную.

Положения «электрических выключателей» регистра и их битовые значения

Поскольку состояние выключателей регистра можно сравнить с числами и наоборот, то регистр можно сравнить с памятью, которая способна хранить данные размером в одно число. Благодаря этим сравнениям, мы пришли к тому, что на самом деле регистры это и есть ячейки памяти. Задача ячейки памяти заключается обычно в том, чтобы хранить информацию, а в регистре эта информация чем-либо управляет. Если, в изображённый на рисунке регистр, вписать битовое значение 01100001, то 3 воображаемых выключателя нажимаются и что-то начинает происходить.

Если у кассетного магнитофона каждую кнопку можно включать по отдельности, то в регистрах изменение одного «выключателя» или бита происходит сложнее. В любом случае придётся изменить содержание всего регистра разом. Прежде чем говорить об изменении битов, необходимо знать, что регистров у микроконтроллеров много. Для управления некоторых частей микроконтроллера могут использоваться десятки регистров. Обилие регистров означает то, что их необходимо как-то различать. Для этого используются имена, например, название одного из регистров - PORTB. На самом деле имена регистров придуманы для упрощения работы разработчиков и всего лишь замещают цифровые адреса.

Использование

В программе языка Си для записывания или чтения значения регистра необходимо к нему обратиться как к переменной. Следующий пример демонстрирует запись бинарного значения в выдуманный регистр REG и чтение этого значения в переменную reg. Перед бинарным значением пишется 0b (впереди ноль), чтобы компилятор понял систему счисления.

  REG = 0b01100001;
  unsigned char reg = REG;

В записи и чтении значений регистров ничего сложного нет, сложность появляется тогда, когда необходимо изменить значение отдельных битов в регистре. Для изменения битов сначала необходимо изучить бинарные операции и различные системы счисления. Никто не запрещает использовать бинарные числа, но работа с ними неудобна в связи с их длиной и обычно используют шестнадцатеричные числа, которые короче.

Шестнадцатеричные числа

В отличие от бинарной системы, где числа 0 и 1 или от десятичной системы, где числа от 0 до 9, в шестнадцатеричной системе – от 0 до F. Одно шестнадцатеричное число образуется из четырех битов. На приведённой таблице показаны шестнадцатеричные числа и соответствующие им бинарные числа. Очерёдность их считывания слева направо и их нумерация начинается с нуля. Впереди приведено бинарное значение регистра 01100001, которое в шестнадцатеричной системе счисления соответствует 61, а на языке Си пишется как 0x61 (впереди ноль).

Для изменения отдельных битов в числе (регистре, переменной или где-либо ещё), нужно использовать бинарные операции. Бинарная операция - это операция между бинарными числами, где между битами этих чисел происходят отдельные логические операции. В большинстве микроконтроллеров используется четыре бинарных операции, у каждой из которых несколько названий. Далее приведена соответствующая всем четырём бинарным операциям логическая операция с отдельным битом или битами.

Отрицание, логическое умножение, логическое сложение и неравнозначность

 

  • Отрицание / Инверсия
    Отрицание изменяет значение бита на противоположное, т.е. 0 меняется на 1 и 1 меняется на 0. На языке Си знак отрицания “~“.
  • Логическое умножение / Конъюнкция
    При умножении двух битов ответ будет 1, только в случае, если оба бита были 1, во всех других случаях ответ будет 0. В языке Си знак умножения “&“.
  • Логическое сложение / Дизъюнкция
    При сложении двух битов ответ будет 1, если хотя бы значение одного бита 1, во всех других случаях ответ будет 0. В языке Си знак сложения „|“.
  • Неравнозначность / Исключающая дизъюнкция
    При операции неравнозначности между двумя битами ответ будет 1, если значения битов отличаются друг от друга, во всех других случаях ответ будет 0. В языке Си знак неравнозначности “^”.

Всё вышеприведённое необходимо для изменения значений отдельных битов. Но одной лишь теории будет недостаточно, поэтому далее приведены некоторые типичные примеры с регистрами.

Настройка отдельного бита высоким

Операция настройки бита высоким

Для того, чтобы один или несколько битов в регистре настроить высокими т.е. единицей, необходимо использовать операцию логического сложения. Один операнд операции сложения должен быть регистром, второй бинарным числом, где высокий только тот бит, который желают настроить высоким и в регистре. Это второе бинарное число называют битовой маской. Рядом изображенная операция на языке Си выглядит следующим образом:

  // Предположим, что REG = 0x0F
  REG = REG | 0x11; // Первый метод
  REG |= 0x11;      // Второй метод
  // Здесь REG = 0x1F

Настройка отдельного бита низким

Операция настройки бита низким

Для того, чтобы один или несколько битов настроить низкими, т.е. нулём, необходимо использовать операцию логического умножения. Один операнд операции должен быть регистром, другой битовой маской, где низким настроен только тот бит, который желают настроить низким и в регистре. Изображённая рядом операция на языке Си выглядит следующим образом:

  // Предположим, что REG = 0x0F
  REG = REG & 0xFE; // Первый метод
  REG &= 0xFE;      // Второй метод
  // Здесь REG = 0x0E

 

Операция инвертирования бита

Операция инвертирования бита

Для инвертирования одного или нескольких битов в регистре необходимо использовать операцию неравнозначности. Один из операндов операции должен быть регистром, второй битовой маской, где высоким настроен только тот бит, который желают инвертировать и в регистре. Операция, изображенная рядом, на языке Си выглядит следующим образом:

  // Oletame, et REG = 0x0F
  REG = REG ^ 0x11; // Üks meetod 
  REG ^= 0x11;      // Teine meetod (rakendada tohib korraga ainult üht)
  // Siinkohal REG = 0x1E

Kogu registri inverteerimine

Bittide inverteerimise tehe

Kogu registri bittide inverteerimiseks tuleb kasutada eitustehet. See on unaarne tehe ehk tal on ainult üks operand. Kõrvalnäites toodud tehe näeb C-keeles välja niimoodi:

  // Oletame, et REG = 0x0F
  REG = ~REG;
  // Siinkohal REG = 0xF0

Üksiku biti väärtuse lugemine

Biti lugemise tehe

Ühe või enam biti väärtuse lugemiseks registrist tuleb kasutada sama tehet, mis biti nullimisel - loogilist korrutamist. Tehte üks operand peab olema register, teine bitimask, kus kõrgeks on seatud vaid see bitt, mille väärtust registrist lugeda soovitakse. Kõrvalnäites toodud tehe näeb C-keeles välja järgmiselt:

  // Oletame, et REG = 0x0F
  unsigned char x = REG & 0x01;
  // Siinkohal x = 0x01

 

Biti nihutamine

Tegelikult on paljudes programmeerimiskeeltes peale binaartehete veel mõned bitioperatsioonid, mis teevad programeerija elu lihtsamaks. Need on bitinihutuse operatsioonid, mis binaararvus nihutavad bitte kas vasakule või paremale poole. Nihutusoperatsioonide põhiline väärtus seisneb registritega tegeldes nende võimes bitijärkusid bitimaskiks teisendada ja vastupidi.

Bitinihe vasakule

Kõrvaloleval pildil on toodud näide bitinihutuse operatsioonist vasakule. Bitinihutus pole loogikaoperatsioon ja sel puudub vastav tähis, C-keeles on see aga “«”. Nihet vasakule kasutatakse bitijärgu bitimaskiks teisendamiseks. Näiteks, kui soovitakse kuuenda biti (NB! järk on 5) maski, siis tuleb arvu 1 nihutada vasakule 5 korda. Näites toodud operatsioon näeb C-keeles välja järgmiselt:

REG = 0x01 << 5;
// Siinkohal REG = 0x20
Bitinihe paremale

Sarnaselt bitinihkega vasakule toimib ka bitinihke operatsioon paremale. Selle operatsiooni tähis C-keeles on “»”. Nihet paremale kasutatakse bitimaskist biti loogilise väärtuse leidmiseks. Eespool oli toodud näiteks üksiku biti väärtuse lugemise tehe. Oletame, et bitt, mida lugeda, pole aga madalaima järguga, vaid näiteks järguga 5. Sel juhul oleks lugemisel vastus kas 0x20 või 0x00, kuid vahel läheb vaja vastust 1 või 0 ja siis tulebki appi nihe paremale. Kõrvalnäites toodud operatsioon näeb C-keeles välja nii:

// Oletame, et REG väärtus on 0x20
unsigned char x = REG >> 5;
// Siinkohal on x väärtus 0x01 (ehk lihtsalt 1)

Kui bitinihke operatsioonidega nihkub bitt madalaimast järgust paremale või kõrgeimast järgust vasakule, siis see bitt kaob. Mõnedes programmeerimiskeeltes on olemas ka roteeruvad bitinihke operatsioonid, kus “servast” välja minev bitt tuleb teiselt poolt tagasi. C-keeles roteeruvad bitinihke operatsioonid puuduvad, kuid vajadusel saab need ise kirjutada.

Kõik toodud bitioperatsioonide näited toimivad peale registrite ka muutujatega ja konstantidega. Viimased saavad muidugi ainult operandideks, mitte vastusteks olla.

AVR registrid

Selleks et midagi reaalselt mikrokontrolleri registritega teha saaks, tuleb osata selle mikrokontrolleriga läbi saada. Kõigi mikrokontrolleritega käib kaasas üks või mitu andmelehte, kus on dokumenteeritud kogu mikrokontrolleri struktuur ja funktsionaalsus. Andmelehes on kirjeldatud ka registrid. Järgnevalt uurime, kuidas saada aru AVR-i andmelehe registrite kirjeldusest.

Üks AVR register selle andmelehest

Pildil on toodud ATmega128 mikrokontrolleri register UCSRnA, mille pikem nimetus on “USART Control and Status Register A”. See on register, millega sätitakse AVR-i USART moodulit ja kust saab lugeda selle mooduli olekuid. Kõik AVR-i registrite nimed kirjutatakse suurte tähtedega, kuid tähelepanelik lugeja ilmselt märkab, et selles registris on väike n-täht. Väikese n-tähega tähistatakse nimelt mõne mooduli indeksit. Kuna ATmega128-s on 2 üsna sarnast USART moodulit, siis ei kirjeldata nende registreid topelt, vaid ühe korra ja n-tähe asemele peab lugeja arvestama kas “0” või “1”. Seega ATmega128-s on registrid UCSR0A ja UCSR1A.

Registri sisu tähistab paksu piirjoonega 8 lahtriga kast. Iga lahter tähistab üht bitti. Kasti kohal on toodud biti järgud - suurenevad paremalt vasakule. Kuna AVR on 8-bitine mikrokontroller, on ka enamik registreid 8-bitised. Mõningad erandid on 16-bitised registrid, mis koosnevad tegelikult kahest 8-bitisest registrist. Lisaks registritele on nimi ka igal registri bitil - täpselt nagu kassetimängija nuppudelgi. Iga biti kohta on andmelehes olemas selle selgitus. Biti nimed on samuti lühendid ja n-täht neis tuleb samuti asendada mooduli indeksiga. Mõnes registris pole kõiki 8 bitti kasutatud ja sel juhul tähistatakse biti lahter sidekriipsuga.

Registri bittide all on toodud kaks rida, kus on kirjas, kas bitt on loetav (R), kirjutatav (W) või mõlemat (R/W). Näiteks olekubitte ei saa üle kirjutada ja isegi siis, kui seda programmis üritada, ei omanda bit lihtsalt talle omistatavat väärtust. Biti puhul, mida saab ainult kirjutada, on öeldud üks kindel väärtus, mis selle lugemisel alati tuleb. Bittide all teises reas on toodud vaikeväärtus, mis on bitil pärast mikrokontrolleri käivitamist (inglise keeles reset).

Kui AVR-i registrite nimed viitavad tegelikult mälupesade aadressidele, siis biti nimede taga peitub selle biti järgu number. Seega registris bittidega manipuleerimiseks tuleb bitinimed nihutusoperatsiooni abil bitimaskiks teisendada. Järgnevalt on toodud mõned C-keele näitelaused eeltoodud USART 0 mooduli registri kasutamiseks.

  // TXC0 biti kõrgeks seadmine
  UCSR0A |= (1 << TXC0);
 
  // U2X0 biti madalaks seadmine
  UCSR0A &= ~(1 << U2X0);
 
  // UDRE0 biti(maski) väärtuse lugemine
  unsigned char u = (UCSR0A & (1 << UDRE0));
 
  // Siinkohal on u väärtus kas 0 või 32,
  // mis võimaldab seda loogilises avaldises kasutada
  if (u)
  {
     // MPCM0 biti inverteerimine
     UCSR0A ^= (1 << MPCM0);
  }
 
  // Mõnikord on aga vaja saada konkreetne 0 või 1 väärtus,
  // selleks tuleb loetud bitti nihutada paremale
  u >>= UDRE0;
 
  // Siinkohal on u väärtus kas 0 või 1
ru/avr/registers.1376405861.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