assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 35
Текст из файла (страница 35)
Он содержит слово состояния, с помощью которого производятся выбор канала, задание режима работы канала и типа операциипередачи значения в канал.Ввод из порта и вывод в порт153Далее описана структура слова состояния:il Бит 0 определяет тип константы пересчета: 0 — константа задана двоичнымчислом, 1 — константа задана двоично-десятичным (BCD) числом. Константапересчета — значение, загружаемое извне в регистр-фиксатор; в нашем случаезагружаться будет двоичное число, поэтому значение этого поля будет равно 0.ii Биты 1-3 определяют режим работы микросхемы таймера. Всего можно определить шесть режимов, но обычно используется третий, поэтому для нашегослучая значение поля — 011.т Биты 4-5 определяют тип операции: 00 — передать значение счетчика в регистрфиксатор (то есть возможны не только операция записи значения в канал, нои извлечение значения регистра-счетчика из него), 10 — записать в регистр-фиксатор только старший байт, 01 — записать в регистр-фиксатор только младшийбайт, 11 — записать в регистр-фиксатор сначала старший байт, затем младший.В нашем случае значение поля будет 11.
Поэтому формирование 16-разрядногорегистра-фиксатора через 8-разрядный регистр ввода-вывода производитсяследующим образом: запись производится в два приема, первый байт из регистра ввода-вывода записывается на место старшего байта регистра-фиксатора,второй байт — на место младшего байта. Нетрудно догадаться, что в регистрввода-вывода эти байты помещаются командами IN и OUT.II Биты 6-7 определяют номер программируемого канала. В нашем случае ониравны 10.Для формирования любого звука необходимо задать его длительность и высоту.
После того как значение из регистра ввода-вывода попало в регистр-фиксатор,оно моментально записывается в регистр-счетчик. Сразу же после этого значениерегистра-счетчика начинает уменьшаться на единицу с приходом каждого импульсаот системных часов. На выходе любого из трех каналов таймера стоит схема логического умножения. Эта схема имеет два входа и один выход. Значение регистрасчетчика участвует в формировании сигнала на одном из входов схемы логического умножения И. Сигнал на втором входе этой схемы зависит от состояния бита Орегистра микросхемы интерфейса с периферией (порт 61h). В свое время мы подробно разберемся с логическими операциями, сейчас следует лишь пояснить, чтоединица на выходе схемы логического умножения может появиться только в одном случае — когда на обоих входах единицы.
Когда значение в регистре-счетчикестановится равным нулю, на соответствующем входе схемы И формируется такаяединица. И если при этом на втором входе, значение которого зависит от бита Опорта 61h, также 1, то импульс от системных часов проходит на выход канала 2.Одновременно с пропуском импульса в канале 2 немедленно производится загрузкасодержимого регистра-фиксатора (которое не изменилось, если его не изменилиизвне) в регистр-счетчик.
Весь процесс с уменьшением содержимого регистра-счетчика повторяется заново. Теперь вы понимаете, что чем меньшее значение загружено в регистр-фиксатор, тем чаще будет происходить обнуление регистра-счетчика и тем чаще импульсы будут проходить на выход канала 2. А это означаетбольшее значение высоты звука. Понятно, что максимальное значение частоты навходе 1 динамика — 1,19 МГц. Таким образом, импульс с выхода канала 2 попадает154Глава 7. Команды обмена даннымина динамик, и если на последний подан ток, то возникает долгожданный звук. Подачей тока на динамик управляет бит 1 порта 61h. Как прервать звучание? Очевидно, для этого возможны два пути: первый — отключить ток, сбросив бит 1 порта61h, второй — сбросить бит 0 порта 61h.
Эти две возможности используют для создания различных звуковых эффектов. Сбрасывая и устанавливая эти биты, мыфактически определяем длительность звучания.Если вы внимательно следили за всеми рассуждениями, то, наверное, без трудасможете понять, почему первый канал таймера формирует сигналы аппаратногопрерывания от таймера 18,2 раза в секунду (на основании этих сигналов программы отслеживают время). Для этого BIOS во время загрузки после включения компьютера загружает в первый канал соответствующее значение.Таким образом, наметились три последовательных действия, необходимые дляпрограммирования звукового канала таймера (они применимы и к остальным каналам).1. Посредством порта 43 h выбрать канал, задать режим работы и тип операциипередачи значения в канал. В нашем случае соответствующее значение будетравно 10110110-ОЬ6Ь.2.
Подать ток на динамик, установив бит 1 порта 61h.3. Используя регистр АХ, поместить нужное значение в порт 42h, определив темсамым нужную высоту тона.Далее в листинге 7.1, приведена программа, реализующая некоторые звуки.Многие команды вам уже знакомы, некоторые мы пока еще не рассматривали, поэтому поясним их функциональное назначение. Подробно они будут рассмотреныв последующих главах. Для удобства в программе была использована макрокоманда delay, выполняющая задержку работы программы на заданное время. Подробнее механизм макроподстановок будет рассмотрен в главе 14.
Сейчас толькоотметьте для себя, что введенная таким образом макрокоманда в тексте программы синтаксически ничем не отличается от других команд ассемблера, и это позволяет программисту при необходимости расширить стандартный набор команд ассемблера. Введите текст макрокоманды delay (строки 13-25) и воспринимайте еечисто по функциональному назначению (задержка выполнения программы на промежуток времени, задаваемый значением ее операнда).
Стоит отметить, что данная макрокоманда чувствительна к производительности процессора, из-за чегозвуки на компьютерах с разными моделями процессоров могут не совпадать. Сегмент кода, как обычно, начинается с настройки сегментного регистра DS (строки32-33) на начало сегмента данных. После этого строками 37-38 мы выполняемдействия первого этапа — настройку канала 2, которая заключается в записи в регистр управления (порт 43h) байта состояния OB6h. На втором шаге мы должныустановить биты 0 и 1 порта 61h. Предварительно необходимо извлечь содержимое этого порта. Это делается для того, чтобы выполнять установку битов 0 и 1, неизменяя содержимого остальных битов порта 61h (строки 39-41).
Принцип формирования сигнала сирены заключается в том, что в цикле на единицу изменяетсясодержимое регистра-счетчика и делается небольшая задержка для того, чтобысигнал некоторое время звучал с нужной высотой. Постепенное повышение, а за-Ввод из порта и вывод в порт155тем понижение высоты и дает нам эффект сирены. Строки 43-53 соответствуютциклу, в теле которого высота повышается, а строки 55-62 — циклу понижениятона. Оба цикла повторяются последовательно 5 раз.
Контроль осуществляетсяс помощью переменной cnt, содержимое которой увеличивается на 1 в строке 69и контролируется на равенство 5 в строках 71-72. Если cnt = 5, то команда СМРустанавливает определенные флаги. Последующая команда условного переходаONE анализирует эти флаги и в зависимости от их состояния передает управлениелибо на метку, указанную в качестве операнда этой команды, либо на следующуюза JNE команду.
Цикл в программе ассемблера можно организовать несколькимиспособами; все они будут подробно рассмотрены в главах 10 и 11. В данном случаецикл организуется командой ШОР, которая в качестве операнда имеет имя метки.На эту метку и передается управление при выполнении команды ШОР. Но до тогокак передать управление, команда ШОР анализирует содержимое регистра ЕСХ/СХ,и если оно равно нулю, управление передается не на метку, а на следующую заШОР команду. Если содержимое регистра ЕСХ/СХ не равно нулю, то оно уменьшается на единицу и управление передается на метку.
Таким образом в ЕСХ/СХ хранитсясчетчик цикла. В нашей программе он загружается в ЕСХ/СХ в строках 42 и 54.Листинг 7.1. Реализация сирены<7>-Prg_7_l.asn;Программа,имитирующая звук сирены.;Изменение высоты звука от 450 до 2100 Гц.;Используется макрос delay (задержка).;При необходимости;можно поменять значение задержки (по умолчанию - для процессораPentium).<8> masm<9> modelsmallstack100h<10>;макрос задержки, его текст ограничивается директивами macro и endm.;На входе — значение задержки (в икс)delay macro timeext, iter<14>localpushcx<15><16>movcx, time<17>ext:pushcx<18><19>movcx,5000iter:<20>iterloop<21>cx<22>popext<23>loopcx<24>Popendm<25>сегмент данных.data<26>нижняя граница звучания 450 Гцtonelow dw 2651<27>счетчик для выхода из программыcntdb 0<28>верхняя граница звучанияtempdw 7<29>сегмент кода.code<30>точка входа в программуmain:<31>связываем регистр ds с сегментомmov ax ,@data<32>данных через регистр ахmov ds , ax<33>очищаем ахmov ax ,0<34><35>go:<3б> ;заносим слово состояния 10110110b(0B6h) в командный регистр (порт 43h)продолжение &156Глава 7.
Команды обмена даннымиЛистинг 7.1(продолжение)<37>raov al,0B6h<38>out 43h,al<39>in al,61h;получим значение порта 61h в al<40>oral,3инициализируем динамик и подаем ток в порт 61hout 61h,al<42>mov ex,2083;количество шагов ступенчатого изменения тонаmusicup:<43><44>;в ах значение нижней границы частотыmov ax.tonelow<45><46>out 42h,al;в порт 42п младшее слово ax:al<47>xchg al.ah;обмен между al и ah<48>;в порт 42h старшее слово ах:ahout 42h.aladd tonelow.l<49>;повышаем тон<50>delay 1;задержка на 1 мксmov dx.tonelow ;в dx текущее значение высоты<52>mov temp.dx;temp — верхнее значение высоты;повторить цикл повышения<53>loop musicupвосстановить счетчик цикла<54>mov ex,2083musicdown:<55>;в ах верхнее значение высоты<56>mov ax,temp<57>out 42h,al;в порт 42h младшее слово ax:al;обмен между al и ah<58>mov al.ahout 42h,al;в порт 42h старшее слово ax:ah<59>sub temp.l;понижаем высоту<60>delay 1;задержка на 1 мксloop musicdown ;повторить цикл понижения<62>nosound:<63><64>;получим значение порта 61h в ALin al,61h<65>and al.OFCh;выключить динамик;в порт 61hout 61h,al<66>;для последующих циклов<67>mov dx,2651mov tonelow.dx<68>увеличиваем счетчик проходов, то есть<69>inc cntколичество звучаний сирены<70>5 раз ?cmp cnt,5если нет, идти на метку go<72>jne goexit:<73>mov ах,4с0011;стандартный выход<74>int 21h<75>end m a i n;конец программы<76>Среди файлов, прилагаемых к книге, в каталоге данной главы есть еще одинпример использования команд ввода из порта и вывода в порт — это редакторCMOS-памяти.