Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.234.139.149] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Всем доброго времени суток,
Задание такое (делается в emu8086): Пользователь вводит координаты левого верхнего (x1, y1) и правого нижнего (x2, y2) углов прямоугольника. Программа должна нарисовать прямоугольник на экране и вывести его периметр (P) и площадь (S). Примечание: Для ввода/вывода использовать прерывания (INT). Не использовать никакие команды "emu, macro" и т.п. Вот код: include 'emu8086.inc' org 100h jmp kod dannie: dlina dw 0 sirina dw 0 xkord dw 0 ykord dw 0 plosiad dw 0 perimetr dw 0 msg1 db 'Vvedite x koordinatu centra priamougolnika:', '$' msg2 db 'Vvedite y koordinatu centra priamougolnika:', '$' msg3 db 'Vvedite sirinu priamougolnika:', '$' msg4 db 'Vvedite dlinu priamougolnika:', '$' msg5 db 'Plosiad Vasego priamougolnika ravna: ', '$' msg6 db 'Dlina Vashego priamougolnika ravna: ', '$' msg7 db 'Certim? (Nazmite liubuiu klavishu)', '$' p1 dw 0 ;x konec verhnei linii p2 dw 0 ;y konec levoi linii p3 dw 0 ;x konec niznei linii p4 dw 0 ;y konec pravoi linii kod: ;--vivodim znacenia mov dx, offset msg1 mov ah, 9 int 21h call scan_num mov xkord, cx call CLEAR_SCREEN mov dx, offset msg2 mov ah, 9 int 21h call scan_num mov ykord, cx call CLEAR_SCREEN mov dx, offset msg3 mov ah, 9 int 21h call scan_num mov sirina, cx call CLEAR_SCREEN mov dx, offset msg4 mov ah, 9 int 21h call scan_num mov dlina, cx ;-- ;--scitaem plosiad i perimetr mov al, b.[dlina] mov bl, b.[sirina] mul bl mov plosiad, ax mov bx, 0 add bx, sirina add bx, sirina add bx, dlina add bx, dlina mov perimetr, bx call CLEAR_SCREEN mov dx, offset msg5 mov ah, 9 int 21h mov dx, offset msg6 mov ah, 9 int 21h mov dx, offset msg7 mov ah, 9 int 21h mov ah, 0 int 16h ;--nahodim verhniy praviy ugol priamogugolnika mov ax, xkord mov bl, 2 div bl mov b.[xkord], al mov ax, ykord mov bl, 2 div bl mov b.[ykord], al ;-- ;--vistavliaem video rezim 320x200, 256 cvetov mov al, 13h mov ah, 0 int 10h ;-- mov cx, xkord mov dx, ykord mov bx,dlina add bx,xkord mov p1, bx ;--certim verhniuiu liniu mov al, 50 verhniaiaLinia: mov ah, 0ch int 10h inc cx cmp cx,p1 JNAE verhniaiaLinia ;-- mov cx, xkord mov dx, ykord mov bx, ykord add bx, sirina mov p2, bx ;--certim levuiu liniu levaiaLinia: mov ah,0ch int 10h inc dx cmp dx,p2 JNAE levaiaLinia ;-- mov bx, cx add bx, dlina mov p3, bx ;--certim nizniuiu liniu nizniaiaLinia : mov ah,0ch int 10h inc cx cmp cx,p3 JNAE nizniaiaLinia ;-- mov bx,ykord mov p4, bx ;--certim pravuiu liniu pravaiaLinia: mov ah,0ch int 10h dec dx cmp dx,p4 JNB pravaiaLinia ret DEFINE_SCAN_NUM DEFINE_CLEAR_SCREEN end 1. По заданным координатам прямоугольник чертится, с этим проблем нет, но почему-то не выводятся площадь и периметр,хотя, вроде как, должны. 2. Можно ли сократить код? Ибо преподу может не понравится такой длинный код. Заранее благодарю за оказанную помощь. |
Сообщ.
#2
,
|
|
|
Можно! Всякие такие вещи
Цитата Oxidous @ можно сократить до:mov bx, 0 add bx, sirina add bx, sirina add bx, dlina add bx, dlina mov bx, sirina add bx, dlina shl bx, 1; умножаем всё на 2 |
Сообщ.
#3
,
|
|
|
Огромное Вам спасибо
А можно ли чем то заменить директиву "include emu8086.inc"? Просто препод хочет,чтоб не использовались директивы и всякие команды macro. Чем тогда можно заменить "call scan_num" и "call CLEAR_SCREEN"? Чтоб убрать из программы emu8086.inc? |
Сообщ.
#4
,
|
|
|
Цитата Oxidous @ Например, так:Чем тогда можно заменить "call CLEAR_SCREEN"? dannie: clrScr db 27, '[2J' ; Esc-последовательность чистки экрана ;... ;вместо 'call CLEAR_SCREEN', это: mov AH, 9 mov DX, offset clrScr int 21h |
Сообщ.
#5
,
|
|
|
Благодарю Вас за ответ
Я вытащил код из emu8086.inc и с CLEAR_SCREEN' ом разобрался Вот сам код CLEAR_SCREEN: PUSH AX ; store registers... PUSH DS ; PUSH BX ; PUSH CX ; PUSH DI ; MOV AX, 40h MOV DS, AX ; for getting screen parameters. MOV AH, 06h ; scroll up function id. MOV AL, 0 ; scroll all lines! MOV BH, 07 ; attribute for new lines. MOV CH, 0 ; upper row. MOV CL, 0 ; upper col. MOV DI, 84h ; rows on screen -1, MOV DH, [DI] ; lower row (byte). MOV DI, 4Ah ; columns on screen, MOV DL, [DI] DEC DL ; lower col. INT 10h ; set cursor position to top ; of the screen: MOV BH, 0 ; current page. MOV DL, 0 ; col. MOV DH, 0 ; row. MOV AH, 02 INT 10h POP DI ; re-store registers... POP CX ; POP BX ; POP DS ; POP AX Но думаю,что лучше использую Ваш код,ибо он более короткий Только не получается понять,как вставить код SCAN_NUM. Вот вытащенный код CAN_NUM из emu8086.inc: DEFINE_SCAN_NUM MACRO LOCAL make_minus, ten, next_digit, set_minus LOCAL too_big, backspace_checked, too_big2 LOCAL stop_input, not_minus, skip_proc_scan_num LOCAL remove_not_digit, ok_AE_0, ok_digit, not_cr ; protect from wrong definition location: JMP skip_proc_scan_num SCAN_NUM PROC NEAR PUSH DX PUSH AX PUSH SI MOV CX, 0 ; reset flag: MOV CS:make_minus, 0 next_digit: ; get char from keyboard ; into AL: MOV AH, 00h INT 16h ; and print it: MOV AH, 0Eh INT 10h ; check for MINUS: CMP AL, '-' JE set_minus ; check for ENTER key: CMP AL, 13 ; carriage return? JNE not_cr JMP stop_input not_cr: CMP AL, 8 ; 'BACKSPACE' pressed? JNE backspace_checked MOV DX, 0 ; remove last digit by MOV AX, CX ; division: DIV CS:ten ; AX = DX:AX / 10 (DX-rem). MOV CX, AX PUTC ' ' ; clear position. PUTC 8 ; backspace again. JMP next_digit backspace_checked: ; allow only digits: CMP AL, '0' JAE ok_AE_0 JMP remove_not_digit ok_AE_0: CMP AL, '9' JBE ok_digit remove_not_digit: PUTC 8 ; backspace. PUTC ' ' ; clear last entered not digit. PUTC 8 ; backspace again. JMP next_digit ; wait for next input. ok_digit: ; multiply CX by 10 (first time the result is zero) PUSH AX MOV AX, CX MUL CS:ten ; DX:AX = AX*10 MOV CX, AX POP AX ; check if the number is too big ; (result should be 16 bits) CMP DX, 0 JNE too_big ; convert from ASCII code: SUB AL, 30h ; add AL to CX: MOV AH, 0 MOV DX, CX ; backup, in case the result will be too big. ADD CX, AX JC too_big2 ; jump if the number is too big. JMP next_digit set_minus: MOV CS:make_minus, 1 JMP next_digit too_big2: MOV CX, DX ; restore the backuped value before add. MOV DX, 0 ; DX was zero before backup! too_big: MOV AX, CX DIV CS:ten ; reverse last DX:AX = AX*10, make AX = DX:AX / 10 MOV CX, AX PUTC 8 ; backspace. PUTC ' ' ; clear last entered digit. PUTC 8 ; backspace again. JMP next_digit ; wait for Enter/Backspace. stop_input: ; check flag: CMP CS:make_minus, 0 JE not_minus NEG CX not_minus: POP SI POP AX POP DX RET make_minus DB ? ; used as a flag. ten DW 10 ; used as multiplier. SCAN_NUM ENDP skip_proc_scan_num: DEFINE_SCAN_NUM ENDM |
Сообщ.
#6
,
|
|
|
Цитата Oxidous @ А внутри ещё и макрос PUTC, т.е. его надо будет вытащить. И понеслось... Вот вытащенный код CAN_NUM из emu8086.inc |
Сообщ.
#7
,
|
|
|
Да, Вы правы, если отключить include 8086.inc, то работать перестаёт и выдаёт ранее описанные ошибки
А как можно вытащить данный макрос или быть может есть какая-либо альтернатива SCAN_NUM? Полная мозголомка... Сейчас программа выглядит уже так: include 'emu8086.inc' ; подключение директивы org 100h ; приветствие mov dx, offset msg1 mov ah, 9 int 21h call scan_num ; очистка экрана call CLEAR_SCREEN ; вывод значений mov dx, offset msg2 mov ah, 9 int 21h call scan_num mov xkord, cx call CLEAR_SCREEN mov dx, offset msg3 mov ah, 9 int 21h call scan_num mov ykord, cx call CLEAR_SCREEN mov dx, offset msg4 mov ah, 9 int 21h call scan_num mov shirina, cx call CLEAR_SCREEN mov dx, offset msg5 mov ah, 9 int 21h call scan_num mov dlina, cx ; вычисляем площадь и периметр прямоугольника ; площадь прямоугольника mov ax, dlina mul shirina mov plosiad, ax ; периметр прямоугольника mov bx, shirina add bx, dlina add bx, bx mov perimetr, bx call CLEAR_SCREEN mov dx, offset msg6 mov ah, 9 int 21h mov dx, offset msg7 mov ah, 9 int 21h mov dx, offset msg8 mov ah, 9 int 21h mov ah, 0 int 16h ; находим правый верхний угол прямоугольника mov ax, xkord mov bl, 2 div bl mov b.[xkord], al mov ax, ykord mov bl, 2 div bl mov b.[ykord], al ; выставляем видео режим 640x480, 16 цветов mov al, 12h mov ah, 0 int 10h mov cx, xkord mov dx, ykord mov bx,dlina add bx,xkord mov p1, bx ; чертим верхнюю линию mov al, 50 VerhLinia: mov ah, 0ch int 10h inc cx cmp cx,p1 JNAE VerhLiniia mov cx, xkord mov dx, ykord mov bx, ykord add bx, shirina mov p2, bx ; чертим левую линию LevLinia: mov ah,0ch ; левая линия фиолетового цвета mov al, 5 int 10h inc dx cmp dx,p2 JNAE LevLinia mov bx, cx add bx, dlina mov p3, bx ; чертим нижнюю линию NiznLinija: mov ah,0ch ; нижняя линия красного цвета mov al, 4 int 10h inc cx cmp cx,p3 JNAE NiznLinia mov bx,ykord mov p4, bx ; чертим правую линию PravLinija: mov ah,0ch ; правая линия голубого цвета mov al, 3 int 10h dec dx cmp dx,p4 JNB PravLinia ret ; процедура CLEAR_SCREEN CLEAR_SCREEN PROC NEAR PUSH AX ; store registers... PUSH DS ; PUSH BX ; PUSH CX ; PUSH DI ; MOV AX, 40h MOV DS, AX ; for getting screen parameters. MOV AH, 06h ; scroll up function id. MOV AL, 0 ; scroll all lines! MOV BH, 07 ; attribute for new lines. MOV CH, 0 ; upper row. MOV CL, 0 ; upper col. MOV DI, 84h ; rows on screen -1, MOV DH, [DI] ; lower row (byte). MOV DI, 4Ah ; columns on screen, MOV DL, [DI] DEC DL ; lower col. INT 10h ; set cursor position to top ; of the screen: MOV BH, 0 ; current page. MOV DL, 0 ; col. MOV DH, 0 ; row. MOV AH, 02 INT 10h POP DI ; re-store registers... POP CX ; POP BX ; POP DS ; POP AX ; RET CLEAR_SCREEN ENDP dlina dw 0 shirina dw 0 xkord dw 0 ykord dw 0 plosiad dw 0 perimetr dw 0 msg1 db 'Pogrammu napisal: Imia Familija. Nazmite <Enter> ', '$' msg2 db 'Vvedite X koordinatu centra priamougolnika: ', '$' msg3 db 'Vvedite Y koordinatu centra priamougolnika: ', '$' msg4 db 'Vvedite shirinu priamougolnika (max 480): ', '$' msg5 db 'Vvedite dlinu priamougolnika (max 640): ', '$' msg6 db 'Plosiad Vashego priamougolnika: ', '$' msg7 db 'Perimetr vashego priamougolnika: ', '$' msg8 db 'Dlia sozdanija priamougolnika nazmite <ENTER>', '$' p1 dw 0 ;конец верхней линии x p2 dw 0 ;конец левой линии y p3 dw 0 ;конец нижней линии x p4 dw 0 ;конец правой линии y DEFINE_SCAN_NUM end |
Сообщ.
#8
,
|
|
|
Можно сократить очистку:
CLEAR_SCREEN PROC NEAR mov AX, 0B800h ; адрес видеопамяти mov CX, 80*25 ; сколько символов сотрём mov ES, AX ; ибо напрямую нельзя xor DI, DI ; стирать с начала будем ES:DI mov AX, 0F20h ; белыми пробелами забивать будем rep STOSW ;символ с цветом (2 байта) кидаем в цикле RET CLEAR_SCREEN ENDP Добавлено Цитата Oxidous @ Да, можно самому так написать:быть может есть какая-либо альтернатива SCAN_NUM? MY_SCAN_NUM PROC NEAR mov AH, 2 mov DL, '>' ; приглашение int 21h ; выводим приглашение xor DI, DI ; итоговое число, - пока ноль my_input: mov AH, 8 ; ввод символа без показа int 21h cmp AL, 13 ; Enter нажали ? je Oxid_vihod ; да - уходим cmp AL, '9' ja my_input ; какую-то бОльшую букву ввели - игнорируем cmp AL, '0' jb my_input ; какую-то меньшую букву ввели - игнорируем mov AH, 2 mov DL, AL ; цифра int 21h ; выводим цифру sub AL, '0' ; преобразуем символ в число 0..9 xor AH, AH ; AH = 0 mov CX, AX ; цифра теперь в CX mov AX, DI ; в AX наш итог mov BX, 10 ; десятичная у нас система ввода mul BX ; AX = AX*10 add AX, CX ; добавим нашу цифру mov DI, AX ; результат в DI jmp my_input ; на следующую цифру Oxid_vihod: mov CX, DI ; запишем результат RET ; валим MY_SCAN_NUM ENDP |
Сообщ.
#9
,
|
|
|
Славян
Огромное Вам спасибо А что за метка "je Oxid_vihod" ? Потому как программа ругается и выдаёт ошибку: undeclared label: je Oxid_vihod Include 'emu8086.inc' и DEFINE_SCAN_NUM (в конце кода) я закомментировал, Ваш код вставил в ret, сразу после процедуры CLEAR_SCREEN, соответственно в программе вызов с "call scan_num" заменил на "call MY_SCAN_NUM". Не могли бы Вы пояснить "je Oxid_vihod" и где в коде теперь вставить "Oxid_vyhod", чтоб ошибка исчезла? |
Сообщ.
#10
,
|
|
|
Цитата Oxidous @ Смотрите внимательнее: у меня всюду слово так написано Oxid_vihod, а у вас где-то описка в букве "Oxid_vyhod". Не могли бы Вы пояснить "je Oxid_vihod" и где в коде теперь вставить "Oxid_vyhod", чтоб ошибка исчезла? |
Сообщ.
#11
,
|
|
|
Вот рабочий вариант:
код ;.286 .model tiny CODE SEGMENT org 100h ASSUME CS:CODE ;, DS:CODE, ES:CODE start: jmp start1 dlina dw 0 shirina dw 0 xkord dw 0 ykord dw 0 plosiad dw 0 perimetr dw 0 otvet db 0,'$',10,13,'$' p1 dw 0 ;конец верхней линии x p2 dw 0 ;конец левой линии y p3 dw 0 ;конец нижней линии x p4 dw 0 ;конец правой линии y start1: mov dx, offset msg1 mov ah, 9 int 21h call MY_SCAN_NUM1 ;scan_num ; очистка экрана call CLEAR_SCREEN ; вывод значений mov dx, offset msg2 mov ah, 9 int 21h call MY_SCAN_NUM1 ;scan_num mov xkord, cx call CLEAR_SCREEN mov dx, offset msg3 mov ah, 9 int 21h call MY_SCAN_NUM1 ;scan_num mov ykord, cx call CLEAR_SCREEN mov dx, offset msg4 mov ah, 9 int 21h call MY_SCAN_NUM1 ;scan_num mov shirina, cx call CLEAR_SCREEN mov dx, offset msg5 mov ah, 9 int 21h call MY_SCAN_NUM1 ;scan_num mov dlina, cx ; вычисляем площадь и периметр прямоугольника ; площадь прямоугольника mov ax, dlina mul shirina mov plosiad, ax ; периметр прямоугольника mov bx, shirina add bx, dlina add bx, bx mov perimetr, bx mov word ptr otvet, bx call CLEAR_SCREEN mov dx, offset msg6 mov ah, 9 int 21h mov DX, offset otvet ; вывод периметра int 21h mov dx, offset msg7 mov ah, 9 int 21h mov dx, offset msg8 mov ah, 9 int 21h mov ah, 0 int 16h ; находим правый верхний угол прямоугольника mov ax, xkord mov bl, 2 div bl mov xkord, ax ;mov b.[xkord], al mov ax, ykord mov bl, 2 div bl mov ykord, ax ;mov b.[ykord], al ; выставляем видео режим 640x480, 16 цветов mov al, 12h mov ah, 0 int 10h mov cx, xkord mov dx, ykord mov bx, dlina add bx, xkord mov p1, bx ; чертим верхнюю линию mov al, 50 VerhLinia: mov ah, 0Ch int 10h inc cx cmp cx, p1 JNAE VerhLinia mov cx, xkord mov dx, ykord mov bx, ykord add bx, shirina mov p2, bx ; чертим левую линию LevLinia: mov ah,0ch ; левая линия фиолетового цвета mov al, 5 int 10h inc dx cmp dx,p2 JNAE LevLinia mov bx, cx add bx, dlina mov p3, bx ; чертим нижнюю линию NiznLinija: mov ah,0Ch ; нижняя линия красного цвета mov al, 4 int 10h inc cx cmp cx, p3 JNAE NiznLinija mov bx, ykord mov p4, bx ; чертим правую линию PravLinija: mov ah, 0Ch ; правая линия голубого цвета mov al, 3 int 10h dec dx cmp dx, p4 JNB PravLinija ret CLEAR_SCREEN PROC NEAR mov AX, 0B800h ; адрес видеопамяти mov CX, 80*25 ; сколько символов сотрём mov ES, AX ; ибо напрямую нельзя xor DI, DI ; стирать с начала будем ES:DI mov AX, 0720h ; серыми пробелами забивать будем rep STOSW ;символ с цветом (2 байта) кидаем в цикле RET CLEAR_SCREEN ENDP MY_SCAN_NUM1 PROC NEAR mov AH, 2 mov DL, '>' ; приглашение int 21h ; выводим приглашение xor DI, DI ; итоговое число, - пока ноль my_input: mov AH, 8 ; ввод символа без показа int 21h cmp AL, 13 ; Enter нажали ? je Oxid_vihod ; да - уходим cmp AL, '9' ja my_input ; какую-то бОльшую букву ввели - игнорируем cmp AL, '0' jb my_input ; какую-то меньшую букву ввели - игнорируем mov AH, 2 mov DL, AL ; цифра int 21h ; выводим цифру sub AL, '0' ; преобразуем символ в число 0..9 xor AH, AH ; AH = 0 mov CX, AX ; цифра теперь в CX mov AX, DI ; в AX наш итог mov BX, 10 ; десятичная у нас система ввода mul BX ; AX = AX*10 add AX, CX ; добавим нашу цифру mov DI, AX ; результат в DI jmp my_input ; на следующую цифру Oxid_vihod: mov CX, DI ; запишем результат RET ; валим MY_SCAN_NUM1 ENDP msg1 db 'Programmu napisal: Imya Familiya. Najmite <Enter> ', '$' msg2 db 10,13,'Vvedite X koordinatu centra pryamougolnika: ', '$' msg3 db 10,13,'Vvedite Y koordinatu centra pryamougolnika: ', '$' msg4 db 10,13,'Vvedite shirinu pryamougolnika (max 480): ', '$' msg5 db 10,13,'Vvedite dlinu pryamougolnika (max 640): ', '$' msg6 db 10,13,'Ploshad vashego pryamougolnika: ', '$' msg7 db 10,13,'Perimetr vashego pryamougolnika: ', '$' msg8 db 10,13,'Dlya sozdaniya pryamougolnika najmite <ENTER>', '$' code ENDS end start |
Сообщ.
#12
,
|
|
|
Славян Да Вы просто кудесник прям ))) Правда, огромное Вам спасибо,очень и очень мне помогли
Всё работает так, как нужно, и да, я не заметил,что сделал опечатку ))) А почему не выводятся значения периметра и площади в msg6 и msg7 ? Вычисляться - вычисляется ведь, но вместо значений там просто пустота |
Сообщ.
#13
,
|
|
|
Цитата Oxidous @ Ну потому что надо ещё научиться переводить числа из машинного представления в человеческий, 10-тичный, формат. А почему не выводятся значения периметра и площади в msg6 и msg7 ? |
Сообщ.
#14
,
|
|
|
Славян Да, благодярю Вас Я нашёл код,для преобразования в десятичную систему счисления, правда только от 0 до 99:
Вывод целого беззнакового числа от 0 до 99. Число для вывода должно находиться в ax. OutInt proc aam add ax,3030h mov dl,ah mov dh,al mov ah,02 int 21h mov dl,dh int 21h OutInt endp Вывод целого знакового, либо беззнакового числа.Число для вывода должно находиться в ax. Изменяя число - основание сс можно выводить числа в двоичной, троичной и т.п. системах счисления: OutInt proc ;; если число знаковое, то необходимо расскоментировать следующие строки ;; Проверяем число на знак. ; test ax, ax ; jns oi1 ; ;; Если оно отрицательное, выведем минус и оставим его модуль. ; mov cx, ax ; mov ah, 02h ; mov dl, '-' ; int 21h ; mov ax, cx ; neg ax ;; Количество цифр будем держать в CX. ;oi1: xor cx, cx mov bx, 10 ; основание сс. 10 для десятеричной и т.п. oi2: xor dx,dx div bx ; Делим число на основание сс. В остатке получается последняя цифра. ; Сразу выводить её нельзя, поэтому сохраним её в стэке. push dx inc cx ; А с частным повторяем то же самое, отделяя от него очередную ; цифру справа, пока не останется ноль, что значит, что дальше ; слева только нули. test ax, ax jnz oi2 ; Теперь приступим к выводу. mov ah, 02h oi3: pop dx ; Извлекаем очередную цифру, переводим её в символ и выводим. ;; раскоментировать если основание сс > 10, т.е. для вывода требуются буквы ; cmp dl,9 ; jbe oi4 ; add dl,7 ;oi4: add dl, '0' int 21h ; Повторим ровно столько раз, сколько цифр насчитали. loop oi3 ret OutInt endp |
Сообщ.
#15
,
|
|
|
Цитата Oxidous @ Только не забудьте в конце процедуры ret добавить. Я нашёл код,для преобразования в десятичную систему счисления, правда только от 0 до 99: Вывод целого беззнакового числа от 0 до 99. Число для вывода должно находиться в ax. |