Что значит с флагом v программирование

Персональная страничка
Диканева Тараса
Викторовича

7.1. Переменные-флаги: теория

Флаг – это полотнище правильной (как правило, прямоугольной) формы прикрепленное к древку или поднимаемое на специальной мачте (флагштоке). Исторически флаги появились для передачи простых сигналов на поле боя. Например: подняли флаг, и конница понеслась в атаку! Как-то так. В простейшем случае с помощью флага передается информация объемом 1 бит (одно из двух: флаг поднят или нет).

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

1) Подводится баланс коммерческого предприятия. Дальнейшие действия могут зависеть от того, будет он положительным или отрицательным. Если отрицательный, надо просить кредит, положительный – планировать отдых на Багамах. В общем, самая существенная информация может быть передана одним битом.

2) Решаем квадратное уравнение. Если дискриминант не отрицательный – ищем корни. Для хода вычислительного важен факт не отрицательности, который также содержит 1 бит информации и может, таким образом, быть сохранен с помощью логической переменной.

3) Детям на уроке физкультуры велено построиться по росту. Если они построились не по росту, надо на них наорать. Опять действия учителя зависят от информации объемом 1 бит.

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

Читайте также:  Оцинкованный кузов что это значит

Пример 1. Решение квадратного уравнения.

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

Переменная-флаг передает информацию о наличии корней. С ее помощью первый блок сигнализирует второму блоку. Вы скажете, почему бы второму программисту вместо строчки

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

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

Представьте себе, что вам требуется написать программу размером несколько тысяч строк (это сравнительно небольшая программа). Есть единственный способ создавать программы такого размера – это разбиение решаемой задачи на подзадачи и написание отдельных блоков программы, решающих каждый свою подзадачу. Чтобы можно было сосредоточиться на решении отдельной подзадачи надо сделать их решение по возможности максимально независимым друг от друга. Для этого от одного блока к другому должно передаваться как можно меньше информации. Так что даже если программу пишет всего один человек, флаги облегчат его работу.

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

В дополнение еще один пример.

Пример 2. Проверка упорядоченности последовательности.

Пользователь вводит 10 чисел. Требуется проверить, упорядочены ли они по возрастанию, и передать эту информацию с помощью переменной флага.

Если очередное введенное число (x) будет меньше предыдущего (x2), то флаг примет значение false и сохранит это значение до конца цикла.

Блоки, передающие друг другу информацию с помощью флагов, не обязательно должны идти последовательно друг за другом. Можно представить себе ситуацию, когда один блок является составной частью другого. Например:

Пример 3: Найти все простые числа от 1 до N.

Число называется простым, если не делится ни на какое другое число кроме 1 и самого себя. Простейший алгоритм поиска таких чисел состоит в том, чтобы перебрать все числа и для каждого проверить наличие делителей. Поиск делителей можно мыслить себе как отдельный блок программы, результатом работы которого будет присваивание значения флаговой переменной.
Блок поиска простых чисел будет включать в себя блок проверки на наличие делителей.
Программную реализацию этого алгоритма выполните в качестве самостоятельного упражнения (см. задачу 7.1).

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

Источник

Электроника для всех

Блог о электронике

AVR. Учебный курс. Флаги и условные переходы

Есть в AVR (да и, пожалуй, во всех остальных процессорах) особый регистр SREG. О нем я несколько раз упоминал в прошлых статьях, но не вдавался в подробности. Чтож, пришло время рассказать, что же это же SREG такой и зачем он нужен.

SREG это регистр состояния ядра. Он так называется Status Register. В этом регистре находится независимых битов — флажков. Которые могут быть либо 1 либо 0, в зависимости от выполненных в прошлом операций.

И вот по тому какие флаги стоят, можно понять что произошло с процессором и что нам дальше делать.

Например, если флаг Z (Zero) выставлен в 1, значит в ходе вычисления предыдущей математической операции в результате образовался ноль.

А если выставлен флаг С (Carry — заем, перенос), то мы из меньшего числа отняли большее, или же прибавили такое число, что результат стал больше 255.

А теперь подробней по каждому флагу.

  • I — флаг разрешения прерываний. Когда установлен в 1 — прерывания разрешены.
  • T — пользовательский флаг. Можно юзать по своему назначению.

Кроме того, есть две команды которые позволяют в этот бит записать любой бит любого из 32 регистров общего назначения R0-R31 (далее буду их звать РОН). Это команды BLD Rn,bit и BST Rn,bit

Число в дополнительном коде с заемом — самая естественная форма представления числа во вселенной! Вот возьмем, например, число -61 как его получить? Ну не знаем мы про отрицательные числа! Просто! Вычтем его из нуля 00 — 61 = 39 Во как! Заняли из старшего разряда! Не похоже, да? Хорошо, проверим столбиком:
61
+
39

00 А единичка не влезла в разрядность!

ЧТД. (с) Лохов С.П. (Наш преподаватель по ассемблеру в универе)

