Помощь - Поиск - Пользователи - Календарь
Полная версия: Обработка прерываний
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ассемблер
Rocket
Доброго времени суток! Мне нужно реализовать программу, которая выводила бы последовательно цифры от 0 до 9 в одно место экрана. При вводе с клавиатуры какой-либо цифры темп вывода менялся. Значение задержки между выводом очередного символа определяется следующим способом: введённую цифру умножить на 2 в степени 9, это и будет число повторений цикла задержки. Для анализа нажатия клавиши использовать вектор 1Ch. (завершение программы осуществляется при вводе цифры 0)
Проблема возникла непосредственно при написании подпрограммы обработки прерывания 1Ch...
Вот мои наработки по данной программе:

data segment
exit db 0 ;признак завершения программы
sym db "0","1","2","3","4","5","6","7","8","9" ;символ, выводимый на экран
pos dw 3840 ;позиция начального вывода символа
atr db 10 ;атрибут символа(зелёный)
old_cs dw ? ;адрес сегмента старого вектора 1Сh
old_ip dw ? ;адрес смещения старого вектора 1Ch
data ends

code segment
assume cs:code, ds:data

New_1Ch proc ;подпрограмма обработки прерывания 1Ch

iret
New_1Ch endp

ClnScr proc ;программа очистки экрана
push cx
push ax
push si
xor si,si
mov ah, 7
mov dl,' '
mov cx, 2000

cln1:
mov es:[si], ax
inc si
inc si
loop cln1
pop si
pop ax
pop cx
ret
ClnScr endp

Delay proc ;программа задержки
push cx
xor cx,cx
mov cl,9
sal count,cl
xor cx,cx
mov cx,count
d:
loop d
pop cx
ret
Delay endp

Out_Sym proc
push ax
push bx
push si
mov al,[sym+si]
mov ah,atr
mov bx,pos
call Delay
mov es:[bx],ax
pop bx
pop ax
ret
Out_Sym endp

;основная программа
start:
mov ax,data
mov ds,ax

mov ax, 4c00h
int 21h
code ends
end start


Конечно и эти подпрограммы требуют доработок... Вобщем, требуется Ваша помощь... smile.gif
volvo
Ну, с процедурами - это ты сам как нибудь додумаешь, вот основа программы: получение символа через $1C, и вывод счетчика на экран:
.model small
s_data segment

old_cs dw ? ; для хранения «старого» вектора
old_ip dw ? ; прерываний с номером 1Ch

atr db 10 ; атрибут символов (зеленый)
msg db '0' ; строка, выводимая на экран

cycles dw ? ; 1*2^9
multCycle dw 2048 ; 512 - очень мало, задержку побольше
symbol db '1' ; Символ, нажатый пользователем. В начале = "1"
curr db 0 ; Номер символа, который печатается в данный момент
Pressed db 1 ; Нажал ли пользователь чего-нибудь?

; Куда будет выводиться символ
X equ 40
Y equ 14
s_data ends

s_stack segment stack
db 256 dup(?)
s_stack ends

s_code segment
assume cs: s_code, ds: s_data, ss: s_stack

; подпрограмма обработки прерываний 1Ch
new_1c proc far

; Сохраняем значения всех регистров, которые будут меняться
push ax
push bx
push ds
push es

; DS <- сегмент данных
mov ax, s_data
mov ds, ax

; Проверяем, было ли нажатие
mov ax, 40h ; ES <- BIOS
mov es, ax
mov ax, es:[1Ch] ; AX <- Конец буфера клавиатуры
mov bx, es:[1Ah] ; BX <- Начало буфера клавиатуры
cmp bx, ax ; (BX = AX) => Буфер пуст
jne get_char ; Нет

; Да
jmp go_out

get_char:
mov al, es:[bx] ; Забираем символ из буфера
mov es:[1Ch], bx ; Буфер пуст
mov symbol, al
inc Pressed ; Признак нажатия

go_out:
pop es
pop ds
pop bx
pop ax
iret
new_1c endp

start:
mov ax, s_data
mov ds, ax

; Запомним текущий вектор 1ch
mov ah, 35h
mov al, 1Ch
int 21h

mov old_ip, bx
mov old_cs, es

; Подменим обработчик
push ds ; DS:DX <- Новый обработчик
mov dx, offset new_1c
mov ax, seg new_1c
mov ds, ax
mov ah, 25h
mov al, 1Ch
int 21h ; Установили его
pop ds

mov ax, s_data
mov es, ax ; ES <- s_data

