Итак, чтобы умножить 976 на коэффициент 0,48576, следует сначала последний вручную умножить, например, на 2 16= 65 536, и тем самым получить числитель соответствующей двоичной дроби (у которой знаменатель равен 65 536) — он будет равен 31834,76736, или, с округлением до целого 31 835. Такой точности хватит, если исходные числа не выходят, как у нас, за пределы трех-четырех десятичных разрядов. Теперь мы в контроллере должны умножить исходную величину 976 на константу 31 835 и полученное число 31 070 960 (оно оказывается 4-байтовым — S01DA1AF0, потому нашу Mui6i6 придется чуть модифицировать, как сказано при ее описании ранее) сдвигаем на 16 разрядов вправо:
;в ddHH: ddH: ddM: ddL число $01DA1AF0,
;его надо сдвинуть на 16 разрядов
сlrг cnt
div16L: ;деление на 65536
lsr ddHH ;сдвинули старший
ror ddH ;сдвинули 3-й
rоr ddM ;сдвинули 2-й
rоr ddL ;сдвинули младший
inc cnt
cpi cnt,16
brne divl6L ;сдвинули-поделили на 2 в 16
В результате, как вы можете легко проверить, старшие байты будут нулевыми, а в ddM:ddL окажется число 474 — тот же самый результат. Но и это еще не все, такая процедура приведена скорее для иллюстрации общего принципа. Ее можно еще больше упростить, если обратить внимание на то, что сдвиг на восемь разрядов есть просто перенос значения одного байта в соседний (в старший, если сдвиг влево, и в младший — если вправо). Итого получится, что для сдвига на 16 разрядов вправо нам надо всего-навсего отбросить два младших байта, и взять из исходного числа два старших ddHH:ddH— это и будет результат. Проверьте — S01DA и есть 474. Никаких других действий вообще не требуется!
Если степень знаменателя дроби, как в данном случае, кратна 8, то действительно никакого деления, даже в виде сдвига, не требуется, но чаще всего это не так. Однако и тут приведенный принцип может помочь: например, при делении на 2 15(что может потребоваться, если, например, в нашем примере константа больше единицы) вместо пятнадцати кратного сдвига вправо результат можно сдвинуть на один разряд влево (фактически умножив число на два), а потом уже выделить из него старшие два байта. Итого процедура будет состоять из четырех операций сдвига и займет четыре такта. А в виде циклического сдвига на 15, как ранее, нам требуется в каждом цикле сделать четыре операции сдвига и одну увеличения счетчика: 15 х 5 = 75 простых однотактных операций, и еще 15 операций сравнения, из которых 14 займут два такта — итого 104 такта. А решение «в лоб» на основе операций целочисленного деления в несколько раз превышало бы и эту величину. Существенная разница, правда? Вот такая специальная арифметика в МК.
Операции с числами в формате BCD
Это важная группа операций, ведь значительная часть устройств на основе МК предназначена для демонстрации чисел в том или ином виде. Это, естественно, можно делать только в десятичном формате, в то время как внутреннее представление чисел в регистрах двоичное. В некоторых микропроцессорных системах (в их число входит семейство x 51 от Intel и, кстати, x86) даже имеется специальная инструкция для т. н. двоично-десятичной коррекции , которая позволяет получить верный результат при сложении двоично-десятичных чисел в упакованном формате (о BCD-форматах см. главу 7 ). Но в системе команд AVR такой инструкции нет, и, в общем-то, она все равно не очень-то полезна, т. к. математические операции в любом случае удобнее выполнять в «родной» двоичной форме, а для представления на дисплее числа так или иначе приходится «распаковывать». В ПК этим незаметно для пользователя занимаются процедуры на языках высокого уровня (да так успешно, что приходится скорее озадачиваться обратной проблемой — представлением десятичных чисел в двоичной/шестнадцатеричной форме), ну а на уровне ассемблера десятичные преобразования приходится делать, что называется, ручками.
Заметки на полях
Традиционная область использования команд двоично-десятичной коррекции, в том числе и в процессорах х 86 — манипуляции со значением времени, полученным из микросхем RTC, в которых часы, минуты и секунды всегда хранятся в упакованном BCD-формате. Как вы увидите далее, такой формат хранения довольно удобен на практике. Однако область применения микроконтроллерных систем далеко не исчерпывается подсчетом и демонстрацией времени, потому нам придется выйти за рамки однобайтовых кодов, для которых, собственно, инструкция коррекции и создавалась. Уже для двухбайтовых чисел ее применение вызывает только лишние сложности.
Читать дальше
Конец ознакомительного отрывка
Купить книгу