Вот двоичный доп код работает точно по такому же принципу. А в процессоре есть команды для перевода числа из в доп код за одну команду.

Флаги, кроме автоматической установки, можно устанавливать и сбрасывать вручную. Для этого есть команды

SE* для установки и CL* для сброса. Вместо звездочки подставляется нужный флаг, например, CLI — запрет прерываний.

В даташите, в разделе Instruction Set Summary, написано какая команда что делает и на какие флаги влияет.

INC Rd Increment Rd = Rd + 1 Z,N,V DEC Rd Decrement Rd = Rd − 1 Z,N,V TST Rd Test for Zero or Minus Rd = Rd AND Rd Z,N,V CLR Rd Clear Register Rd = Rd XOR Rd Z,N,V SER Rd Set Register Rd = $FF None

Команда INC прибавляет к регистру 1, но несмотря на то, что она может добить регистр до переполнения, флаг переполнения С она не ставит. Такая особенность.

Зато она ставит флаги нуля, отрицательного значения и переполнения доп кода. Как инкремент может дать нуль? Элементарно, прибавив к -1 +1. Минус 1 в двоичной знаковой арифметике = FF. FF+1=1 00 ,но 1 не влезла в разрядность, поэтому 00 Логично же? 🙂

Или хотим мы, например, узнать в каком регистре число больше в R17 или R18

Нет ничего проще — к нашим услугам команда CP (нет, не детское порно, а Compare). Эта команда, у себя в уме, из R17 вычитает R18 при этом содержимое регистров не меняется, а меняются только флаги. И если, например, выскочил флаг С, значит при R17-R18 произошел заем, а значит R18 больше R17. Если флаг С не появился, то значит R17 больше чем R18. А коли у нас выскочил нуль, то значения равны. Есть еще команда CPI Rn,### работает также, но сравнивает регистр (только старшую группу) с произвольным числом. Используется чаще.

А потом смотрим флаги. И дальше в ход вступают команды условных переходов из группы BRANCH (ветвление). BR**

И вот в этом месте товарищей из ATMEL надо хватать за ноги и бить головой об стену. Потому что я не понимаю на кой хрен было так все запутывать, изобретая команды которых реально нет?

Суди сам. Флагов у нас 8, соответственно должно быть 16 возможных бранчей. 8 по условию — флаг есть, 8 по условию — флага нет. Бранчевых команд же у нас аж 20 штук.

BRBC # переход если бит # в регистре SREG=0 BRBS # переход если бит # в регистре SREG=1 BRCS переход если С=1 BRCC переход если С=0 BREQ переход если Z=1 BRNE переход если Z=0 BRSH переход если С=0 BRLO переход если С=1 BRMI переход если N=1 BRPL переход если N=0 BRGE переход если S=0 BRLT переход если S=1 BRHC переход если H=0 BRHS переход если H=1 BRTC переход если T=0 BRTS переход если T=1 BRVS переход если V=1 BRVC переход если V=0 BRID переход если I=0 BRIE переход если I=1

Однако, если глубоко копнуть, поглядеть на реальные коды команд, то окажется, что BRCS=BRLO и BRCC=BRSH — у них вообще одинаковый код.

А таких команд как BRBS # и BRBC # вообще не существует. Это всего лишь иносказательная запись всех остальных бранчей, в зависимости от номера бита #.

А таких команд синонимов там дофига 🙂
Так что гордое «131 Powerful Instructions – Most Single-clock Cycle Execution» на самом деле является не более чем гнилым маркетинговым высером. Нет там 131 команды! Есть 131 мнемоника, а это несколько разные вещи. Потому как ты помидор не обзови — картошкой он от этого не станет.

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

Может быть, но как по мне — только ситуацию запутывают. Из-за этого я после ассемблера С51 долго плевался на систему команд AVR, потом привык и ничо так, вкатило.

Итак, как работает любой из бранчей (да, тому кто придумал переименовать родимый J** в BR** я тоже ежедневно посылаю лучи поноса, надеюсь в сортире он себе уже кабинет обустроил).

Проверяется условие и если оно верное делается переход.

Например, на входе у нас значение.

  • Если значение = 1, то делаем действие А
  • Если значение = 2, то делаем действие Б
  • А если значение меньше 13, то делаем действие ЦЭ
  • Во всех остальных случаях не делаем ничего

Нет ничего проще, пусть значение приходит через регистр R16

CPI R16,1 ; Сравниваем R16 с 1 BREQ ActionA ; Переход если равно (EQual, Z=1) ; Если не равно, то идем дальше CPI R16,2 ; Сравниваем R16 с 2 BREQ ActionB ; Переход если равно ; Если не равно, то идем дальше CPI R16,13 ; Сравниваем R16. т.е. R16-13 BRCS ActionC ; Если возник перенос, значит R16 меньше 13 ; Если не возник — идем дальше RJMP NoAction ; Переход на выход ActionA: NOP NOP ; Делаем наш экшн NOP RJMP NoAction ; Выходим, чтобы не влезть в ActionB ActionB: NOP NOP ; Делаем наш экшн NOP RJMP NoAction ; Выходим, чтобы не влезть в ActionC ActionC: NOP NOP ; Делаем наш экшн NOP NoAction: NOP ; Вместо NOP, разумеется, должны быть какие-нибудь полезные команды.

Сложно? Вот и я думаю, что делать нефиг :))))) Ничуть не сложней чем на Си забабахать из if then конструкцию или switch-case какой-нибудь.

Бег по граблям
У команд BR*** есть правда весьма ощутимое западло. Дальнобойность их составляет всего 63 команды. Т.е. это относительный переход. Поначалу ты этого не заметишь — короткая программа обычно не допускает переходов дальше 63.

Но вот, со временем, твоя программа распухнет, появится дофига кода и дальности бранча перестанет хватать. Вроде бы все работало, а добавил пару команд — и компилятор начал ругаться злыми словами — Error out of range или что то в этом духе. Как быть?

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

ActionA: NOP NOP NOP RJMP NoAction NOP ; То есть если я вот тут поставлю островок ; то он никогда не выполнится. Т.к. сверху ; Процессор перепрыгнет сразу по RJMP ; А снизу вход будет сразу же на ActionB ActionB: NOP NOP NOP RJMP NoAction И вот, в этом островке, мы создаем капсулу телепортер такого вида: ActionA: NOP NOP NOP RJMP NoAction ;———————————— Near: JMP FarFar_away ;———————————— ActionB: NOP NOP NOP RJMP NoAction

Т.е. бранчу теперь достаточно дострелить до островка Near, а там дальнобойный JMP зашлет его хоть в бутсектор на другой конец флеша.

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

Test & Skip
Кроме Branch‘ей есть еще один тип команд: проверка — пропуск.
Работает она по принципу “Проверяем условие, если справедливо — пропускаем следующую команду”
Запомнить просто, первая буква это Skip — пропуск. Вторая условие — С=Clear, т.е. 0 S=Set, т.е. 1. Соответственно S**C пропуск если сброшено. S**S пропуск если установлено.

Указываешь ей какой РОН, и какой номер бита в этом регистре надо проверить. И если условие верное, то следующая команда будет пропущена.

SBRC R16,3 ; Если бит 3 в регистре R16 = 0, то прыжок через команду, на NOP RJMP bit_3_of_R16_Not_Zer0 NOP SBRS R16,3 ; Если бит 3 в регистре R16 = 1, то прыжок через команду, на NOP RJMP bit_3_of_R16_Zer0 NOP

SBIC/SBIS Но проверяет она не биты регистров РОН, а биты регистров периферийных устройств. Те самые,что идут в памяти между блоком РОН и оперативкой. Но есть у ней ограничение — она может проверить только первые 1F регистров ввода вывода. Если заглянешь в m16def.inc (для мега16, для других МК в их файл дефайнов)

То увидишь там это:

.equ UBRRH = 0x20 .equ UCSRC = 0x20 .equ EEARL = 0x1e AssemblerAVRПрограммированиеФлаги

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

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

48 thoughts on “AVR. Учебный курс. Флаги и условные переходы”

Начал изучать прерывания опять же на С. И вот какое дело, обработчик прерываний у меня срабатывает когда на линии PB5 меняется уровень, в обработчеке у меня простой код если PB5 = 0 и PB6= 0 то пишу ноль, исли PB6=1 пишу еденицу. Так вот за 100 ms
у меня проходит 100 едениц и нулей. Суть в чем если я просто посылаю по UART, то принимаю все биты. Но стоит мне записать биты в массив, а потом перевести их в число, как на выходе я получаю какую то биллиберду. Я вот думаю успевает ли выполнится обработчик прерывания, до возникновения другого прерывания? Или может я что не так делаю.

Тьфу ты не туда написал, как удалить не знаю ((

Посчитай такты за который выполняется обработчик прерывания. Прикинь время на выполнение. С учетом кварца. Потом позырь на то с какой скоростью у тебя прерывания вызваются — нет ли затыка.

Что то совсем у меня худо с прерываниями. Такое ощущений что программа постоянно перезапускается. Вот допустим в главной функции если после всей инициализации поставить UDR = ‘S’, при включении у меня, валится это S всех щелей. Что такое немогу ни как разобратся, отключаю прерывания, все нормально работает. Но вроде обработчик не вызывается до тех пор пока уровень не изменится на ножке PB5. Чудеса да и только)

чего-то я не пойму, флаг S и N одно и то же? ведь оба знак показывают
S это что главный флаг знака, а V и N частные случаи?
как вообще определить отрицательность числа по двоичноми коду, ведь может быть положительное число с 1 в 7 бите

По одним только флагам никогда ничего сказать определенно нельзя.

Только в контексте предыдущей выполненной команды. А вот уже она выставляет флаги в зависимости от результатов операции.

Знак у двоичного числа тоже никак нельзя определить в отрыве от контекста.

Источник

Оцените статью