; основной цикл программы
main_loop:
cmp Pressed, 0 ; Проверяем, было ли нажатие?
je make_delay ; Нет, идем к паузе

; Да, было... Сбрасываем флаг нажатия, и проверяем,
; если нажат "0" - на выход

mov Pressed, 0
cmp symbol, 30h
je q

xor ax, ax
mov al, symbol
sub al, 30h ; Число, введенное пользователем
mul multCycle ; Домножаем на коэффициент
mov cycles, ax ; И сохраняем в cycles

make_delay:
; У меня ничего не получалось разглядеть, пока я не стал
; повторять эту задержку 3000 раз... Если хочешь - убери этот доп. цикл
mov cx, 3000
m2:
push cx
mov cx, cycles
m1:
nop
loop m1
pop cx
loop m2

mov al, curr
add al, '0'
mov msg[0], al ; Конвертируем curr в символ

xor bh, bh
mov ah, 13h ; Функция вывода строки с атрибутом
mov al, 0
mov dh, Y
mov dl, X
lea bp, msg ; ES:BP <- выводимая строка
mov cx, 1 ; Длина выводимой строки
mov bl, atr
int 10h

; это я добавлял для тестирования,
; в каком порядке выводятся символы
; mov ah, 0eh
; mov al, msg[0]
; mov bh, 0
; int 10h

inc curr
cmp curr, 10 ; Дошли до десятки?
jne main_loop ; Нет еще

; Да, сбрасываем на 0
mov curr, 0
jmp main_loop

q:
; Восстановливаем все назад
push ds

mov dx, old_ip
mov ax, old_cs
mov ds, ax
mov ah, 25h
mov al, 1Ch
int 21h
pop ds

mov ax, 4C00h ; И выходим
int 21h
s_code ends
end start
Rocket
Цитата(volvo @ 15.12.2008 23:02) *
Ну, с процедурами - это ты сам как нибудь додумаешь, вот основа программы: получение символа через $1C, и вывод счетчика на экран:

Большое спасибо за помощь! good.gif
У меня возник ряд вопросов:
1) Директива equ. Я так понимаю, что это объявление данных? Какой директиве она эквивалентна?
2)
mov msg[0], al	
здесь используется относительно регистровая адресация?т.е. адрес вычисляется как сумма содержимого регистра и смещения...
3)

xor bh, bh
mov ah, 13h
mov al, 0
mov dh, Y
mov dl, X
lea bp, msg
mov cx, 1
mov bl, atr
int 10h


Что за прерывание 10h? Как оно организуется,чему оно эквивалентно? например заменить на на функцию 02h, возможно?...
volvo
Цитата(Rocket @ 16.12.2008 18:12) *
У меня возник ряд вопросов:
1) Директива equ. Я так понимаю, что это объявление данных? Какой директиве она эквивалентна?
Это не объявление данных, это просто символическая константа:
Цитата
Директива EQU не определяет элемент данных, но определяет значение, которое может быть использовано для подстановки в других командах.
, то есть везде, где компилятор встречает слово X, он заменяет его на 40. Аналог Сишного #define, обычная текстовая подстановка.

Цитата(Rocket @ 16.12.2008 18:12) *

2)
mov msg[0], al	
здесь используется относительно регистровая адресация? т.е. адрес вычисляется как сумма содержимого регистра и смещения...
Индексная адресация: msg - адрес строки, 0 - смещение.

Цитата(Rocket @ 16.12.2008 18:12) *
Что за прерывание 10h? Как оно организуется,чему оно эквивалентно? например заменить на на функцию 02h, возможно?...
Что за машина КамАЗ? Как она движется? Чему эквивалентна?

Что за вопросы, как организуется 10-е прерывание? Так же, как и все остальные... Оно у тебя что, под запретом? Это нигде не указано.

10H - это так называемое видео-прерывание, занимается обслуживанием монитора. Функция 13H выводит строку с атрибутами, вторая функция досовского прерывания выводит строку без атрибутов, цвет ты уже потеряешь... Не надо никогда пытаться все привести к использованию только одного прерывания. Пользоваться надо тем, что подходит по функциональности. Для работы с видеоадаптером надо пользоваться видеопрерыванием. Недавно у меня на одном из форумов спросили, можно ли избавиться от подключения модуля DOS в программе, "он же нужен всего для одной функции, что надо сделать, чтобы и использовать функцию, и не делать Uses DOS?". А когда ему привели ассемблерный вариант этой функции: "Пользуйся, ты хотел избавиться от модуля? Избавляйся", он почему-то решил не рисковать, и модули не отключил...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.