TITLE alarm v.2.0.
.model small
.stack 100h
DATASG SEGMENT 'DATA'
DB 7CH, 0C6H,0CEH, 0DEH, 0F6H, 0E6H,7CH, 00 ;КОД 0
DB 30H, 70H, 30H, 30H, 30H, 30H, 0FCH, 00 ;КОД 1
DB 78H, 0CCH,0CH, 38H, 60H, 0CCH, 0FCH, 00 ;КОД 2
DB 78H, 0CCH,0CH, 38H, 0CH, 0CCH, 78H, 00 ;КОД 3
DB 1CH, 3CH, 6CH, 0CCH, 0FEH,0CH, 1EH, 00 ;КОД 4
DB 0FCH, 0C0H, 0F8H, 0CH, 0CH, 0CCH, 78H, 00 ;КОД 5
DB 38H, 60H, 0C0H, 0F8H, 0CCH, 0CCH, 78H, 00 ;КОД 6
DB 0FCH, 0CCH, 0CH, 18H, 30H,30H, 30H, 00 ;КОД 7
DB 78H, 0CCH,0CCH, 78H, 0CCH, 0CCH, 78H, 00 ;КОД 8
DB 78H, 0CCH,0CCH, 7CH, 0CH,18H, 70H, 00 ;КОД 9
DB 00, 30H, 30H, 00, 00, 30H,30H, 00 ;КОД :
DELT EQU 9
DATASG ENDS
STACKSG SEGMENT STACK 'STACK'
DB 100H DUP(?)
STACKSG ENDS
CODESG SEGMENT 'CODE'
ASSUME CS:CODESG,SS: STACKSG, DS: DATASG
jmp Set
;************ЧАСТЬ №1:Завод будильника************
Getnum2 proc ; ввод двузначного числа с клавиатуры
call get0_9 ; ввод числа десятков
shl al,4 ; сдвиг числа в регистре влево - десятки
push ax
call get0_9 ; ввод числа едениц
mov bx,ax
pop ax
add ax,bx ; получаем результат
ret
Getnum2 endp
get0_9 proc ; ввод однозначного числа с клавиатуры
mov ah, 00h ; печать символа (тип 16-обмен данными с клавиатурой)
int 16h
xor ah,ah ; скан код клавиши не нужен
mov bl,al ; копия для эхо-вывода
sub ax,'0' ; перевести из символа в число
; Эхо-вывод введенной цифры
push ax
mov ah,0eh ; функция телетайпного вывода
mov al,bl ; введенный символ
int 10h ; выдать на экран
pop ax
ret
get0_9 endp
rewrite_hours:
mov al,08h ; сдвиг влево на 2 символа, при неправильнном вводе
int 29h
mov al,08h
int 29h
set_hours:
call Getnum2 ; вводим значение hours
cmp ax,24h ; проверяем на правильность ввода часов
jge rewrite_hours ; если не правильно ввели число часов, то повторяем нашу процедуру
mov ch,al ; установка будильника на часы
mov al,':' ; разделитель
int 29h
jmp set_minutes
rewrite_minutes:
mov al,08h ; сдвиг влево на 2 символа, при неправильнном вводе
int 29h ; недокументированное прерывание (быстрый вывод символа на экран в режиме телетайпа)
mov al,08h
int 29h
set_minutes:
call Getnum2 ; вводим значение minutes
cmp ax,60h ; проверяем на правильность ввода минут
jge rewrite_minutes ; если не верно, то заново
mov cl,al ; установка будильника на минуты
mov ah,6 ; Запускаем будильник
int 1Ah
установка вектора прерывания
; В указанное время вызовется прерывание int 4Ah, следовательно, чтобы его его обработать,
; на него нужно поставить свой обработчик.
; ф-ция 25h рерывания int 21h(Вход: AH = 25H AL = номер прерывания)
mov ax,254ah ; установить вектор
mov dx,offset Beeper ; прерывания по INTN0 по
int 21h ; адрессу Beeper`a
Beeper:
push ax
push bx
push dx
push cx
mov cx,60000
RepL:
push cx
mov ax,500
call Sound
call Delay
mov ax,700
call Sound
call Delay
pop cx
loop RepL
call NoSound
call rem
pop dx
pop bx
pop ax
ret
; Процедура Sound: генерация звука
; Вход: AX = частота звука (Гц)
Sound proc
xchg bx,ax ; Частота
mov dx,12h ; (DX,AX)=1193181
cmp bx,dx ; Если Bx <= 18Гц, то выход
jbe Done ; Чтобы избежать переполнения
in al,61h ; Порт РВ
or al,3 ; Установить биты 0-1
out 61h,al
mov al,10110110b ; Управляющее слово таймера: канал 2, режим 3, двоичное слово
out 43h,al ; Вывод в регистр режима
mov ax,34DDh
div bx ; AX=(DX:AX)/BX
out 42h,al ; Младший байт счетчика
mov al,ah
out 42h,al ; Старший байт счетчика
Done: ret
Sound endp
; Процедура NoSound: выключение звука
NoSound proc
in al,61h ; Порт РВ
and al,3 ; Сброс битов 0-1
out 61h,al
ret
NoSound endp
Delay proc
mov ah,86h
mov cx,01h
mov dx,0
int 15h
ret
endp
rem proc
get_key:
mov ah,0 ; номер функции для "чтения"
int 1ah ; получаем значение счетчика
add dx, delt ; добавляем время задержки к младшему слову
mov bx,dx ; запоминаем требуемое значение в BX
dccl:
int 1ah ; получаем значение счетчика
cmp dx,bx ; сравниваем с искомым
jb dccl ; если не равен, то повторяем снова
call timeprt ; вызываем чтение времени
mov ah, 06
mov dl, 0ffh
int 21h
cmp al, 27
jnz get_key
ret
rem endp
;************Часть №2:Вывод на экран времени****************
;***********П/П ЗАДАНИЯ ХАР-К ЭКРАНА**********
cls proc
push ax
push cx
push di
push es
mov ah, 05 ; фун-ия выбора страницы видеопамяти
mov al, 0 ; в ал заносится №страницы
int 10h
mov ax, 0b800h ; загружаем в сегментный регистр
mov es, ax ; видеобуфер
mov cx, 2000
xor di, di
mov ah, 1ah
mov al, ' '
rep stosw
pop es
pop di
pop cx
pop ax
ret
cls endp
;*****************П/П ПОЛУЧЕНИЯ ВРЕМНИ****************
timeprt proc
push ax
push bx
push cx
push dx
mov bx,0107h
mov ah,2ch ; фун-ия чтения времени
int 21h
; сн-часы
xor ah,ah ; обнуляем регистр
mov al,ch
mov ch,10 ; делитель
div ch ; делим на 10
call print ; вызываем п/п вывода большой цифры псевдографикой
add bl,8
mov al,ah
call print
; выводим разделитель - :
add bl,8
mov al,0ah
call print
; cl = минуты
add bl,8
xor ah,ah ; обнуление регистра
mov al,cl
div ch
call print
add bl,8
mov al,ah
call print
; снова разделитель печатаем
add bl,8
mov al,0ah
call print
; dh-секунды
add bl,8
xor ah,ah
mov al,dh
div ch
call print
add bl, 8
mov al, ah
call print
pop dx
pop cx
pop bx
pop ax
ret
timeprt endp
;*****П/П ВЫВОДА НА ЭКРАН БОЛЬШОГО ЧИСЛА ****
PRINT PROC
;IN: AL-код символа; BH-строка начала печати; BL-столбец начала печати
push ax
push cx
push dx
push bx
xor ah, ah ; обнуление регистра ah
mov cl, 8
mul cl ; умножение сl на ан ? и занесение значения в ах
mov si, ax
mov ax, datasg ; установка в ds адресса
mov ds, ax ; сегмента данных
mov ax, 0b800h ; в дополнительный сегмент
mov es, ax ; помещаем число
; di=(80*(bh-cl)+bl)*2
mov al, bh
mov cl, 80
mul cl ; умножение сl*al (т.е. 80*bh) и рез-т заносится в ах
xor ch, ch ; обнуляем сн
mov cl, bl
add ax, cx
mov cx, 2
mul cx
mov di, ax
mov ah, 1ah
mov cx, 8
print_ic:
push cx
push di
lodsb ; загрузить символ (байт)
mov cx, 8
print_ec:
rol al, 1 ; циклический сдвиг влево на 1 разряд
push ax
and al, 1
jnz one
mov al, ' '
jmp printp
one: mov al, '&'
printp:
stosw ; сохранение слова в ах
pop ax
loop print_ec ; зациклиться пока сх не равен 0
pop di
add di, 160
pop cx
loop print_ic ; зациклиться пока сх не равен 0
pop bx
pop dx
pop cx
pop ax
ret
print endp
Set:
mov ah,7 ; сброс будильника(для установки нового)
int 1Ah
call cls
jmp set_hours ; прыгаем на установку времени для будильника
END Set
CODESG ENDS
[Asm] Установка времени и вывод большими цифрами
Мне нужно реализовать программу с возможностью задания времени срабатывания сигнала (проще будильник), с последующим выводом системного времени большими цифрами на экран
Компилятор создает .ехе файл - ошибок нет, однако работает она не так как надо: программа стопорится сразу же после показа времени и не реагирует на установку времени для будильника:(
По отдельности каждая из частей работает (вывод времени большими цифрами и установка времени)
Подскажите что может быть не так...
Код:
работа с будильником ведётся через прерывание , а не по опросу в цикле .
проблема в том, что срабатывает будильник стабильно секунд через 10-15, не зависимо от установленного времени в регистры
хм, ответ на мою проблемы кроется наверно тут:
Цитата:
В MS-DOS векторы прерывания могут быть установлены посредством использования функции MS-DOS с кодом 25h "Установить вектор прерывания". Операция установки очень проста: в регистр AL заносится номер вектора, а адрес для загрузки в вектор заносится в пару регистров DS : DX (сегмент:смещение). В связи с тем, что в программах типа .COM регистр DS устанавливается в то же самое значение, что и регистр CS, содержимое регистра DS уже является правильным для вызова.
Код:
set_minutes:
call Getnum2 ; вводим значение minutes
cmp ax,60h ; проверяем на правильность ввода минут
jge rewrite_minutes ; если не верно, то заново
mov cl,al ; установка будильника на минуты
mov ah,6 ; Запускаем будильник
int 1Ah
установка вектора прерывания
; В указанное время вызовется прерывание int 4Ah, следовательно, чтобы его его обработать,
; на него нужно поставить свой обработчик.
; ф-ция 25h рерывания int 21h(Вход: AH = 25H AL = номер прерывания)
mov ax,254ah ; установить вектор
mov dx,offset Beeper ; прерывания по INTN0 по
int 21h
call Getnum2 ; вводим значение minutes
cmp ax,60h ; проверяем на правильность ввода минут
jge rewrite_minutes ; если не верно, то заново
mov cl,al ; установка будильника на минуты
mov ah,6 ; Запускаем будильник
int 1Ah
установка вектора прерывания
; В указанное время вызовется прерывание int 4Ah, следовательно, чтобы его его обработать,
; на него нужно поставить свой обработчик.
; ф-ция 25h рерывания int 21h(Вход: AH = 25H AL = номер прерывания)
mov ax,254ah ; установить вектор
mov dx,offset Beeper ; прерывания по INTN0 по
int 21h
а где ret? или так и задумывалось?
exe от com ничем отличаться не будет в вашем случае, если речь об этом.
А для чего в выделенной части нужен ret?
А вопрос насчет возврата смещения в сегменте (offset Beeper) не спроста задавался...
При компилировании программы типа .com (только будильник), тревога срабатывала в точно указанное с клавиатуры время. А при компилировании .exe (будильник и время большими цифрами) тревога срабатывала почти сразу, независимо от установленного времени.
Следовательно возможной причиной и явл-ся неправильная установка вектора срабатывания тревоги при компилировании exe файла
Цитата: xmavr
Alm3n
А для чего в выделенной части нужен ret?
А для чего в выделенной части нужен ret?
точняк. не посмотрел, что ты прыжком туда переходишь. но все равно вопрос, нафига тогда еще один ret?
вот, прыжок на set_minutes, потом он перетекает в Beeber, который в свою очередь заканчивается ret'ом. или я где-то прыжок пропустил между set_minutes и ret'ом beeper'а?
если уж так нужен одинаковый сегмент, то допиши
Код:
mov ax, DATASG
mov ds, ax
mov ds, ax