Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[Asm] Установка времени и вывод большими цифрами

69K
19 мая 2011 года
xmavr
4 / / 30.03.2011
Добрый вечер!
Мне нужно реализовать программу с возможностью задания времени срабатывания сигнала (проще будильник), с последующим выводом системного времени большими цифрами на экран

Компилятор создает .ехе файл - ошибок нет, однако работает она не так как надо: программа стопорится сразу же после показа времени и не реагирует на установку времени для будильника:(
По отдельности каждая из частей работает (вывод времени большими цифрами и установка времени)
Подскажите что может быть не так...
Код:
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
252
25 мая 2011 года
koderAlex
1.4K / / 07.09.2005
работа с будильником ведётся через прерывание , а не по опросу в цикле .
69K
31 мая 2011 года
xmavr
4 / / 30.03.2011
так я нигде не делаю опрос, я устанавливаю время срабатывания будильника, запускаю его (int 1ah) и далее инициализирую прерывание 4ah

проблема в том, что срабатывает будильник стабильно секунд через 10-15, не зависимо от установленного времени в регистры


хм, ответ на мою проблемы кроется наверно тут:
Цитата:
В MS-DOS векторы прерывания могут быть установлены посредством использования функции MS-DOS с кодом 25h "Установить вектор прерывания". Операция установки очень проста: в регистр AL заносится номер вектора, а адрес для загрузки в вектор заносится в пару регистров DS : DX (сегмент:смещение). В связи с тем, что в программах типа .COM регистр DS устанавливается в то же самое значение, что и регистр CS, содержимое регистра DS уже является правильным для вызова.

316
31 мая 2011 года
Alm3n
889 / / 29.05.2009
Код:
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

а где ret? или так и задумывалось?
exe от com ничем отличаться не будет в вашем случае, если речь об этом.
69K
01 июня 2011 года
xmavr
4 / / 30.03.2011
Alm3n
А для чего в выделенной части нужен ret?

А вопрос насчет возврата смещения в сегменте (offset Beeper) не спроста задавался...
При компилировании программы типа .com (только будильник), тревога срабатывала в точно указанное с клавиатуры время. А при компилировании .exe (будильник и время большими цифрами) тревога срабатывала почти сразу, независимо от установленного времени.
Следовательно возможной причиной и явл-ся неправильная установка вектора срабатывания тревоги при компилировании exe файла
316
01 июня 2011 года
Alm3n
889 / / 29.05.2009
Цитата: xmavr
Alm3n
А для чего в выделенной части нужен ret?


точняк. не посмотрел, что ты прыжком туда переходишь. но все равно вопрос, нафига тогда еще один ret?
вот, прыжок на set_minutes, потом он перетекает в Beeber, который в свою очередь заканчивается ret'ом. или я где-то прыжок пропустил между set_minutes и ret'ом beeper'а?
если уж так нужен одинаковый сегмент, то допиши

 
Код:
mov ax, DATASG
mov ds, ax
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог