Выражение — это запись алгоритма вычислений над операндами при помощи знаков математических, логических и прочих действий. Другими словами: выражение — есть формула вычислений, записанная средствами языка программирования.
В определении выражения использован новый термин: операнд. Операнд — это выражение, над которым выполняется какое-либо действие. Как видите, операнд и выражение оказываются определенными друг через друга. Надеюсь, для образованного человека не составит труда представить себе, что же такое выражение на самом деле — для этого достаточно вспомнить, что такое математическое выражение.
В языке Си определены два типа операндов (выражений): математические и логические. Математическое выражение состоит из операндов, эквивалентных числам, и знаков математических операций. Логическое выражение — это выражение отношений, т.е. ответов на вопросы «больше?», «меньше?», «равно?» и т.д. Аналогично математическим, существуют логические действия и соответствующие им знаки логических операций.
c для avr (макросы) программирование на си для avr микроконтроллеров
Действия могут выполняться над двумя операндами или над одним операндом -унарные операции.
В Си определены следующие унарные математические операции:
Знак | Операция |
– | Унарный минус, признак изменения знака числа на противоположный |
+ | Унарный плюс, означает сохранение знака числа без изменения (принципиального смысла не имеет) |
++ | Знак инкремента, увеличение операнда на 1 |
— | Знак декремента, уменьшение операнда на 1 |
~ | Побитовая инверсия числа |
Математических операций над двумя операндами больше:
Знак | Операция |
+ | Сумма операндов |
– | Разность операндов |
* | Произведение операндов |
/ | Частное операндов |
% | Остаток от целочисленного деления операндов |
| | Побитовая операция ИЛИ над операндами |
> | Побитовый сдвиг влево |
Побитовый сдвиг вправо |
Об операциях побитового сдвига следует упомянуть, что эти операции сохраняют знак операнда, если операнд имеет знаковый тип.
Унарная логическая операция всего одна:
Знак | Операция |
! | Логическое отрицание (НЕ) |
Логических операций над парой операндов больше:
Знак | Операция |
|| | Логическое ИЛИ |
Логическое И | |
> | Больше |
Меньше | |
== | Эквивалентно |
!= | Не эквивалентно |
Меньше или равно | |
>= | Больше или равно |
Важно понимать, что для логических выражений определено лишь два значения результата: ИСТИНА и ЛОЖЬ, причем истинным в Си считается любое не равное нулю значение, а ложным – значение ноль.
Introduction to AVR Studio
Вот несколько примеров логических и арифметических выражений:
5+2*3- арифметическое выражение, эквивалентное 11
(5+2) * 3 — арифметическое выражение, эквивалентное 21
5 + var * (3 + Ь) — арифметическое выражение с использованием переменных
(5 > 2) — логическое выражение со значением ЛОЖЬ
(2-7) >= -11 — логическое выражение со значением ИСТИНА
(2-7) >= 0 — логическое выражение со значением ЛОЖЬ
Знаки арифметических и логических операций называются по-другому операторами, однако понятие оператор более широкое, и включает в себя не только какое либо одно действие, но и целую группу [действий, выполняемых по определенным правилам.
Особняком стоит операция, обозначаемая символом «?» -условная операция. Эта операция имеет достаточно сложную форму записи:
? :
Операция позволяет выбрать в качестве своего результата одно из значений — значение1 или значение2 в зависимости от того, истинно или ложно выражение1. В качестве обоих значений могут использоваться так же выражения.
Пример:
х > 5 ? 4 : 8 — если х будет меньше или равно 5, то результат операции будет 8, а если х будет больше 5 — результат будет 4.
Смысл в выражениях был бы невелик, если бы результат их вычислений было бы невозможно присваивать значениям переменных. Для присвоения значения переменной используется оператор присваивания, обозначаемый символом «=»:
var = 5 + 2 ; // присвоить переменной var значение выражения 5 + 2, т.е. 7
Возвращаясь к описанию переменных, следует заметить, что можно присваивать значение переменной сразу в момент ее описания:
int var = 5 ; // описанная переменная var имеет тип int и значение 5
В операторе присваивания левее знака «=» должно находиться так называемоелеводопустимое выражение, т.е. либо переменная, либо такое выражение, результатом которого будет значение указателя, который покажет место в памяти для хранения результата. Правее знака равенства может находиться любое праводопустимое выражение, т.е. в сущности, любое выражение. Интересный момент возникает, если и слева и справа от знака равенства используется одна и та же переменная:
Такое выражение следует понимать так: «присвоить переменной S значение, равное сумме ее текущего значения и числа 5». Можно записать то же самое более коротким способом:
В данном примере использован двойной оператор «+=», называемый присваивание с суммированием. Значение этого оператора то же самое: увеличение значения переменной на число правее оператора. Кроме присваивания с суммированием допустимы аналогичные комбинации для присваивания с разностью, с умножением, делением или остатком от деления, записываемым соответственно так: «-=», «*=», «/=» или «%=». Любой такой оператор «разворачивается» аналогично рассмотренному:
a *= 2 равносильно a = a * 2
a /= 2 равносильно a = a / 2
a -= 2 равносильно a = a – 2
a %= 2 равносильно a = a % 2
Несколько слов о присваивании значений переменным типа указатель. Как было сказано, указатель есть ни что иное, как адрес объекта в памяти, соответственно в качестве значения можно ему присваивать только адрес. Делается это при помощи унарного оператора взятия адреса далее происходит присваивание указателю значения адреса переменной var.
приведут к одинаковому результату.
Иногда требуется обратиться к какому-либо участку памяти, который явно не является конкретной переменной, т.е. адрес участка известен, но соответствующего ему описанного в программе объекта нет. В этом случае следует использовать прием, названный явным приведением типа:
3. В нужном месте разрешаем прерывания программы. Это делается также однократно, после того как сделаны все приготовления:
[Обработчик прерывания на ASM]
Этот вариант не многим сложнее, просто организован по-другому. Я его сделал на основе отдельного файла, который содержит только код на языке ассемблера. Алгоритм тут тоже другой — обработчик прерывания срабатывает раз в секунду и сам себя запрещает. Основная программа отслеживает это событие и меняет секундные счетчики (выполняет все действия, которые нужно выполнять раз в секунду), и нова разрешает прерывание. Такой алгоритм позволяет ускорить обработку прерывания, что может быть критично для некоторых задач (например, только так можно организовать точный отсчет времени при использовании библиотеки V-USB). Процесс по шагам:
1. Настраиваем таймер. Это может делать код на C. Все точно так же, как и с обработчиком прерывания на C (см. шаг 1).
2. Готовим файл с нашим кодом обработчика на языке ассемблера. Вот пример кода:
#include /io.h> .text .global TIMER1_OVF_vect TIMER1_OVF_vect: push R24 ldi R24, 0 out _SFR_IO_ADDR(TIMSK), R24 pop R24 reti
Этот код будет работать очень быстро, поскольку короткий. Он почти ничего не делает, только запрещает прерывание от таймера 1 (в регистре TIMSK сбрасываются все флаги, в том числе и нужный нам флаг TOIE1). Запускать прерывание будет основная программа, как только обнаружит, что прерывание запрещено (путем анализа состояния флага TOIE1).
3. В нужном месте разрешаем прерывания программы. Это делается также однократно, после того как сделаны все приготовления:
4. В основной программе, в главном цикле main, должен максимально часто вызываться следующий код:
..void main (void) .. while (1) .. if (0==(TIMSK TIMSK = (1 ); //далее действия, которые будут происходить // раз в секунду .. > .. >>
[Общие замечания]
Можно заметить, что в обоих примерах использовалась именованная константа TIMER1_OVF_vect, которая задает адрес вектора прерывания таймера 1. Имена констант можно узнать во включаемом файле процессора. Для ATmega16, например, это будет файл c:WinAVR-20080610avrincludeavriom16.h. Чтобы имена стали доступны, не нужно добавлять именно этот файл в проект директивой #include, достаточно добавить #include и задать макроопределение, задающее тип процессора (например, MCU = atmega16. Это можно сделать либо в Makefile, либо в свойствах проекта).
При использовании одновременно нескольких прерываний в AVR важно помнить, что прерывания имеют фиксированный, ненастраиваемый приоритет. Чем меньше адрес вектора прерывания, тем приоритет у прерывания выше. Этот приоритет срабатывает, если при выходе из прерывания имеется несколько необработанных флагов прерывания. Прерывание с более высоким приоритетом НЕ может временно приостановить уже работающий обработчик прерывания с меньшим приоритетом, чтобы немедленно выполнить свой код. Работает система примерно так:
— когда общие прерывания разрешены (установлен бит I в регистре SREG, этот бит называют Global Interrupt Enable), то может быть вызвано любое разрешенное прерывание с любым приоритетом. Бит Global Interrupt Enable может быть принудительно сброшен или установлен командами CLI или SEI соответственно.
— для того, чтобы прерывание могло сработать и вызвать свой обработчик, кроме установки бита Global Interrupt Enable необходимо также установить бит разрешения соответствующего прерывания. Для таймеров-счетчиков это биты регистра TIMSK, для интерфейса SPI — бит SPIE в регистре SPCR, и т. д.
— когда срабатывает любое прерывание, то сразу очищается флаг I (Global Interrupt Enable), и автоматически запрещаются все прерывания, пока не произойдет выход из обработчика прерывания. Если во время работы обработчика прерывания возникали условия, при которых должны были сработать другие прерывания, то эти другие прерывания не вызываются, а просто запоминаются соответствующие им флаги (прерывания «откладываются» на будущее). При выходе из обработчика прерывания запомненные флаги прерывания запустят нужный обработчик прерывания в соответствии с назначенным ему приоритетом (если на данный момент имеется несколько отложенных прерываний).
— разработчик может в обработчике прерывания вызвать команду SEI (которая установит флаг Global Interrupt Enable), тем самым разрешив выполнение других прерываний во время работы этого обработчика прерывания. Тогда, если произойдет новое другое прерывание до завершения текущего обработчика (в котором уже была вызвана команда SEI), текущий обработчик прерывания будет приостановлен, адрес возврата в него будет сохранен в стеке и будет вызвано новое прерывание. Таким способом можно обеспечить некое подобие соблюдения приоритета — в низкоприоритетных обработчиках прерывания должна первой стоять команда SEI, а в высокоприоритетных обработчиках команда SEI должна отсутствовать, что обеспечит выполнение этого обработчика полностью.
Отсутствие возможности четко настроить приоритет — довольно серьезный недостаток платформы AVR.
[Ссылки]
Источник: microsin.net