Юрий Ревич - Занимательная электроника
- Название:Занимательная электроника
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2015
- Город:Санкт-Петербург
- ISBN:978-5-9775-3479-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Юрий Ревич - Занимательная электроника краткое содержание
На практических примерах рассказано о том, как проектировать, отлаживать и изготавливать электронные устройства в домашних условиях. От физических основ электроники, описания устройства и принципов работы различных радиоэлектронных компонентов, советов по оборудованию домашней лаборатории автор переходит к конкретным аналоговым и цифровым схемам, включая устройства на основе микроконтроллеров. Приведены элементарные сведения по метрологии и теоретическим основам электроники. Дано множество практических рекомендаций: от принципов правильной организации электропитания до получения информации о приборах и приобретении компонентов применительно к российским условиям. Третье издание дополнено сведениями о популярной платформе Arduino, с которой любому радиолюбителю становятся доступными самые современные радиоэлектронные средства.
Для широкого круга радиолюбителей
Занимательная электроника - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Поэтому для начала поучимся оперировать в контроллере большими числами и представлять их в десятичной форме. В следующей главе мы перейдем к Arduino , где таких проблем не существует вовсе, — любые арифметические действия программируются «прозрачно» для пользователя, а сопутствующие проблемы за вас уже решили создатели компилятора AVRGCC. Зато когда вы поглядите на объем получающегося кода, то оцените преимущества программирования на ассемблере. И дело даже не в самом объеме (аналогичная программа для Arduino просто не влезла бы в память mega8535), а в скорости исполнения: к этой программе мы спокойно можем добавить еще часы с будильником, запись в память, общение с компьютером, и все это будет спокойно выполняться на частоте 4 МГц с максимально возможной скоростью и без потерь.
Арифметика многобайтовых чисел в МК
Сложение и вычитание больших чисел в МК не представляет трудностей. Корректная операция сложения двух 16-разрядных чисел будет занимать две команды:
add RL1,RL2
adc RH1,RH2
Здесь переменные RL1 и RL2 содержат младшие байты слагаемых, a RH1 и RH2 — старшие. Если при первой операции результат превысит 255, то перенос запишется во все тот же флаг переноса С и учтется при второй операции. Общий результат окажется в паре RH1:RL1. Совершенно аналогично выглядит операция вычитания. Примеры операций с большим числом слагаемых вы найдете в тексте программ далее.
А вот с умножением и делением несколько сложнее. Выполнение типовых операций на AVR для чисел с различной разрядностью, вообще говоря, приводится в фирменных руководствах по применению: «аппнотах» ( Application Notes , в данном случае номер 200). Но эти процедуры для наших целей все равно придется творчески переработать. Поэтому мы не будем на них останавливаться, а сразу воспользуемся тем обстоятельством, что для контроллеров семейства Mega определены аппаратные операции умножения. Тогда и алгоритм сильно упрощается и легко модифицируется для любого размера операндов и результата. Вот так выглядит алгоритм для перемножения двух 16-разрядных сомножителей с получением 24-разрядного результата (в названиях исходных переменных отражен факт основного назначения такой процедуры — для умножения неких данных на некий коэффициент [37] Сокращения LSB и MSB означают least (most) significant bit — младший (старший) значащий разряд, по-русски МЗР и СЗР, соответственно.
):

