Если вы посмотрите таблицу команд в Приложении 4, то можете обратить внимание, что из восьмибитовых арифметических операций с константой доступно только вычитание (SUBI, SUCI), напрашивающейся операции сложения с константой нет. Это не упущение автора при формировании выборочной таблицы, а действительная особенность системы команд AVR. Это можно обойти при желании вычитанием отрицательного числа, но на практике не очень-то требуется, потому что разработчики семейства AVR решили облегчить жизнь пользователям, добавив в перечень арифметических команд две очень удобные команды adiw и sbiw, которые, по сути, делают то же самое, что пары команд add/adc (sub/sbc), только за одну операцию, и притом с константой, а не с регистром. Единственный их недостаток— работают они только с определенными парами регистров: с четырьмя парами, начиная с r25-r24. Три старших пары (r26-27, r28-29 и r30-31) носят еще название X, Y и Z, и мы их будем «проходить» далее в этой главе, они задействованы в операциях обмена данными с SRAM. Но, к счастью, точно так же работает и пара r24-r25, которая более нигде не употребляется в объединенном качестве, и это очень удобно. Независимо от используемой пары, старшим считается регистр с большим номером, а операцию нужно проводить с младшим, при этом перенос учтется автоматически. Например, в результате выполнения последовательности команд
clr r25
ldi r24,100
adiw r24,200
в регистрах r25:r24 окажется записано число 300 (в r25 будет записано $01, что эквивалентно 256 для 16-разрядного числа, а в r24 окажется $2С = 44). Аналогично работает и процедура вычитания константы sbiw.
С арифметикой многоразрядных чисел мы познакомимся в главе 15, там же попробуем освоить умножение и деление. Заметим, что все эти операции корректно работают с числами со знаком (см. главу 7), но вы удивитесь, узнав, насколько редко такая задача возникает на практике. А с дробными числами (с «плавающей запятой») AVR работать напрямую не «умеют», и тут приходится хитрить, о чем мы подробнее поговорим в главе 15.
Кроме собственно арифметических, к этой группе команд еще иногда относят некоторые логические операции, например логический сдвиг, хотя чаще их помещают в группу инструкций для операций с битами. Самая простая такая операция — сдвиг всех разрядов регистра влево (lsl) или вправо (lsr) на одну позицию. Сдвиги приходится применять довольно часто, потому что, как вы знаете из главы 7, такая операция равносильна умножению (соответственно, делению) на 2. Для того чтобы разряды не терялись при сдвиге, предусмотрены разновидности этих операций: rol и rоr. Они учитывают все тот же флаг переноса С, и его можно перенести в другой регистр. Например, в результате выполнения последовательности команд
lsl R1
rol R2
регистр R1 будет умножен на 2, а старший его разряд (неважно, ноль он или единица) окажется в младшем разряде R2. Причем обратите внимание, что R2 при этом также умножается на 2, и, следовательно, его младший разряд без учета переноса всегда окажется равным нулю (четные числа в двоичной системе оканчиваются на 0).
Здесь же имеет смысл рассмотреть инструкции установки отдельных битов. Команды, устанавливающие значения битов в регистрах общего назначения (sbr и cbr) иногда относят к группе арифметических операций, а команды, устанавливающие биты в регистрах ввода/вывода (sbi и cbi) — к группе битовых операций. Правда, в некоторых пособиях их относят к одной группе операций с битами, что, конечно, логичней. Но почему такой разнобой, если они, по сути, делают одно и то же?
Механизм работы этих команд существенно различается. Очевиднее всего устроены sbi и cbi: так, уже знакомая нам команда sbi PortB,5 установит в единичное состояние разряд номер 5 порта В. Если этот разряд порта сконфигурирован на выход, то единица появится непосредственно на соответствующем выводе микросхемы (например, для микросхемы ATmega8 это вывод 19, для 8515 или 8535 любого семейства это вывод 6 и т. п.), если на вход, то эта операция управляет подключением «подтягивающего» резистора.