4927 subscribers

Микроконтроллеры для начинающих. Часть 25. Условные переходы

302 full reads
817 story viewsUnique page visitors
302 read the story to the endThat's 37% of the total page views
2,5 minutes — average reading time

В предыдущей статье мы поговорили о командах перехода в общем и подробнее о безусловных переходах. Давайте теперь познакомимся с командами условного перехода.

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

Как видно из названия переходов - "условные" - понятно, что они должны эти условия проверять. Но что это за условия? В предыдущей статье я уже говорил, что чаще всего это флаги состояний процессора. Но не только.

Условия с флагами состояний

С точки зрения процессора условие это состояние одного или нескольких бит. Эти биты располагаются в регистрах процессора, причем не обязательно доступных программно. Давайте вспомним иллюстрацию из статьи "Микроконтроллеры для начинающих. Часть 14. Начинаем знакомство в системой команд. Флаги и статусы"

Иллюстрация флагов состояния из 14 части цикла статей
Иллюстрация флагов состояния из 14 части цикла статей
Иллюстрация флагов состояния из 14 части цикла статей

Эти флаги состояний связанны с результатом выполнения операций. Давайте посмотрим на работу команд условных переходов немного подробнее. Например, возьмем команду BREQ из микроконтроллеров AVR которая выполняет переход при установленном флаге Z

Микроконтроллеры для начинающих. Часть 25. Условные переходы

Здесь нет ничего нового и я уверен, что если не все, то большинство из вас это видели и знают. В документации команда BREQ обозначена как "переход если равно". Просто подразумевается, что она используется после команд сравнения (мы их уже рассматривали). Для не есть парная команда BRNE (переход если не равно).

Но если посмотреть на другие команды условных переходов AVR, то будет видно, что такая мнемоника несколько ограничена по смыслу. Больше подошли бы мнемоники BRZS и BRZC (бит Z установлен или сброшен). Тем более, что для других флагов используется именно такой подход.

А теперь давайте посмотрим на эту команду под несколько иным углом зрения. Чуть позже станет понятно, зачем это нужно

Микроконтроллеры для начинающих. Часть 25. Условные переходы

По сути, здесь нет отличий от предыдущей иллюстрации. На первый взгляд. Условие "проверка бита" вполне применимо к проверке флага состояния, так как флаги являются битами регистра состояния. А "GOTO label" является эквивалентом "переход на label". Нарисовано только немного странно... Но в общем ничего особенного.

На самом деле отличия тут есть, причем весьма существенные. Давайте с этим разберемся подробнее.

Условия как состояние бит

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

Флаги состояния, которые располагаются в регистрах состояния, не отражают полного состояния процессора. В частности, они не отражают, например, что процессор выполняет обработку прерывания или обработку сбоя по питанию.

Про прерывания будет отдельная статья, возможно даже несколько. Для сегодняшней статьи, что бы разобраться с условными переходами, нам будет достаточно лишь нескольких общих моментов. Прерывания могут возникать из-за внешних условий и при выполнении команд. Обработку большинства прерываний можно запретить, замаскировать. Большинство прерываний возникает асинхронно, то есть, независимо от хода выполнения программы.

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

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

Теперь становится понятной "проверка бита" в иллюстрации. Ведь условием может быть состояние любого бита любого регистра. И даже ячейки памяти данных.

Как вы помните, адрес бита задается как адрес байта и номер бита в этом байте. MCS-51 в данной статье я не буду затрагивать. При этом для большинства микроконтроллеров есть разница, где располагается байт, в регистре процессора, ячейке памяти данных, байте в пространстве ввода-вывода (для AVR).

В качестве примера опять возьмем микроконтроллеры AVR. А точнее, команду BREQ, которую уже рассматривали. Как вы помните, эта команда выполняет переход если Z=1. При этом флаг Z хранится в регистре состояния SREG в бите номер 1. А значит, мы можем воспользоваться командой BRBS, которая есть в системе команд AVR

BRBS 1, label

Команда BRBS проверяет состояние указанного бита в SREG и выполняет переход, если он установлен. В данной случае, мы проверяем бит номер 1 (Z).

Есть и парная команда BRBC, которая выполняет переход, если указанный бит сброшен.

Для AVR нет возможности задать бит в регистре отличном от SREG для этих команд. Но есть другие команды, которые мы рассмотрим чуть позже. Зато есть возможность проверки работы глобальным флагом разрешения прерываний командами BRID и BRIE.

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

BTJT $addr, #num, label

Эта команда проверит бит num в байте addr (адресация непосредственная) и выполнит переход на метку label, если этот бит установлен. Тоже самое, но для проверки сброшенного состояния бита можно сделать командой BTJF.

В микроконтроллерах PIC нет деления на регистры процессора и ячейки памяти данных. Вы же помните, что память данных в этих микроконтроллерах называется регистровым фалом? Исключением является WREG, к сожалению. Поэтому в PIC мы можем задать любой бит в почти любом байте. И даже, использовать для этого косвенную (индексную) адресацию через INDF. Только вот адрес перехода там нельзя задать... Почему так? Давайте и с этим разберемся.

Обобщенные условия и обобщенные переходы

С обобщенными условиями мы только что познакомились. А вот что за обобщенные переходы? Еще раз посмотрите на последнюю иллюстрацию. Мы добрались до "GOTO label".

Да, это "переход на label" в дословном переходе. Но это можно, и нужно, рассматривать и как некую отдельную команду. Причем не обязательно команду перехода. И "странная" иллюстрация показывает, что если условие выполняется, то эта отдельная команда тоже выполняется. А если условие на выполняется, то это команда пропускается!

Это, как показывает практика, самый сложный для новичков случай. Давайте остановимся на нем чуть подробнее. В качестве подопытной будет выступать команда BTFSC для микроконтроллеров PIC

BTFSC STATUS, 2

Эта команды выполнит проверку бита 2 регистра STATUS (это флаг Z). Если бит установлен, то следующая за BTFSC команды будет выполнена. Если же бит сброшен, то следующая за BTFSC команда будет пропущена. Фактически, эта команда просто будет заменена на NOP.

Давайте посмотрим, как для PIC будет выглядеть аналог команды BREQ, который мы уже рассматривали. Теперь нам потребуется две команды, а не одна.

BTFSC STATUS, 2

GOTO label

Эта последовательность команд выполнит переход, ели флаг Z установлен. И это полностью соответствует изображенному на последней иллюстрации.

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

BTFSC STATUS, 2

INC count

Не нужно никаких дополнительных меток и переходов после выполнения различных веток условных переходов. Счетчик будет увеличиваться только для ненулевых элементов, для нулевых операция инкремента будет пропускаться. Я оставил за рамками обсуждения перебор элементов и их проверку. Есть и парная команда BTFSS, которая пропускает следующую команду, если бит установлен.

Думаете, для других архитектур нет подобных команд? Ошибаетесь! Для AVR, который многие любят, есть команды SBRS и SBRC которые делают точно тоже самое, что и BTFSS на пару с BTFSC. Только здесь нет универсальности указания бита, он должен находиться в регистрах процессора.

Если в качестве условия нужно использовать бит в адресном пространстве ввода-вывода (регистры оборудования в AVR), то придется использовать команды SBIS и SBIC. При этом, как и для PIC, следующая за этими командами команда не обязательно должна быть командой безусловного перехода.

Специфические команды PIC

Я долго думал, где рассказать о двух специфических для PIC командах. Стоит ли им посвящать отдельную статью, или лучше отнести их к условным переходам. В конечном итоге, решил рассказать о них здесь.

Речь идет о командах INCFSZ и DECFSZ. Они предназначены для организации циклов и специфичны для PIC. Первая команда увеличивает на 1 указанный байт и пропускает следующую за ней команду, если в результате увеличения получили 0. Фактически, это переполнение байта, так как FFh+01h=00h. Вторая команды выполняет уменьшение на 1 указанного байта и пропускает следующую за ней команду, если в результате байт стал равен 0.

По своей сути, эти команды проверяют состояние флага Z, но перед этим выполняют дополнительные действия. Эти команды могут показаться излишними, так как прекрасно заменяются командами INCF или DECF и BTFSS. Но они занимают только одно слово в памяти программ и выполняются быстрее, что и служит причиной их существования.

Кроме этих команд есть и другие, специфичные уже только для PIC18. Я не буду рассматривать их отдельно, просто перечислю чуть позже в списке.

Ну вот мы и познакомились с тем, что это за команды условных такие и какие тут есть особенности и сложности. Осталось кратко перечислить все эти команды, так как все подробности нами рассмотрены.

Условные переходы PIC

BTFSS - проверка бита и пропуск следующей команды, если бит установлен