Как видите, если нужно получить полный 32-разрядный диапазон, просто добавьте еще один регистр для старшего разряда ( temp3 , к примеру) и одну строку кода перед командой ret :
adc temp3,r01
Естественно, можно просто обозвать r01 через temp3 , тогда и добавлять ничего не придется.
Деление — значительно более громоздкая процедура, чем умножение, требует больше регистров и занимает больше времени. Операции деления двух чисел (и 8- и 16-разрядных) приведены в той же «аппноте» 200, но они не всегда удобны на практике: часто нам приходится делить результат какой-то ранее проведенной операции умножения или сложения, а он нередко выходит за пределы двух байтов.
Здесь нам потребуется вычислять среднее значение для уточнения результата измерения по сумме отдельных измерений. Если даже само измерение укладывается в 16 разрядов, то сумма нескольких таких результатов уже должна занимать три байта. В то же время делитель — число измерений — будет относительно небольшим и укладывается в один байт. Но мы не будем здесь заниматься построением «настоящих» процедур деления (интересующихся отсылаю к моей книге [21]). Многие подобные задачи на деление удается решить значительно более простым и менее громоздким методом, если заранее подгадать так, чтобы делитель оказался кратным степени 2. Тогда все деление сводится, как мы знаем, к сдвигу разрядов вправо столько раз, какова степень двойки.
Для примера предположим, что мы некую величину измерили 64 раза и хотим узнать среднее. Пусть сумма укладывается в 2 байта, тогда вся процедура деления будет такой:

He правда ли, гораздо изящнее и понятнее? Попробуем от радости решить задачку, которая на первый взгляд требует по крайней мере знания высшей алгебры — умножить некое число на дробный коэффициент (вещественное число с «плавающей запятой»). Теоретически для этого требуется представить исходные числа в виде мантисса-порядок, сложить порядки и перемножить мантиссы. Нам же неохота возиться с этим представлением, т. к. мы не проектируем универсальный компьютер, и в подавляющем большинстве реальных задач все конечные результаты у нас есть целые числа.
На самом деле эта задача решается очень просто, если ее свести к последовательному умножению и делению целых чисел, представив реальное число в виде целой дроби с оговоренной точностью. В десятичной форме это выглядит так: представим число 0,48576 как 48 576/100 000. И если нам требуется на такой коэффициент умножить, к примеру, число 976, то можно действовать, не выходя за рамки диапазона целых чисел: сначала умножить 976 на 48 576 (получится заведомо целое число 47 410 176), а потом поделить результат на 10 5, чисто механически перенеся запятую на пять разрядов. Получится 474,10176 или, если отбросить дробную часть, 474. Большая точность нам и не требуется, т. к. и исходное число было трехразрядным.
Улавливаете, к чему я клоню? Наше ноу-хау будет состоять в том, что мы для того, чтобы «вогнать» дробное число в целый диапазон в микроконтроллере, будем использовать не десятичную дробь, а двоичную — деление тогда сведется к той же самой механической процедуре сдвига разрядов вправо, аналогичной переносу запятой в десятичном виде.
Итак, чтобы умножить 976 на коэффициент 0,48576, следует сначала последний вручную умножить, например, на 2 16(65 536), и тем самым получить числитель соответствующей двоичной дроби (у которой знаменатель равен 65 536) — он будет равен 31 834,76736, или, с округлением до целого, 31 835. Такой точности хватит, если исходные числа не выходят, как у нас, за пределы 3–4 десятичных разрядов. Теперь мы в контроллере должны умножить исходную величину 976 на константу 31 835 (см. процедуру перемножения ранее) и полученное число 31 070 960 (оно оказывается 4-байтовым — $01DA1AF0, потому нашу процедуру Mui1x16 придется чуть модифицировать, как сказано при ее описании) сдвинуть на 16 разрядов вправо:

В результате, как вы можете легко проверить, старшие байты окажутся нулевыми, а в ddM: ddL окажется число 474 — тот же самый результат. Но и это еще не все — такая процедура приведена скорее для иллюстрации общего принципа. Ее можно еще больше упростить, если обратить внимание на то, что сдвиг на восемь разрядов есть просто перенос значения одного байта в соседний (в старший, если сдвиг влево, и в младший — если вправо). Итого получится, что для сдвига на 16 разрядов вправо нам надо всего-навсего отбросить два младших байта и взять из исходного числа два старших ddHH: ddH — это и будет результат. Проверьте — $01DA и есть 474. Никаких других действий вообще не требуется!
Читать дальшеИнтервал:
Закладка: