Вернуться на Страничку новостей.

13.11.2008

Ноябрь
9:55 03.11.2008

Не так давно купил книгу "Рисуем на компьютере" Николая Куприянова. Хорошая книга, небольшого объема. В книге есть ссылки на интересные сайты на тему графики.

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



Prog07

Теперь добавим в программу код, который все отловленные
клавиши поместит в массив в памяти.

Вопрос в том, как поместить в массив, находящийся в памяти
данные, находящиеся в 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


Поскольку вышеуказанная программа, работает правильно. То наша задача внедрить
этот код в резидентную программу. Но поскольку работу резидентной программы не получается отследить в дебуггере, то придумаем, чтобы программа выдавала звуковой сигнал,
в каждый момент, когда она поймает клавишу. Поскольку у меня нет кода, который бы выдавал
звуковой сигнал, воспользуемся программой Prog_7_1.asm из книги Юрова.

Эта программа давала сирену, а мы попробуем,чтобы она просто выдавала небольшой длительности звуковой сигнал одного тона.

Между прочим в директории обращенной к этому уроку у Юрова есть интересная программа, - редактор 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


Hosted by uCoz