Глава 5
Не так давно купил книгу "Рисуем на компьютере" Николая Куприянова. Хорошая книга, небольшого объема. В книге есть ссылки на интересные сайты на тему графики.
http://animasfera.narod.ru сайт Николая Куприянова и Уфимского худож.факультета.
http://ufalend.narod.ru Выставка картин в стиле фэнтези.
http://nimicanime.narod.ru - сайт об анимации Andrey Miller. Много инф о графич. редакторах.
9:20 04.11.2008
Есть такая попытка: если книга в формате djvu то вопрос в следующем: как перевести текст
отображенный на картинке, а в формате djvu все тексты - суть картинки, в txt-формат?
Попробуем это сделать через программу FineReader. Которая может считать с картинки и перевести в текстовый формат.
Так у меня в формате djvu есть книга "The Practice of Programming" Brian Kernigan.
www.all_eBooks.com
http://www.r-hdd.narod.ru -чей это сайт?
**************************************************
Внимание! Файл скачан с портала vsebook.ru
This file was downloaded from vsebook.ru portal
**************************************************
Файл взят с сайта http://www.vsebook.ru/
Там есть ещё множество интересных и редких книг и журналов
Данный файл представлен исключительно
в ознакомительных целях.
7:30 09.11.2008
Дочитал на неделе Дневник Тараса Шевченко. Начал читать его еще на Украине. Случайно взял с полки у Любы, а теперь специально в библиотеке, чтобы дочитать. Какой точный получился снимок с эпохи середины 19-го века! Теперь мне видно стало "откуда ноги растут" у революции 1905 и 1917 года. Отчетливо видна пропасть между "народом" и власть имущими. Еще до отмены крепостного права. И как-то он связал многих выдающихся деятелей того времени. Со многими общался. Присутствует кинематографический эффект. Вполне можно ставить фильм. А может уже и снят он. Ценная книга. Не без юмора.
7:42 09.11.2008
Продолжим "бзик идею" отловить нажатые пользователем клавиши и сохранить их
в памяти компа, а затем в отдельном файле. Для этого воспользуемся программой
из главы 15 книги Калашникова.
Prog01
Оригинальная программа из
главы 15 Калашникова
Поскольку оригинальная программа содержит в себе несколько
резидентов, то мы упростим ее и оставим только ту часть кода, которая
отвечает за клавиатуру.
Prog02
Намеренно упростил предыдущую
программу. Сделали ее резидентной
по прерыванию 09h.
Она делает только то,
что проверяет находится ли она уже в
памяти компа. То есть резидентна ли она.
Если да, то сообщает об этом "Мы уже в памяти!!!"
Кроме этого программа получает скан-код клавиши
из 60h порта, проверяет, не является ли нажатая клавиша
клавишей F12. Если да, то меняем местами бит 1 (on/off)
в переменной Num_status. В противном случае возвращаемся
в оригинальный обработчик.
Код программы:
; === Начало программы: ===
.286
cseg segment
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h
Begin:
jmp Init ;На метку инициализации
; === Процедура обработки 09h прерывания (клавиатура) ===
Int_09h_proc proc
cmp ax,9889h ;Проверка на повторную загрузку в память (см. )
jne Check_funcs
xchg ah,al ;Если это наш "позывной", то даем ответ, меняя местами
iret ;AH/AL и немедленно выходим из 21h...
Check_funcs:
pusha
in al,60h ;Получим скан-код клавиши
cmp al,58h ;Это F12?
jne No_F12 ;Нет - передаем управление оригинальному обработчику
xor cs:Num_status,1 ;Если нажали F12, то меняем местами бит 1 (on/off)
No_F12:
popa
jmp dword ptr cs:[Int_09h_vect] ;Передаем управление оригинальному
;обработчику 09h...
Int_09h_vect dd ? ;Переменная для хранения адреса 09h прерывания
Int_09h_proc endp
; ===============================================================
; Инициализация (подготовка и настройка резидента)
Init:
mov ax,9889h ;Проверим, в памяти ли мы уже или еще нет
int 09h ;9889h - наш позывной
cmp ax,8998h ;Отозвался обработчик (AH/AL должны поменяться местами)?
jne Set_resident
mov ah,9 ;Если в памяти, то выведем соответствующее сообщение
mov dx,offset In_memory
int 21h
ret ;...И вернемся в DOS
Set_resident: ;Если нас в памяти нет, то установим резидент
; Теперь 09h...
mov ax,3509h
int 21h ;Получим и сохраним адрес (вектор) 09h прерывания
mov word ptr Int_09h_vect,bx ;Вначале младшее слово (смещение)...
mov word ptr Int_09h_vect+2,es ;Затем старшее (сегмент)
mov ax,2509h
mov dx,offset Int_09h_proc
int 21h ;"Повесим" нашу процедуру на 09h прерывание
mov ah,9
mov dx,offset Mess_hello
int 21h
mov dx,offset Init
int 27h ;Оставим программу резидентной в памяти.
;================================
In_memory db 'Программа уже загружена в память!!!!',0Ah,0Dh,0Ah
Mess_hello db 'Резидент к книге "Ассемблер? Это просто! Учимся программировать", Глава № 15.',0Ah,0Dh,0Ah
db '"Горячие" клавиши: F12 - вкл./выкл. замену букв и области DTА,',0Ah,0Dh
db ' Shift+PrintScreen - запись содержимого экрана в файл.',0Ah,0Dh,0Ah
db 'Автор: Калашников Олег Александрович (Assembler@Kalashnikoff.ru),',0Ah,0Dh
db 'http://www.Kalashnikoff.ru, Россия, Москва, 2000 год.',0Ah,0Dh,'$'
Num_status db 0
cseg ends
end Begin
Теперь добавим в программу код, который все отловленные
клавиши поместит в массив в памяти.
Вопрос в том, как поместить в массив, находящийся в памяти
данные, находящиеся в al и делать это в цикле.
Эта программа ловит нажатые клавиши и в цикле помещает их скан-код
в массив в памяти.
Массив объявлен так:
mas_b label byte
rept 10
db 00h
endm
Цикл повторить 10 раз.
Прочитать порт 60 поместить скан-код клавиши из al-в массив.
in al,60h ;Получим скан-код клавиши читая порт 60
Код, который должен поместить данные в массив:
mov mas_b[si],al ;запись в массив al
inc si ;продвижение к следующему элементу массива
Программа резидентная. И трудно проверить ее в отладчике,
так как она резидентная и в отладчике можно проследить только от метки Init
и до конца.
Чтобы можно было проверять работу программы в дебуггере, напишем небольшую тестовую программу. Эта программа будет ждать, когда пользователь нажмет
клавишу, чтобы запомнить ее в массиве, а при нажатии Esc или при повторении
цикла 10 раз выведет данные из массива в файл.
Prog11
Эта программа уже ждет пользователя, при помощи функции Wait_key
и запоминает в массив 10 клавиш из порта 60 (их скан-коды).
Выводит в файл, но опять выводит как коды клавиш, а не как скан-коды.
Это уже так интерпретирует комп при выводе на экран, а на самом деле в памяти
- скан-коды нажатых клавиш, в файле - тоже скан-коды нажатых клавиш.
Программа работает правильно! Я проверил другой программой, которая считала
данные из файла, образованного в результате работы этой программы,
в память и оказалось, что в памяти все скан-коды, нажатых нами клавиш.
Еще бы она это делала в случае, когда она является резидентной.
Все таки при нажатии Esc программа хоть и заканчивается, но выдает кучу предупреждений
о том, что надостаточно памяти. И что команда DOS-задана неправильно.
Надо проверять Esc в другом месте программы.
Вот текст программы:
CSEG segment
assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
org 100h
Begin:
mov cx, 10
xor si,si
Next_key:
in al,60h ;Получим скан-код клавиши
;сейчас в al -скан-код клавиши
;теперь надо поместить скан-код клавиши в массив
mov mas_b[si],al ;запись в массив al
inc si ;продвижение к следующему элементу массива
call Wait_key ;Вызываем процедуру ожидания нажатия клавиши
cmp al,27 ;Пользователь нажал ESC?
je Out_prog ;Если так, то на метку Quit_prog
loop Next_key
;---открываем файл с помощью функции "создания"
LEA DX,File_name ;DS:DX указывают на путь к файлу
MOV CX,0 ;атрибуты файлы (здесь обычные)
MOV AH,3CH ;номер функции
INT 21H ;открываем файл
jc Error_file ;Ошибка открытия файла?
MOV Handle,AX ;запоминаем номер файла
;---записываем в файл 10 байтов
MOV AH,40H ;номер функции
MOV BX,Handle ;номер файла в BX
MOV CX,10 ;число байт, которые надо записать
LEA DX,mas_b ;DS:DX указывают на буфер данных
INT 21H ;записываем данные
JC Out_prog ;проверка на ошибки
CMP CX,20 ;и их обработка
JNE Out_prog ;
mov ah,3Eh ;Закрываем файл
mov bx,Handle
int 21h
mov dx,offset Mess_ok
Out_prog:
mov ah,9
int 21h
int 20h ;Выходим из программы
Error_file:
mov dx,offset Mess_error
jmp Out_prog
; === Подпрограммы ===
; --- Wait_key ---
Wait_key proc
mov ah,10h ;Функция 10h прерывания 16h - ожидание нажатия клавиши
int 16h
ret
Wait_key endp
;==== Переменные ======
Handle dw 0
Mess_ok db 'File already in memory! See in debugger!$'
Mess_error db 'Not successful to open (search) file '
File_name db 'c:\TASM\BIN\work\fileOut.out',0,'!$'
mas_b label byte
rept 10
db 00h
endm
CSEG ends
end Begin
Эта программа давала сирену, а мы попробуем,чтобы она просто выдавала небольшой длительности звуковой сигнал одного тона.
Между прочим в директории обращенной к этому уроку у Юрова есть интересная программа, - редактор CMOS-памяти - в которой есть много полезных процедур, в том числе и - процедура вывода дампа памяти. Воспользуйся ими в дальнейшем.
Ну вот немного изменил программу Юрова и она уже выдает какой-то чирикание.
Далее поробуем упростить программу, чтобы она просто выдавала звуковой сигнал.
Чтобы далее можно было вставить этот фрагмент в резидентную программу.
Значительно упростил код предыдущей программы.
По прежнему программа выдает звуковой сигнал.
Как видим в программе создания звукового сигнала участвую порты 42, 43, 61.
Порт 43(порт таймера) - регистр управления, в него мы заносим слово состояния
Порт 42(порт таймера) - регистр ввода/вывода, в него заносим частоту звука
Порт 61 - в этот регистр подаем ток (включаем динамик).
Интересно из книги Юрова (стр 139) о микросхеме таймера:
Микросхема таймера имеет три канала с совершенно одинаковой внутренней структурой и принципом работы. На каждый канал с таймера подаются импульсы от микросхемы системных часов, которые по сути представляют собой генератор импульсов, работающих с частотой 1,19 Мгц. Каждый канал имеет ДВА ВХОДА и ОДИН ВЫХОД.
Выходы каждого канала замкнуты на вполне определенные устройства компа.
Так канал 0 замкнут на контроллер прерываний и является источником аппаратного прерывания из таймера, которое возникает 18,2 раза в секунду.
Канал 1 связан с микросхемой прямого доступа к памяти(DMA).
Канал 2 выходит на динамик компьютера.
Как мы отметили, каналы таймера имеют одинаковую структуру, основу которой составляют три регистра:
регистр ввода/вывода разрядностью 8 бит (порт 42 в нашем случае)
регистр защелка 16 бит
регистр-счетчик 16 бит
Все регистры связаны между собой следующим образом:
В регистр ввода/вывода извне помещается некоторое значение. Источником этого значения может быть либо системное программное обеспечение, либо программа пользователя. Каждый регистр ввода/вывода имеет адрес в адресном пространстве ввода/вывода (номер порта ввода/вывода).
Регистр ввода/вывода канала 2 имеет номер порта ввода/вывода 42h. Помещаемые в него значения немедленно попадают в регистр-защелку, или как его еще называют в регистр-фиксатор, где значения сохраняются до тех пор, пока в регистр ввода/вывода не будет записано новое значение.
Но как спросите вы согласуются эти регистры по их разрядности, ведь один из них 8-, а другой 16-разрядный? Для этого предназначен регистр управления (ему соответствует порт 43).
Он содержит "слово состояния", с помощью которого производится выбор канала, задание режима работы канала и тип операции передачи значения в канал.
Слово состояния имеет следующую структуру:
Бит 0 - определяет тип константы пересчета: 0 - константа задана двоичным числом, 1 - константа задана двоично-десятичным числом (BCD). Константа пересчета - значение, загружаемое извне в регистр-защелку. В нашем случае загружаться будет двоичное число, поэтому значение этого поля будет 0.
Биты 1-3 определяют режим работы таймера. Всего можно определить шесть режимов, но обычно используется третий, поэтому для нашего случая значение - 011.
Биты 4-5 определяют тип операции:
00 - передать значение счетчика в регистр-задвижку (можно прочитать или записать)
01 - записать в регист-задвижку только младший байт
10 - записать в регист-задвижку только старший байт
11 - записать в регист-задвижку сначала старший байт, затем младший
Биты 6-7 определяют номер программируемого канала. В нашем случае значение - 10 (третий канал)
В нашей программе мы поставили значение типа операции 11 (сначала записать старший, а затем младший байт), поэтому формирование 16-битного регистра-защелки через 8-битный регистр ввода/вывода производится следующим образом: запись производится в два приема,
первый байт из регистра ввода/вывода записывается на место старшего байта регистра-защелки, второй байт - на место младшего байта. Не трудно догадаться, что в регистр ввода-вывода эти байты помещаются командами in и out.
mov ax,tonelow
out 42h,al ;в порт 42h младшее слово ax :al
xchg al,ah ;обмен между al и ah
out 42h,al ;в порт 42h старшее слово ax:ah
Таким образом через регистр ввода/вывода (порт 42h) мы записали в регистр-защелку канала
16-разрядное значение в два приема.
После того, как значение из регистра ввода/вывода попало в регистр-защелку, оно моментально
записывается в регистр-счетчик. Сразу же после этого значение регистра-счетчика начинает уменьшаться на единицу с приходом каждого импульса от системных часов.
Prog15
Нерезидентная программа.
Еще упростил предыдущуй программу и она по-прежнему выдает
короткий звук, что мне и надо.
Убрал макрос задержки delay
В таком виде пожалуй программу можо преобразовать в макрос.
Передавая в параметре количество повторений цикла (длину звучания).
;---------Prg_7_1.asm---------------
;Программа, создающая звук .
;------------------------------------
CSEG segment
assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
org 100h
Begin:
xor ax,ax ;очищаем ax
;заносим слово состояния 10110110b(0В6h) в командный регистр (порт 43h)
mov al,0B6h
out 43h,al
in al,61h ;получим значение порта 61h в al
or al,3 ;инициализируем динамик и подаем ток в порт 61h
out 61h,al
mov cx,10000 ;количество повторений тона
;------------------
musicup:
;в ax значение частоты
mov ax,tonelow
out 42h,al ;в порт 42h младшее слово ax :al
xchg al,ah ;обмен между al и ah
out 42h,al ;в порт 42h старшее слово ax:ah
loop musicup ;повторить цикл
;----------------
nosound:
in al,61h ;получим значение порта 61h в AL
and al,0FCh ;выключить динамик
out 61h,al ;в порт 61h
exit:
mov ax,4c00h ;стандартный выход
int 21h
;----------------
tonelow dw 2651 ;нижняя граница звучания = 450 Гц
CSEG ends
end Begin
Ну резидентная программа, которая отлавливает нажатые клавиши и более ничего не делает
у нас есть. Это Prog02. Можно будет вставить этот код в нее.
Но пока далее сделаем небольшую нерезидентную программку, которая отлавливает нажатие клавиши, и выдает при этом звук. Всего пять циклов. Проверим работу макроса Get_Sound
Prog17
Теперь написана нерезидентная программа, правда без макроса, которая отлавливает
клавиши в цикле (10 итераций) и выдает при каждой итерации цикла отлова звук.
Теперь фрагмент программы издающий звук можно вставить в резидентную программу,
отлова клавиш, чтобы фиксировать, что программа работает(бдит) в резидентном режиме
И при этом подает звук при каждом "отлове" клавиши.
За основу возьмем Prog02 которая отлавливает нажатия и больше ничего не делает
Prog18
Резидентная программа.
.286
cseg segment
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h
Begin:
jmp Init ;На метку инициализации
; === Процедура обработки 09h прерывания (клавиатура) ===
Int_09h_proc proc
cmp ax,9889h ;Проверка на повторную загрузку в память (см. )
jne Check_funcs
xchg ah,al ;Если это наш "позывной", то даем ответ, меняя местами
iret ;AH/AL и немедленно выходим из 21h...
Check_funcs:
pusha
in al,60h ;Получим скан-код клавиши
cmp al,1h ;Это Esc?
je Out_prog ;Если так, то на метку Out_prog
;--- дадим короткий звук ----------
push ax
push cx
xor ax,ax ;очищаем ax
;заносим слово состояния 10110110b(0В6h) в командный регистр (порт 43h)
mov al,0B6h
out 43h,al
in al,61h ;получим значение порта 61h в al
or al,3 ;инициализируем динамик и подаем ток в порт 61h
out 61h,al
mov cx,10000 ;количество повторений тона
musicup:
;в ax значение частоты
mov ax,tonelow
out 42h,al ;в порт 42h младшее слово ax :al
xchg al,ah ;обмен между al и ah
out 42h,al ;в порт 42h старшее слово ax:ah
loop musicup ;повторить цикл
nosound:
in al,61h ;получим значение порта 61h в AL
and al,0FCh ;выключить динамик
out 61h,al ;в порт 61h
pop cx
pop ax
;----- конец звука-----------
popa
jmp dword ptr cs:[Int_09h_vect] ;Передаем управление оригинальному
;обработчику 09h...
Out_prog:
mov dx,offset Mess_ok
mov ah,9
int 21h
int 20h ;Выходим из программы
Int_09h_vect dd ? ;Переменная для хранения адреса 09h прерывания
Int_09h_proc endp
; ===============================================================
; Инициализация (подготовка и настройка резидента)
Init:
mov ax,9889h ;Проверим, в памяти ли мы уже или еще нет
int 09h ;9889h - наш позывной
cmp ax,8998h ;Отозвался обработчик (AH/AL должны поменяться местами)?
jne Set_resident
mov ah,9 ;Если в памяти, то выведем соответствующее сообщение
mov dx,offset In_memory
int 21h
ret ;...И вернемся в DOS
Set_resident: ;Если нас в памяти нет, то установим резидент
; Теперь 09h...
mov ax,3509h
int 21h ;Получим и сохраним адрес (вектор) 09h прерывания
mov word ptr Int_09h_vect,bx ;Вначале младшее слово (смещение)...
mov word ptr Int_09h_vect+2,es ;Затем старшее (сегмент)
mov ax,2509h
mov dx,offset Int_09h_proc
int 21h ;"Повесим" нашу процедуру на 09h прерывание
mov ah,9
mov dx,offset Mess_hello
int 21h
mov dx,offset Init
int 27h ;Оставим программу резидентной в памяти.
;================================
tonelow dw 2651 ;нижняя граница звучания = 450 Гц
In_memory db 'Program already in memory!!!!!',0Ah,0Dh,0Ah
Mess_hello db 'Resident from book "Assembler? ',0Ah,0Dh,'$'
Mess_ok db 'File already in memory! See in debugger!$'
Num_status db 0
cseg ends
end Begin
Теперь при запуске из оболочки Norton Commander программа работает нормально в резидентном режиме. Захватывает нажатия клавиш и выдает короткий звук при каждом нажатии клавиши.
При нажатии клавиши Esc программа должна закончиться, но она собщает об исключении
и аварийно прерывается. Надо выяснить какая инструкция вызывает аварию.
Для этого выведем сообщение после нажатия Esc а затем завершимся.
Теперь интересно то, что если я запускаю эту программу из NC, а затем из NC
запуская программу TD.exe то, при работе в программе TD.exe постоянно при каждом
нажатии клавиши слышу звук динамика. То есть наша программа-резидент отлавливает нажатия клавиш и выдает звуки, сообщая, что программа-резидент работает.
Но есть одна маленькая проблема:
Если запустить программу под Windows, то программа работать не будет.
Выяснить и исправить это удастся еще не скоро. Возможно, что программу отлова клавиш можно будет записать на Си.
Prog21
В этой программе нерезидентной соединили Prog11 и Prog17,
программа выдает писк при каждом нажатии,
и записывает все нажатия сначала в память (в массив), а затем в файл.
Всего 10 нажатий.
При последнем 11-том нажатии программа пискнет, ругнется и завершится.
Далее хорошо бы сделать это все в резидентном варианте.
Prog22
Добавим к предыдущей программе переменную для индексации массива
index_mas db 0
Не удалось "запехнуть" в стек переменную index_mas:
**Error** test_15.asm(19) Argument to operation or instruction has illegal size
Оказалось, что эта переменная слишком велика для стека. Нужна переменная величиной в один байт.
При попытке использовать саму переменную в качестве индекса:
mov mas_b[index_mas],al ;запись в массив al
inc index_mas ;продвижение к следующему элементу массива
**Error** test_15.asm(21) Can't add relative quantities
Попробовал такую инструкцию:
**Error** test_15.asm(19) Operand types do not match
Надо было объявить переменную другого типа не db, а dw
index_mas dw 0
Тогда можно работать со стеком без проблем:
push index_mas
pop si
Prog23
К резидентной программе Prog18, рассмотренной нами ранее, добавил код записи в память (в массив) пойманных клавиш.
; === Начало программы: ===
.286
cseg segment
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h
Begin:
jmp Init ;На метку инициализации
; === Процедура обработки 09h прерывания (клавиатура) ===
Int_09h_proc proc
cmp ax,9889h ;Проверка на повторную загрузку в память (см. )
jne Check_funcs
xchg ah,al ;Если это наш "позывной", то даем ответ, меняя местами
iret ;AH/AL и немедленно выходим из 21h...
Check_funcs:
pusha
in al,60h ;Получим скан-код клавиши
cmp al,1h ;Это Esc?
je Out_prog ;Если так, то на метку Out_prog
;сейчас в al -скан-код клавиши
;теперь надо поместить скан-код клавиши в массив
push si
xor si,si
push index_mas
pop si
mov mas_b[si],al ;запись в массив al
pop si
inc index_mas ;продвижение к следующему элементу массива
;--- дадим короткий звук ----------
push ax
push cx
xor ax,ax ;очищаем ax
;заносим слово состояния 10110110b(0В6h) в командный регистр (порт 43h)
mov al,0B6h
out 43h,al
in al,61h ;получим значение порта 61h в al
or al,3 ;инициализируем динамик и подаем ток в порт 61h
out 61h,al
mov cx,10000 ;количество повторений тона
musicup:
;в ax значение частоты
mov ax,tonelow
out 42h,al ;в порт 42h младшее слово ax :al
xchg al,ah ;обмен между al и ah
out 42h,al ;в порт 42h старшее слово ax:ah
loop musicup ;повторить цикл
nosound:
in al,61h ;получим значение порта 61h в AL
and al,0FCh ;выключить динамик
out 61h,al ;в порт 61h
pop cx
pop ax
;----- конец звука-----------
popa
jmp dword ptr cs:[Int_09h_vect] ;Передаем управление оригинальному
;обработчику 09h...
Out_prog:
; mov dx,offset Mess_ok
; mov ah,9
; int 21h
int 20h ;Выходим из программы
Int_09h_vect dd ? ;Переменная для хранения адреса 09h прерывания
Int_09h_proc endp
; ===============================================================
; Инициализация (подготовка и настройка резидента)
Init:
mov ax,9889h ;Проверим, в памяти ли мы уже или еще нет
int 09h ;9889h - наш позывной
cmp ax,8998h ;Отозвался обработчик (AH/AL должны поменяться местами)?
jne Set_resident
mov ah,9 ;Если в памяти, то выведем соответствующее сообщение
mov dx,offset In_memory
int 21h
ret ;...И вернемся в DOS
Set_resident: ;Если нас в памяти нет, то установим резидент
; Теперь 09h...
mov ax,3509h
int 21h ;Получим и сохраним адрес (вектор) 09h прерывания
mov word ptr Int_09h_vect,bx ;Вначале младшее слово (смещение)...
mov word ptr Int_09h_vect+2,es ;Затем старшее (сегмент)
mov ax,2509h
mov dx,offset Int_09h_proc
int 21h ;"Повесим" нашу процедуру на 09h прерывание
mov ah,9
mov dx,offset Mess_hello
int 21h
mov dx,offset Init
int 27h ;Оставим программу резидентной в памяти.
;================================
index_mas dw 0
tonelow dw 2651 ;нижняя граница звучания = 450 Гц
In_memory db 'Program already in memory!!!!!',0Ah,0Dh,0Ah
Mess_hello db 'Resident from book "Assembler? ',0Ah,0Dh,'$'
Mess_ok db 'File already in memory! See in debugger!$'
mas_b label byte
rept 10
db 00h
endm
cseg ends
end Begin
Программа работает. Теперь надо добавить вывод в файл.
Prog24
Вот упрямая программа. Как только добавил код вывода в файл, так перестала работать!
Не пишет в файл. Что не правильно в этом коде? Звуковой сигнал при нажати клавиши выдает.
В память пишет, а в файл нет! Ошибка все равно есть где-то.
Резидентная программа.
.286
cseg segment
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h
Begin:
jmp Init ;На метку инициализации
; === Процедура обработки 09h прерывания (клавиатура) ===
Int_09h_proc proc
cmp ax,9889h ;Проверка на повторную загрузку в память (см. )
jne Check_funcs
xchg ah,al ;Если это наш "позывной", то даем ответ, меняя местами
iret ;AH/AL и немедленно выходим из 21h...
Check_funcs:
pusha
in al,60h ;Получим скан-код клавиши
cmp al,58h ;Это Esc?
je Out_prog ;Если так, то на метку Out_prog
;сейчас в al -скан-код клавиши
;теперь надо поместить скан-код клавиши в массив
push si
xor si,si
push index_mas
pop si
mov mas_b[si],al ;запись в массив al
pop si
inc index_mas ;продвижение к следующему элементу массива
;--- дадим короткий звук ----------
push ax
push cx
xor ax,ax ;очищаем ax
;заносим слово состояния 10110110b(0В6h) в командный регистр (порт 43h)
mov al,0B6h
out 43h,al
in al,61h ;получим значение порта 61h в al
or al,3 ;инициализируем динамик и подаем ток в порт 61h
out 61h,al
mov cx,10000 ;количество повторений тона
musicup:
;в ax значение частоты
mov ax,tonelow
out 42h,al ;в порт 42h младшее слово ax :al
xchg al,ah ;обмен между al и ah
out 42h,al ;в порт 42h старшее слово ax:ah
loop musicup ;повторить цикл
nosound:
in al,61h ;получим значение порта 61h в AL
and al,0FCh ;выключить динамик
out 61h,al ;в порт 61h
pop cx
pop ax
;----- конец звука-----------
popa
jmp dword ptr cs:[Int_09h_vect] ;Передаем управление оригинальному
;обработчику 09h...
Out_prog:
;---открываем файл с помощью функции "создания"
LEA DX,File_name ;DS:DX указывают на путь к файлу
MOV CX,0 ;атрибуты файлы (здесь обычные)
MOV AH,3CH ;номер функции
INT 21H ;открываем файл
jc Error_file ;Ошибка открытия файла?
MOV Handle,AX ;запоминаем номер файла
;---записываем в файл 10 байтов
MOV AH,40H ;номер функции
MOV BX,Handle ;номер файла в BX
MOV CX,10 ;число байт, которые надо записать
LEA DX,mas_b ;DS:DX указывают на буфер данных
INT 21H ;записываем данные
JC Out_prog2 ;проверка на ошибки
CMP CX,10 ;и их обработка
JNE Out_prog2 ;
mov ah,3Eh ;Закрываем файл
mov bx,Handle
int 21h
Out_prog2:
int 20h ;Выходим из программы
Error_file:
mov dx,offset Mess_error
jmp Out_prog2
Int_09h_vect dd ? ;Переменная для хранения адреса 09h прерывания
Int_09h_proc endp
; ===============================================================
; Инициализация (подготовка и настройка резидента)
Init:
mov ax,9889h ;Проверим, в памяти ли мы уже или еще нет
int 09h ;9889h - наш позывной
cmp ax,8998h ;Отозвался обработчик (AH/AL должны поменяться местами)?
jne Set_resident
mov ah,9 ;Если в памяти, то выведем соответствующее сообщение
mov dx,offset In_memory
int 21h
ret ;...И вернемся в DOS
Set_resident: ;Если нас в памяти нет, то установим резидент
; Теперь 09h...
mov ax,3509h
int 21h ;Получим и сохраним адрес (вектор) 09h прерывания
mov word ptr Int_09h_vect,bx ;Вначале младшее слово (смещение)...
mov word ptr Int_09h_vect+2,es ;Затем старшее (сегмент)
mov ax,2509h
mov dx,offset Int_09h_proc
int 21h ;"Повесим" нашу процедуру на 09h прерывание
mov ah,9
mov dx,offset Mess_hello
int 21h
mov dx,offset Init
int 27h ;Оставим программу резидентной в памяти.
;================================
index_mas dw 0
tonelow dw 2651 ;нижняя граница звучания = 450 Гц
In_memory db 'Program already in memory!!!!!',0Ah,0Dh,0Ah
Mess_hello db 'Resident from book "Assembler? ',0Ah,0Dh,'$'
Mess_ok db 'File already in memory! See in debugger!$'
Handle dw 0
Mess_error db 'Not successful to open (search) file '
File_name db 'c:\TASM\BIN\work\fileOut.out',0,'!$'
mas_b label byte
rept 10
db 00h
endm
cseg ends
end Begin
Назад |
Начало урока |
Вверх |
Вперед
Содержание