Арифметические операции. Умножение и деление



Умножение и деление
В микроконтроллерах PIC16 отсутствует аппаратный блок умножения и деления чисел, но эти арифметические операции можно реализовать программным путем.
Операцию умножения можно представить в виде многократного сложения, деление — многократным вычитанием. Например, выражение 8х3=24 равнозначно 8+8+8=24, для деления в качестве примера возьмем следующее выражение 36:10=3,6. Алгоритм деления можно представить так: 36-10-10-10-10=-4, то есть вычитаем из 36 число 10 до тех пор, пока не получим отрицательный результат. При этом результатом операции деления является количество вычитаний, но только без учета последнего вычитания, которое привело к отрицательному результату, так как я рассматриваю здесь только целочисленные операции без дробных частей. В данном примере после четырех вычитаний получаем -4, соответственно ответ равен 3, без учета последнего вычитания.

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

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

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

Деление многобайтных чисел производится по тому же алгоритму, коды подпрограмм представлены ниже:

Следует знать, что в отличие от подпрограмм сложения и вычитания, умножение и деление могут занять значительное процессорное время. Умножение чисел 255х255=65025 занимает около 2303 машинных циклов, при частоте тактового генератора в 20 Мгц, время расчета составит 460 мкс. В основном время расчета зависит от числа, на которое умножаем (прямая зависимость). При делении продолжительность расчета увеличивается с уменьшением числа, на которое делим, например операция деления чисел 255:1=255 займет около 1797 машинных циклов, при 20 МГц время расчета составит 359,4 мкс.

Деление и умножение на число 2 можно производить с помощью сдвига содержимого регистра вправо и влево соответственно, с помощью команд RRF и RLF. Сдвиг происходит через флаг C регистра STATUS, при сдвиге вправо, младший бит передается в C, а значение бита C передается в старший бит сдвигаемого регистра, при сдвиге влево все наоборот. Поэтому при применении команд сдвига для деления и умножения необходимо предварительно очистить бит C регистра STATUS.

Последние записи:

Комментариев 3 на “Арифметические операции. Умножение и деление

  1. Понятные рабочие алгоритмы замечательно и аккуратно выполнены … Автору — интересных заказов от достойных клиентов!

  2. В конце статьи упомянуты команды RRF и RLF, а ведь с их помощью приращение\уменьшение в регистрах с конечным результатом будет на много быстрее и для этого будет возможен выигрыш в количестве строк кода и времени выполнения? Или я ошибаюсь?

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *