
- •220400 «Управление в технических системах» (код и наименование направления подготовки, специальности)
- •Курсовая работа
- •Глава 1. Задание……………………………………………………….………3
- •Глава 2. Десятичный калькулятор
- •Глава 3. Двоичный калькулятор
- •3.1 Текст программы с комментариями.....................................................16-27
- •Int 10h ;Вызывание Dos
- •Int 10h ;Вызывание Dos
Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования «Тольяттинский государственный университет» «ИНСТИТУТ ЭНЕРГЕТИКИ И ЭЛЕКТРОТЕХНИКИ» (институт, факультет) «Автоматизация технологических процессов и производств» (кафедра)
220400 «Управление в технических системах» (код и наименование направления подготовки, специальности)
Системы и средства автоматизации и управления (наименование профиля, специализации)
Курсовая работа
на тему Калькуляторы
Студент А.С.Миронов (И.О.Фамилия)
Руководитель О.Ю.Копша (И.О.Фамилия)
Тольятти 2013
Содержание.
Глава 1. Задание……………………………………………………….………3
Глава 2. Десятичный калькулятор
2.1 Текст программы с комментариями......................................................4-15
2.2 Пример исполнения.....................................................................................15
Глава 3. Двоичный калькулятор
3.1 Текст программы с комментариями.....................................................16-27
3.2 Пример исполнения.....................................................................................27
Задание.
Назначение и функции регистров. Помещение и обработка значений и математические действия над двумя трёхзначными числами. Осуществлять операции над ними: со знаком и без знака.
Написать программы, выполняющие действия математики над числами десятичной, двоичной и шестнадцатеричной систем счисления, вводя значения с клавиатуры.
Десятичный калькулятор.
name "calc2"
PUTC MACRO char
PUSH AX ;Данная команда помещает на вершину стека значение. Предыдущее значение, находящееся на вершине стека перемещается на один уровень вниз.
MOV AL, char ;поместить значение из памяти в регистр AL
MOV AH, 0Eh ;поместить значение из памяти в регистр AH
Int 10h ;Вызывание Dos
POP AX ;Перемещение всего содержимого стека на один уровень вверх. Предыдущее значение, находящееся на вершине стека утрачивается.
ENDM
org 100h
jmp start
; определяем переменные:
msg0 db "calculator.",0Dh,0Ah
db "use 2s numbers",0Dh,0Ah,'$'
msg1 db 0Dh,0Ah, 'enter first number: $'
msg2 db "enter the operator: + - * / : $"
msg3 db "enter second number: $"
msg4 db 0dh,0ah , 'the approximate result is : $'
msg5 db 0dh,0ah ,'press any key... ', 0Dh,0Ah, '$'
err1 db "wrong operator!", 0Dh,0Ah , '$'
smth db " and something.... $"
; оператор может быть: '+','-','*','/' или 'q' для выхода.
opr db '?'
; ввод первого и второго числа с клавиатуры:
num1 dw ?
num2 dw ?
start:
mov dx, offset msg0
mov ah, 9
int 21h
lea dx, msg1 ; получение эффективного адреса (смещения) источника.
mov ah, 09h ; вывод на экран сообщения 1 (Функция DOS)
int 21h
; получаем число введённое с клавиатуры
; результат в регистр cx:
call scan_num
; сохраняем первое число в сх:
mov num1, cx
; новая строка (функции DOS):
putc 0Dh
putc 0Ah
lea dx, msg2
mov ah, 09h ; вывод на экран сообщения 2
int 21h
; считываем оператор:
mov ah, 1 ; ввод с клавиатуры оператора.
int 21h
mov opr, al
; новая строка:
putc 0Dh
putc 0Ah
cmp opr, 'q' ; сравниваем с q, если да, то выход.
je exit
cmp opr, '*'
jb wrong_opr
cmp opr, '/'
ja wrong_opr
; вывод следущего сообщения
lea dx, msg3
mov ah, 09h
int 21h
; получаем число введённое с клавиатуры
; результат в регистр cx:
call scan_num
; сохраняем второе число в сх:
mov num2, cx
lea dx, msg4
mov ah, 09h ; вывод на экран сообщения
int 21h
; вычисляем:
cmp opr, '+' ;позволяет сравнить два числа, сохраняя результат своей работы во флагах.
je do_plus
cmp opr, '-'
je do_minus
cmp opr, '*'
je do_mult
cmp opr, '/'
je do_div
; в случае, если оператор не из перечисленных
wrong_opr:
lea dx, err1
mov ah, 09h ; вывод на экран сообщения об ошибке
int 21h
exit:
; вывод на экран сообщения о выходе
lea dx, msg5
mov ah, 09h
int 21h
; ждём нажатия клавишы...
mov ah, 0
int 16h
ret ; выход из процедуры.
do_plus:
mov ax, num1
add ax, num2
call print_num ; вызов процедуры печати значения.
jmp exit ;Эта команда выполняет безусловный переход.
do_minus:
mov ax, num1
sub ax, num2
call print_num ; вызов процедуры печати значения.
jmp exit
do_mult:
mov ax, num1
imul num2 ; (dx ax) = ax * num2.
call print_num ; вызов процедуры печати значения.
jmp exit
do_div:
mov dx, 0
mov ax, num1
idiv num2 ; ax = (dx ax) / num2.
cmp dx, 0
jnz approx
call print_num ; вызов процедуры печати значения.
jmp exit
approx:
call print_num ; вызов процедуры печати значения.
lea dx, smth
mov ah, 09h ; вывод на экран значения
int 21h
jmp exit
; получаем какое-то число (со знаком или без) с клавиатуры,
; и сохраняем в регистр СХ:
SCAN_NUM PROC NEAR
PUSH DX
PUSH AX
PUSH SI
MOV CX, 0
; сброс флага:
MOV CS:make_minus, 0
next_digit:
; получаем символ с клавиатуры
MOV AH, 00h
INT 16h
; печатаем его:
MOV AH, 0Eh
INT 10h
; проверка на минус:
CMP AL, '-' ;сравнение двух операндов.
JE set_minus ;условный переход = .
; проверка на нажатие клавиши <ENTER>:
CMP AL, 0Dh
JNE not_cr ;условный переход <>.
JMP stop_input
not_cr:
CMP AL, 8 ; <BACKSPACE> нажат?
JNE backspace_checked
MOV DX, 0 ; удалить последнюю цифру
MOV AX, CX ; путём деления:
DIV CS:ten ; AX = DX:AX / 10 (DX-rem).
MOV CX, AX
PUTC ' ' ; очистка последней позиции.
PUTC 8 ; пробел.
JMP next_digit
backspace_checked:
; учитывает только цифры:
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 ; пробел.
PUTC ' ' ; очистка последней позиции.
PUTC 8 ; пробел.
JMP next_digit ; ждём следущее "вложение".
ok_digit:
PUSH AX
MOV AX, CX
MUL CS:ten ; DX:AX = AX*10
MOV CX, AX
POP AX
; проверка числа. должно войти в 16бит
CMP DX, 0
JNE too_big
; преобразования из аскии кода:
SUB AL, 30h
; добавить AL в CX:
MOV AH, 0
MOV DX, CX ; резервное копирование, в случае если результат будет большим.
ADD CX, AX
JC too_big2 ; прыгаем дальше, если число слишком большое.
JMP next_digit
set_minus:
MOV CS:make_minus, 1
JMP next_digit
too_big2:
MOV CX, DX ; восстановить резервные значения перед сложением
MOV DX, 0 ; в DX ноль перед копированием
too_big:
MOV AX, CX
DIV CS:ten ; из DX:AX = AX*10, делаем AX = DX:AX / 10
MOV CX, AX
PUTC 8 ; пробел.
PUTC ' ' ; очистка послденей позиции.
PUTC 8 ; пробел.
JMP next_digit ; ждём нажатия клавишы.
stop_input:
; проверка флага:
CMP CS:make_minus, 0
JE not_minus
NEG CX
not_minus:
POP SI
POP AX
POP DX
RET
make_minus DB ? ; используем как флаг.
SCAN_NUM ENDP
; печатаем число в AX,
; используется с PRINT_NUM_UNS для печати чисел со знаком:
PRINT_NUM PROC NEAR
PUSH DX
PUSH AX
CMP AX, 0
JNZ not_zero
PUTC '0'
JMP printed
not_zero:
; проверка знака у AX,
; если отрецательный сделать абсолютным:
CMP AX, 0
JNS positive
NEG AX
PUTC '-'
positive:
CALL PRINT_NUM_UNS
printed:
POP AX
POP DX
RET
PRINT_NUM ENDP
; печать без знака
; число в АХ
; допускается значение от 0 до 65535 (FFFF)
PRINT_NUM_UNS PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; флаг для претвращения печати нуля перед числом
MOV CX, 1
MOV BX, 1000
; AX равен нулю?
CMP AX, 0
JZ print_zero
begin_print:
; проверка делителя (если нуль то переходим к end_print):
CMP BX,0
JZ end_print
; избегаем печать нуля перед числом:
CMP CX, 0
JE calc
; если AX<BX результат деления будет равен нулю:
CMP AX, BX
JB skip
calc:
MOV CX, 0 ; установка флага.
MOV DX, 0
DIV BX ; AX = DX:AX / BX (DX=остаток).
; печать последней цифры
; AH всегда нуль поэтому игнорируется
ADD AL, 30h ; преобразуем в аскии код.
PUTC AL
MOV AX, DX ; получаем остаток от последних делений.
skip:
; считаем BX=BX/2
PUSH AX
MOV DX, 0
MOV AX, BX
DIV CS:ten ; AX = DX:AX / 2 (DX=отстаток).
MOV BX, AX
POP AX
JMP begin_print
print_zero:
PUTC '0'
end_print:
POP DX
POP CX
POP BX
POP AX
RET
PRINT_NUM_UNS ENDP
ten DW 10 ; используем как число для двух выше описаных процедур
GET_STRING PROC NEAR
PUSH AX
PUSH CX
PUSH DI
PUSH DX
MOV CX, 0 ; счётчик символов.
CMP DX, 1 ; буффер слишком мал?
JBE empty_buffer ;
DEC DX ; резервируем место для последнего нуля.
; цикл для получения нажатой клавишы
wait_for_key:
MOV AH, 0 ; нажата клавиша.
INT 16h
CMP AL, 0Dh ; <RETURN> нажат?
JZ exit_GET_STRING
CMP AL, 8 ; <BACKSPACE> нажат?
JNE add_to_buffer
JCXZ wait_for_key ; ничего не нажато
DEC CX
DEC DI
PUTC 8 ; пробел.
PUTC ' ' ; чистим последнюю позицию .
PUTC 8 ; пробел.
JMP wait_for_key
add_to_buffer:
CMP CX, DX ; буффер переполнен?
JAE wait_for_key ; ждём нажатия <BACKSPACE> или <RETURN>...
MOV [DI], AL
INC DI
INC CX
; печатаем нажатие клавиши:
MOV AH, 0Eh
INT 10h
JMP wait_for_key
exit_GET_STRING:
; обнуляем:
MOV [DI], 0
empty_buffer:
POP DX
POP DI
POP CX
POP AX
RET
GET_STRING ENDP
Пример исполнения
Рис. 1 Скриншот работы десятичного калькулятора.
Двоичный калькулятор.
name "calc2"
PUTC MACRO char
PUSH AX ;Данная команда помещает на вершину стека значение. Предыдущее значение, находящееся на вершине стека перемещается на один уровень вниз.
MOV AL, char ;поместить значение из памяти в регистр AL
MOV AH, 0Eh ;поместить значение из памяти в регистр AH