При чем тут циклы??? Причем тут "пропустишь"? Вам надо: выполнять действие А каждые 10 мс. Необходимое условие успеха: действие А должно выполняться менее 10 мс. Перепрограммируем таймер на 10 мс кванты времени Проверять значение таймера НЕ НАДО - надо перехватить прерывание. И вас будут вызывать автоматом каждые 10 мс. А если больше ничего не требуется, можно и hlt повыполнять. Code (Text): Алгоритм: 1. Перехватить прерывание от таймера (обычно вектор 08) - переназначить на п.5 2. настроить таймер на 10 мс. 3. HLT 4. JMP 3. 5. Обработчик прерывания - вызывается автоматом, раз в 10 мс. Делаем наше действие А. Возвращаемся из прерывания.
Чтение первого поста, отправляет весь ваш поток сознания в мусорку, и дает исчерпывающие ответы на все поставленные вами вопросы.
Проверил. Инструкции тут не причем, этож отдельная аппаратная вещь. В режиме 0 не останавливается на нуле (или останавливается не на нуле), выяснять не стал, лень. В режиме 4 ОСТАНАВЛИВАЕТСЯ НА НУЛЕ, через ноль не переходит. Дальше не считает, ноль вы никогда не пропустите, даже если в цикле опроса будет выполняться что-то достаточно длительное. Так что, drem1lin, между началом и окончанием исполнения следующего кода проходит 10мсек (ну с точностью до длительности одного цикла опроса счетчика вместе с вашими действиями): Code (Text): in al,61h or al,1h out 61h,al mov al,0B8h out 43h,al mov al,09Ch out 42h,al mov al,02Eh out 42h,al m1: ;тут можно выполнить какие-либо действия in al,42h mov bl,al in al,42h mov bh,al cmp bx,0 jnz m1
Не поленился, написал: Code (Text): In Al, 061h ; {Читаем порт} And Al, 0FCh ; {Spk & Gate Off} Out 061h, Al ; {Set} Mov Bl, Al ; {Save} Mov Al, 0B8h ; {80+30+8} Out 043h, Al ; {Set} Mov Ax, 000FFh ; {Hi=0 Lo=FF} Out 042h, Al ; {Out Lo} XcHg Ah, Al ; {Hi=FF Lo=00} Out 042h, Al ; {Out Hi} Xor Ax, Ax ; {=0} Mov Es, Ax ; {Timer Seg} Mov Di, 0046Ch ; {Timer Ofs} Mov Dx, Es:[Di] ; {Timer Val} Mov Cx, 20 ; {Loop Count} Mov Al, Bl ; {Restore} Or Al, 001h ; {Gate On} Out 061h, Al ; {START} @@Loop: In Al, 042h ; {Lo} XcHg Ah, Al ; {Save} In Al, 042h ; {Hi} XcHg Ah, Al ; {Swap} Or Ah, Ah ; {ReLoad?} jNZ @@Ex1 ; {Exit} Cmp Dx, Es:[Di] ; {Timer Val} jE @@Loop ; {No Tic} Mov Dx, Es:[Di] ; {Save New tic} Loop @@Loop ; @@Ex1: AH больше нуля на выходе. Где я ошибся? Та же картина и при режиме 0
Вообще все описания что я видел, говорят что в 4 он должен остановиться, но что я видел в отладчике утверждает другое, хотя может им просто нельзя смотреть счетчик? завтра попробую запустить код в полевых условиях
По моей документации, и 0й и 4й переходят через 0, и продолжают счет. Код, что я привел, полностью рабочий.
MisHel64, вы меня не поняли Зачем вообще обращения к памяти по адресу 0000:046Ch? Я вам говорю про аппаратный счетчик канала динамика (канал 2 таймера), для обращения к нему необходимо всего лишь прочитать порт 42h два раза подряд. Все, ничего больше читать не нужно: Code (Text): @@Loop: In Al, 042h ; {Lo} XcHg Ah, Al ; {Save} In Al, 042h ; {Hi} XcHg Ah, Al ; {Swap} Or Ah, Ah ; {Zero reached?} jNZ @@Loop ; {If no - continue polling}
Я то тебя отлично понял, а вот ты меня нет. Я выслушал твое мнение, и решил его проверить. И по этому то же решил написать небольшой кусок кода, что бы проверить справедливость твоих утверждений, об остановке счета. Выход по условию AX=0, уже в моем тестовом коде не применим. Так как не зависимо от того, продолжает счетчик считать после достижения нуля, или продолжает счет с переходом через ноль, такое условие сработает, и по этому код не даст ответа на поставленный мной вопрос. Для этого и был организован дополнительный цикл ожидания, и я посчитал простейшим способом для этого использовать счетчик тиков. И вот результат моего эксперимента показал, что счетчик переходит через ноль, и продолжает счет, что полностью совпадает с документацией, которой пользуюсь я. В дальнейшем, при проектировании уже реального, а не тестового кода, стоит предусматривать ситуацию, что может произойти переход через ноль, с продолжением счета, и тот момент, что факт перехода через ноль может быть пропущен. PS: Так как данная задача для меня то же сейчас актуальна, и пока носит академический характер, просил бы вас запустить мой код на своем железе, в том числе и под виртуальными машинами, и сообщить результат.
Ясно, но тогда непонятно, каким образом вы проверяете. Code (Text): @@Loop: In Al, 042h ; {Lo} XcHg Ah, Al ; {Save} In Al, 042h ; {Hi} XcHg Ah, Al ; {Swap} Or Ah, Ah ; {ReLoad?} jNZ @@Ex1 ; {Exit} - это же ведь идет сразу после запуска счетчика. Конечно же после запуска в нем еще какое-то промежуточное ненулевое значение (счетчик же еще не успел досчитать до нуля!), вы читаете это ненулевое значение и тут же выходите (СОВСЕМ ВЫХОДИТЕ!), и конечно же видите в AX прочинанное ненулевое значение. Счетчик просто еще ни разу не дошел до нуля, а вы делаете вывод, что он не остановился на нуле. Я проверял просто запуская скомпилированный для DOS exe-шник под WinXP, то есть в ntvdm. Я не знаю подробностей работы vdm, возможно она полностью эмулирует (с остановом на нуле в режиме 4) работу счетчиков, а не дает работать с реальной аппаратурой. Программа инициализировала счетчик, дальше в указанном мною цикле отслеживала достижение счетчиком нуля, затем выходила из цикла и ожидала нажатия клавиши, после чего снова проверяла значение счетчика, оно оставалось нулевым. Сначала давайте разберемся с логикой вашего кода, мои претензии к определению факта неостанова в нуле написаны выше.
Внимательнее код читать нужно! Эта проверка, а не перешел ли счетчик через ноль, и не продолжил ли счет. В старшем байте НУЛЕВОЕ. Посмотрите, какое значения я в него записываю. Я выхожу при не нулевом AH, а не AX. А в AH ненулевое значение будет только, если счетчик плодожил счет после перехода через ноль. А я на реальном железе. Вроде на все ваши претензии ответил? Причина их возникновения, это, только ваша невнимательность.
Виноват. Дурак. Действительно весь ваш код не имел для меня смысла из-за того, что я видел AX там, где фактически написано AH Хотя в ваш огород тоже камень есть - пишите прозрачнее, зачем было запутывать двумя xchg (фактически полное заполнение AX двумя последовательными чтениями), когда нагляднее было сохранить первый раз в другом 8-битном регистре, не вы один ваш код читаете Но вот тогда непонятное расхождение, почему в ntvdm останов в нуле все-таки произошел, неужели полная программная эмуляция этой аппаратуры, да еще и неточно соответствующая?
Блин, опять невнимательносьть Нагляднее было бы вообще первое чтение сделать холостым, раз al не используется. Просто два in al,42h подряд и проверять or al,al
Да, кстати, раз такая пьянка, проверить бы еще и режимы счета с загрузкой/чтением только одним младшим байтом и только одним старшим (то есть, конфигурации 98h и 0A8h).
Я потестировал, в принципе все работает нормально, счетчик в 0 останавливается. Так что решение найдено, всем спасибо. Если кому надо могу выложить код.
MisHel64, запустил ваш код (тоже в ntvdm) - остановилось на нуле (то есть, выхода по JNZ не было, завершилось окончанием loop)! Либо действительно ntvdm эмулирует режим 4 с остановом в нуле, либо еще хуже - на разных матерях разная реализация.
Подождите радоваться. Один и тот же код, написанный MisHel64, по-разному отработал в разных ситуациях. У него (чисто аппаратно) - не остановился, у меня в ntvdm - остановился.
Я запускал на реальном железе, он остановился. Хотя разобраться конечно стоит, почему у MisHel64 он не остановился
Для общего развития, озвучте область задач, в которой требуется однократная задержка в 10 мс? Все, что приходит в голову - периодические действия. Для периодических логичнее все равно основной канал и прерывание, чем с циклами и ожиданием. Тем более если решается в голом ДОСе