Помощь - Поиск - Пользователи - Календарь
Полная версия: Обработка прерываний
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Assembler
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?". А когда ему привели ассемблерный вариант этой функции: "Пользуйся, ты хотел избавиться от модуля? Избавляйся", он почему-то решил не рисковать, и модули не отключил...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.