Листинг 4. На экране инициализировать локальное окно с атрибутом (и текстом). После нажатия командной клавиши окно начинает изменять свои размеры (пульсировать), увеличиваясь и уменьшаясь с определённым периодом. Временной шаг изменения размера окна должен быть много меньше периода пульсации.
mov ax,1003h ;вызов функции установки повышенной яркости
mov bl,0
int 10h
mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
mov ax,1300h ;вывод строки s с атрибутом 02h, длиной 50 символов
mov bx,0002h ;начиная с 1й строки и 10 столбца
mov cx,50
mov dh,1
mov dl,10
lea bp,es:s
int 10h
mov ah,06h ;инициализация локального окна
mov al,0
mov bh,0b4h
mov ch,[row1]
mov cl,[col1]
mov dh,[row2]
mov dl,[col2]
int 10h
mov ax,1300h ;вывод строки s с атрибутом b0h, длиной 8 символов
mov bx,00b0h ;начиная с 9й строки и 33 столбца
mov cx,8
mov dh,9
mov dl,33
lea bp,es:s1
int 10h
repeat: mov ax,0C00h ;очистка буфера клавиатуры
int 21h
mov ah,10h ;функция ввода с клавиатуры
int 16h ;с ожиданием
cmp al,1bh ;нажат Esc?
je outpr1 ;да
cmp al,' ' ;нажат пробел?
je space ;да
jmp repeat ;нажата другая клавиша, повторяем ввод
outpr1:mov ax,4C00h ;завершение программы
int 21h
outpr: mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
mov ax,4C00h ;завершение программы
int 21h
space: mov ax,0C00h ;очистка буфера клавиатуры
int 21h
puls: mov ah,01h ;функция ввода с клавиатуры
int 16h
cmp al,1bh ;нажат Esc?
je outpr ;да
mov ah,10h
mov al,03h
mov bl,1 ;мерцание
int 21h
mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
sub[row1],2
sub[col1],4
add[row2],2
add[col2],4
mov ah,06h ;инициализация локального окна
mov al,0
mov bh,0b4h
mov ch,[row1]
mov cl,[col1]
mov dh,[row2]
mov dl,[col2]
int 10h
mov ax,1300h ;вывод строки s1 с атрибутом b0h, длиной 8 символов
mov bx,00b0h
mov cx,8
mov dh,9
mov dl,33
lea bp,es:s1
int 10h
mov ax,1300h ;вывод строки s2 с атрибутом 02h, длиной 20 символов
mov bx,0002h ;начиная с 1й строки и 10 столбца
mov cx,20
mov dh,1
mov dl,10
lea bp,es:s2
int 10h
jmp tame1
m1: mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
sub[row1],2
sub[col1],4
add[row2],2
add[col2],4
mov ah,06h ;инициализация локального окна
mov al,0
mov bh,0b4h
mov ch,[row1]
mov cl,[col1]
mov dh,[row2]
mov dl,[col2]
int 10h
mov ax,1300h ;вывод строки s1 с атрибутом b0h, длиной 8 символов
mov bx,00b0h
mov cx,8
mov dh,9
mov dl,33
lea bp,es:s1
int 10h
mov ax,1300h ;вывод строки s2 с атрибутом 02h, длиной 20 символов
mov bx,0002h ;начиная с 1й строки и 10 столбца
mov cx,20
mov dh,1
mov dl,10
lea bp,es:s2
int 10h
jmp tame2
m2: mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
add[row1],2
add[col1],4
sub[row2],2
sub[col2],4
mov ah,06h ;инициализация локального окна
mov al,0
mov bh,0b4h
mov ch,[row1]
mov cl,[col1]
mov dh,[row2]
mov dl,[col2]
int 10h
mov ax,1300h ;вывод строки s1 с атрибутом 0fh, длиной 8 символов
mov bx,00b0h
mov cx,8
mov dh,9
mov dl,33
lea bp,es:s1
int 10h
mov ax,1300h ;вывод строки s с атрибутом 02h, длиной 20 символов
mov bx,0002h ;начиная с 1й строки и 10 столбца
mov cx,20
mov dh,1
mov dl,10
lea bp,es:s2
int 10h
jmp tame3
m3: mov ah,06h ;очистка экрана
mov al,0
mov bh,0fh
mov ch,0
mov cl,0
mov dh,40
mov dl,80
int 10h
add[row1],2
add[col1],4
sub[row2],2
sub[col2],4
mov ah,06h ;инициализация локального окна
mov al,0
mov bh,0b4h
mov ch,[row1]
mov cl,[col1]
mov dh,[row2]
mov dl,[col2]
int 10h
mov ax,1300h ;вывод строки s1 с атрибутом 0fh, длиной 8 символов
mov bx,00b0h
mov cx,8
mov dh,9
mov dl,33
lea bp,es:s1
int 10h
mov ax,1300h ;вывод строки s с атрибутом 02h, длиной 20 символов
mov bx,0002h ;начиная с 1й строки и 10 столбца
mov cx,20
mov dh,1
mov dl,10
lea bp,es:s2
int 10h
jmp tame4
tame1: mov ah,0 ;Функция "чтения" циклов таймера
int 1Ah ;Получаем значение счетчика циклов в cx:dx
add dx,18 ;Добавляем 2 сек. к младшему слову в dx
mov bx,dx ;Запоминаем требуемое значение в bx и выполняем
;постоянную проверку значений счетчика времени суток
repeat1: int 1Ah ;Вновь получаем значение счетчика
cmp dx,bx ;Сравниваем с искомым
jne repeat1 ;Если не равно, то повторяем снова,
;иначе задержка окончена
jmp m1
tame2: mov ah,0
int 1Ah
add dx,18
mov bx,dx
repeat2: int 1Ah
cmp dx,bx
jne repeat2
jmp m2
tame3: mov ah,0
int 1Ah
add dx,18
mov bx,dx
repeat3: int 1Ah
cmp dx,bx
jne repeat3
jmp m3
tame4: mov ah,0
int 1Ah
add dx,18
mov bx,dx
repeat4: int 1Ah
cmp dx,bx
jne repeat4
jmp puls
cseg ends
end begin
Окна, демонстрирующие работу программы:
Листинг 5. Программа демонстрирует применение функций BIOS при работе с экраном и клавиатурой. Особенностью программы является широкое использование макросов. Макросы – эффективное языковое средство ассемблера, облегчающее разработку, модификацию и чтение программ. Приведённые ниже примеры макросов на основе функций BIOS, следует рассматривать лишь как один из возможных вариантов, так как структура макросов и реализуемые ими функции зависят как от целевого назначения программы, так и от стиля программирования.
Comment /* Программа инициализирует экран и вводит 2 локальных окна. Командой <F1> устанавливается режим перетаскивания данных, контролируемых курсором, с одного окна в другое. Меню управления курсором, считыванием и записью символов в позиции курсора, содержится в служебном сообщении на экране. В качестве исходных данных предлагаются символы таблицы ASCII, которые выводятся в левое окно клавишей <F2>. Командой <F4> для окна_2 вводится режим блокнота для набора произвольного текста с клавиатуры с возможностью редактирования клавишей <Backspace>. Из режима блокнота можно снова перейти в режим перетаскивания данных, нажав клавишу <F1>. */
Ideal
P386N
MODEL small
Stack 256
;Макросы
;Макрос инициализации окна с цветом (N=0) или его скроллинг вверх на N-строк
;Входные значения: N- параметр, определяющий назначение макроса,
; attrib- атрибут цвета,
; y1,x1- текстовые координаты левого верхнего угла окна,
; y2,x2- текстовые координаты правого нижнего угла окна.
;Выход отсутствует.
MACRO window N,attrib,y1,x1,y2,x2
mov ah,06h ;Функция инициализация окна или его скроллинг вверх
mov al,N
mov bh,attrib ;Атрибут цвета
mov ch,y1 ;Координаты левого верхнего угла (у1,х1)
mov cl,x1
mov dh,y2 ;Координаты правого нижнего угла (у2,х2)
mov dl,x2
int 10h
ENDM window
;Макроопределение locate позиционирования курсора в произвольную точку экрана (y,x) с
;запоминанием координат переменными row_k,col_k (k- номер локального окна).
;Входные значения: определены в описании макроса.
;Выход: row_k= dh= y, col_k= dl= x.
MACRO locate y,x,k
mov ah,02h ;Функция позиционирования курсора
mov bh,0 ;Номер страницы
mov dh,y
mov dl,x
mov [row_&k],dh
mov [col_&k],dl
int 10h
ENDM locate
;Макрос вывода сообщения mes, длиной leng, атрибутом цвета attrib и с позиции (row_k,
;col_k), здесь k -номер окна. После вывода сообщения курсор перемещается в его конец.
;Если сообщение не укладывается в одну строку можно применить
; управляющие коды 10h (перевод строки) и 13h (возврат каретки).
;Входные значения: определены в описании макроса. Выход: отсутствует.
MACRO out_str mes,leng,attrib,k
mov ah,13h
mov al,1 ;Признак смещения курсора в конец строки
mov bh,0 ;Номер видеостраницы
mov bl,attrib
mov cx,leng
mov dh,[row_&k]
mov dl,[col_&k]
mov bp,offset mes ;Адрес строки ES:BP
int 10h
ENDM out_str
;Запись символа с текущим атрибутом на экран в позицию курсора
;Входные значения: AL= ASCII- код символа, BH,CX= номер видеостраницы и число пов-
;торений символа. Выход отсутствует.
Macro write
mov ah,0Ah ;Функция записи символа с текущим атрибутом
mov al,[ASCIIchar] ;ASCII- код символа
mov bh,0
mov cx,1 ;Число повторений символа
int 10h
Endm write
;Чтение символа и атрибута в позиции курсора и запись их в память для хранения.
;Входные значения: BH= номер страницы.
;Выход: AX= AH:AL= "атрибут: ASCII-код символа" этих параметров
; (дополнительно, эти параметры сохраняются переменными attrib и ASCIIchar).
Macro read
push bx
mov ah,08h ;Функция чтение символа и атрибута
mov bh,0
int 10h
mov [attrib],ah ;Сохраним атрибут и
mov [ASCIIchar],al ;символ
pop bx
Endm read
;Копирование символа в позиции курсора с его удалением. Удаление осуществляется
;записью пробела с сохранением в данной позиции текущего атрибута.
;Входные значения: отсутствуют.
;Выход: AX= AH:AL= "атрибут: ASCII-код символа" (дополнительно, эти параметры
;сохраняются переменными attrib и ASCIIchar).
Macro read_del
Read ;Сохраним атрибут и символ
mov ah,09h ;Функция записи символа с заданными атрибутами на эк-ран
mov al,20h ;Поместим ASCII- код пробела и текущий атрибут
mov bl,[attrib]
mov cx,1
int 10h
Endm read_del
crlf equ 13,10,5 DUP(20h)
crlf2 equ 13,10,42 DUP(20h)
Dataseg
ExCode DB 0
mes0 DB '<F1> - transferring simbols'
DB crlf,'<F2> - output table ASCII in left window'
;Вывод изображения всех символов таблицы ASCII, включая управляющие,
; в окно_1 в формате "16 x16". Символы в строке разделяются пробелами.
F2: mov ah,03h ;считаем текущее положение курсора
mov bh,0
int 10h ;Dh= номер строки, DL= номер столбц
mov [stroka],dx
locate 8,7,1 ;row_1=8, col_1=7
mov al,0 ;Первый символ ASCII с кодом 00h
mov cx,256 ;Счётчик циклов вывода
;Вывод символа любого кода ASCII, (включая управляющие) из AL в позицию курсора с
;координатами row_1, col_1 в окно_1 c последующим увеличением координаты курсора в
;строке на 2 позиции вправо
cycle: push cx
mov ah,0Ah ;Функция вывода символа с текущим атрибутом из al
mov bh,0 ;Номер страницы
mov cx,1 ;Число повторений символа
int 10h ;Вывести символ в текущую позицию
inc al ;Следующий символ
test al,0Fh ;Если al не кратен 16
jnz L1 ;продолжить вывод в строке,
add [row_1],1 ;иначе увеличить номер строки на 2
mov [col_1],7 ;Столбец = 7
jmp L2
L1: add [col_1],2 ;Увеличить номер столбца на 2
L2: mov dh,[row_1]
mov dl,[col_1]
mov ah,2 ;Функция установки курсора
int 10h ;Переместить курсор в позицию row_1, col_1
pop cx
loop cycle
mov dx,[stroka]
mov ah,02h ;Установить новую позицию курсора
mov bh,0
int 10h
jmp [F2ex]
;Режим <F4>- вывод текста в окно_2 (блокнот). Переход на новую строку осуществляется ;кл. <Enter> с ASCII- кодом 0Dh, допускается редактирование текста клавишей <Backspace>
F4: locate 8,44,2
repet: mov ax,offset $
mov [f2ex],ax
mov ax,0C00h ;Очистка буфера клавиатуры
int 21h
mov ah,08h ;Функция ввода ASCII- символа в AL без эха
int 21h ;ASCII- код в AL
cmp al,00h ;Расширенный ASCII?
je ex_ascii ;Да
cmp al,08h ;Управляющий код "назад"
je erase ;Да, сотрём предыдущий символ
cmp al,0Dh ;ASCII- код равен 0Dh?
jne out_symb ;Нет, выводим символ на экран
mov ah,03h ;Да, переходим на новую строку. Для этого
;вызовем функцию считывания текущей позиции курсора
mov bh,0 ;Номер страницы
int 10h ;Номер строки в DH, столбца в DL
add dh,1 ;Формирование координаты новой строки
mov dl,44 ;в окне_2
cmp dh,24 ;Номер следующей строки равен 23?
je scroll ;Да, надо произвести прокрутку окна
position: mov ah,02h ;Функция установки позиции курсора
int 10h ;Курсор установлен
jmp repet ;Продолжим вывод текста
scroll: push dx
Window 4,0E4h,8,42,23,76 ;Прокрутка на 4 строки вверх
pop dx
sub dh,4 ;Декремент строки на параметр прокрутки
mov bh,0 ;Номер страницы
jmp position
out_symb: mov ah,0Eh ;Функция вывода символа с текущим атрибутом
mov bh,0 ;в режиме телетайпа
int 10h ;Символ выведен
mov ah,03h ;считаем текущее положение курсора
mov bh,0
int 10h ;Dh= номер строки, DL= номер столбц
cmp dl,77
jne repet
cmp dh,23
je @@8
inc dh
mov dl,42
mov ah,02h ;Установить новую позицию курсора
mov bh,0
int 10h
jmp repet
@@8: push dx
Window 4,0E4h,8,42,23,76 ;Прокрутка на 4 строки вверх
pop dx
sub dh,3 ;Декремент строки на параметр прокрутки
mov bh,0 ;Номер страницы
mov dl,42
mov ah,02h ;Установить новую позицию курсора
mov bh,0
int 10h
jmp repet
;Стирание предыдущего символа путём вывода последовательности 08h, 20h, 08h
erase: mov ah,03h ;считаем текущее положение курсора
mov bh,0
int 10h ;Dh= номер строки, DL= номер столбц
cmp dl,42
jne @@6
cmp dh,8
je repet
dec dh
mov dl,77
mov ah,02h ;Установить новую позицию курсора
mov bh,0
int 10h
@@6: mov cx,3
mov si,0
@@3: mov al,[backspace+si]
inc si
mov ah,0Eh ;Функция вывода символа с текущим атрибутом в
mov bh,0 ;в режиме телетайпа
int 10h ;Символ выведен
loop @@3
jmp repet
;Проверка запроса о выходе из режима набора текста в режим перетаскивания символов<F1>
ex_ascii: mov ah,08h ;Введём старший байт ASCII- кода
int 21h
cmp al,3Bh ;Скан-код клавиши <F1>?
je F1 ;Да, переходим в режим <F1>
cmp al,3Ch ;Нажата <F2>?
je F2 ;Да
cmp al,3Dh ;нажата <F3>?
je F32 ;Да
cmp al,44h ;Скан-код клавиши <F10>?
je F10 ;Да, выходим из программы
jmp repet ;Нет, остаёмся в данном режиме
f32: window 0,0E4h,8,42,23,76 ;Очистка окна_2
locate 8,44,2
jmp repet
;Выход из программы с восстановлением режима обычной яркости
F10: mov ax,1003h ;Вызов функции
mov bl,1 ;Мерцание символа
int 10h
Exit: mov ax,4C00h ;Функция DOS 4Сh:выход из программы
int 21h ;Вызов DOS. Останов
END Start ;Конец программы/точка входа
Окно, демонстрирующее работу программы:
Список литературы
1. Справочник ассемблера IBM PC
2.АфанасьевВ.А.Assembler IBM PC: Учебное пособие. Ч.1. Лабораторный практикум. Новосибирск: Изд-во НГТУ, 2008. – 115 с.
3. Рудаков П.И., Финогенов К.Г."Программируем на языке ассемблера IBM PC"