BTFSC - проверка бита и пропуск следующей команды, если бит сброшен.

BC - переход, если установлен флаг С (PIC18)

BNC - переход, если флаг С не установлен (PIC18)

BN - переход, если установлен флаг N (PIC18)

BNN - переход, если не установлен флаг N (PIC18)

BOV - переход, если установлен флаг OV (переполнение, PIC18)

BNOV - переход, если не установлен флаг OV (переполнение, PIC18)

BZ - переход, если установлен флаг Z (PIC18)

BNZ - переход, если флаг Z не установлен (PIC18)

INCFSZ - инкремент и пропуск следующей команды, если результат равен нулю

DECFSZ - декремент и пропуск следующей команды, если результат равен нулю

DCFSNZ - аналогична DECFSZ, но пропуск выполняется если результат не равен нулю (PIC18)

INFSNZ - аналогична INCFSZ, но пропуск выполняется если результат не равен нулю (PIC18)

TSTFSZ - проверка указанного байта, если он равен нулю следующая команда пропускается (PIC18)

Условные переходы STM8

JRC - переход, если флаг С установлен

JRNC - переход, если флаг С не установлен

JREQ - переход, если флаг Z установлен

JRNE - переход, если флаг Z не установлен

JRH - переход, если установлен флаг переноса между тетрадами

JRNH - переход, если не установлен флаг переноса между тетрадами

JRMI - переход, если установлен флаг N

JRPL - переход, если не установлен флаг N

JRV - переход, если установлен флаг V

JRNV - переход, если не установлен флаг V

JRIH - переход, если на входе прерывания высокий уровень (внимание, для STM8S001J команда не доступна из-за ошибки чипа, обходного пути нет)

JRIL - переход, если на входе прерывания низкий уровень (внимание, для STM8S001J команда не доступна из-за ошибки чипа, обходного пути нет)

JRM - переход, если прерывания замаскированы

JRNM - переход, если прерывания не замаскированы

JRSGE - переход, если больше или равно, знаковое

JRSGT - переход, если больше, знаковое

JRSLE - переход, если меньше или равно, знаковое

JRSLT - переход, если меньше, знаковое

JRUGE - переход, если больше или равно, беззнаковое

JRUGT - переход, если больше, беззнаковое

JRULE - переход, если меньше или равно, беззнаковое

JRULT - переход, если меньше, беззнаковое

BTJT - проверка бита и переход, если установлен

BTJF - проверка бита и переход, если сброшен

Условные переходы AVR

BRBS - переход, если бит в SREG установлен

BRBC - переход, если бит в SREG сброшен

BREQ - переход, если равно

BRNE - переход, если не равно

BRCS - переход, если флаг С установлен

BRCC - переход, если флаг С сброшен

BRSH - перход, если выше или равно, беззнаковое

BRLO - переход, если меньше, беззнаковое

BRMI - переход, если отрицательное

BRPL - переход, если положительное

BRGE - переходе, если больше или равно, знаковое

BRLT - переход, если меньше, знаковое

BRHS - переход, если установлен флаг переноса между тетрадами

BRHC - переход, если не установлен флаг переноса между тетрадами

BRTS - переход, если флаг Т (бит-копия) установлен

BRTC - переход, если флаг Т (бит-копия) сброшен

BRVS - переход, если установлен флаг V

BRVС - переход, если флаг V сброшен

BRIE - переход, если прерывания разрешены

BRID - переход, если прерывания запрещены

CPSE - сравнение двух байт, пропуск следующей команды, если равны

SBRC - пропуск следующей команды, если указанный бит в регистре процессора сброшен

SBRS - пропуск следующей команды, если указанный бит в регистре процессора установлен

SBIC - пропуск следующей команды, если указанный бит в пространстве ввода-вывода сброшен

SBIS - пропуск следующей команды, если указанный бит в пространстве ввода-вывода установлен

Заключение

Команды условных переходов сложны скорее своим многообразием, чем сложностью действий. Но разобраться и освоиться с ними не так и сложно. Я постарался показать, насколько все логично и насколько похоже даже в разных семействах микроконтроллеров. Если что то осталось непомнятным, или возникли вопросы, пишите в комменатриях. Постараюсь, как всегда, подробнее обхяснить непонятное и ответиь на все вопросы.

В следующий раз поговорим о командах работы с подпрограммами и прерываниями. Это будет не менее интересно.

До новых встреч!