Стратегия скриптов WndLpt
Предполагаем, что у нас есть панель светодиодов (LED'ов), подключенных непосредственно к LPT порту и выглядит вот так (при включенных LED'ах):
либо вот так (при выключенных LED'ах):
LED — так мы называем светодиод — так проще.
Скрипт — программа, написанная на специализированном языке программирования.
Сценарий — последовательность состояний светодиодов; последовательность команд, управляющих светодиодами.
Программа — последовательность команд управляющих светодиодами в соответствии с требуемым сценарием.
Подпрограмма — повторяющийся кусок кода программы.
Мы хотим заставить все LED'ы попеременно загораться и гаснуть, для этого создаём текстовый файл и пишем в него следующие строки:
CYCLE: ;
Объявление метки CYCLE
111111111111 ; Включить все 12 LED'ов
000000000000 ; Выключить все 12 LED'ов
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
В первой строке содержится запись «CYCLE:» — ее мы называем «меткой». Она не влияет на светодиоды, но понадобится позже.
Во второй строке содержится двенадцать единиц, каждая из которых предназначена для соответствующего светодиода панели. Эта запись заставляет все LED'ы засветиться.
Вторая строка содержит 12 нулей, и, соответственно, заставляет все LED'ы потухнуть.
Третья строка содержит команду «goto CYCLE», которая заставляет продолжить выполнение скрипта, начиная c ранее обозначенной метки «CYCLE:». Таким образом, образуется бесконечный цикл.
В результате выполнения этого скрипта, панель будет мигать следующим образом:
Слишком быстро? Мельтешит?.. Исправляем:
sleeps 500 ; Установка паузы
между сменой состояний светодиодов
CYCLE: ; Объявление метки CYCLE
111111111111 ; Включить все 12 LED'ов
000000000000 ; Выключить все 12 LED'ов
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
Получаем:
Команда "sleeps 500" задаёт паузу между сменой состояний светодиодов в миллисекундах. В данном случае установлена пауза 500 мс.
Простое мигание - это довольно скучно, попробуем что-нибудь посложнее:
sleeps 500 ; Установка паузы
между сменой состояний светодиодов
CYCLE: ; Объявление метки CYCLE
100000000000 ; Включить LED №1, все остальные потушить
010000000000 ; Включить LED №2, все остальные потушить
001000000000 ; Включить LED №3, все остальные потушить
000100000000 ; Включить LED №4, все остальные потушить
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
Смотрим:
По этой технологии можно составлять довольно большие сценарии, повторяющиеся циклически, например:
CYCLE: ; Объявление
метки CYCLE
sleeps 100 ; Установка паузы между сменой
состояний светодиодов
; Первый блок
100000100000 ; Включить два LED'а: №1 и №7 остальные
потушить
110000110000 ; Включить четыре LED'а: №1 и №7 остальные
потушить
111000111000 ; и т.д. ...
111100111100
111110111110
011111011111
001111001111
000111000111
000011000011
000001000001
; Второй блок
100000100000 ; Здесь повторяются состояния первого
блока
110000110000
111000111000
111100111100
111110111110
011111011111
001111001111
000111000111
000011000011
000001000001
; Третий блок
000000000000 ; Выключить все диоды
111111111111 ; Включить все диоды
sleeps 550 ; Установка паузы между сменой
состояний светодиодов 550 мс
000000000000 ; Выключить все диоды (через 550 мс после
выполнения предыдущей команды)
111111111111 ; Включить все диоды (через 550 мс после
выполнения предыдущей команды)
000000000000 ; Выключить все диоды (через 550 мс после
выполнения предыдущей команды)
nop ; Не менять
состояние светодиодов в течение 550 мс
skip ; Пропустить паузу
перед выполнением следующей смены состояний
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
Выглядит так:
В этом скрипте есть повторяющиеся куски кода, которые значительно увеличивают код не внося ничего нового. Для того чтобы не плодить одни и те же куски по несколько раз существует специальный механизм: подпрограммы. Смотрим:
CYCLE: ; Объявление
метки CYCLE
sleeps 100 ; Установка паузы между сменой
состояний светодиодов
; Первый блок
call P1 ; Выполнение подпрограммы P1
; Второй блок
call P1 ; Выполнение подпрограммы P1
; Третий блок
call P2 ; Выполнение подпрограммы P2
sleeps 550 ; Установка паузы между сменой
состояний светодиодов 550 мс
call P2 ; Выполнение подпрограммы P2
000000000000 ; Выключить все диоды (через 550 мс после
выполнения предыдущей команды)
nop ; Не менять
состояние светодиодов в течение 550 мс
skip ; Пропустить паузу
перед выполнением следующей смены состояний
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
sub P1 ; Объявляем подпрограмму
P1
100000100000 ; Включить два LED'а: №1 и №7 остальные
потушить
110000110000 ; Включить четыре LED'а: №1 и №7 остальные
потушить
111000111000 ; и т.д. ...
111100111100
111110111110
011111011111
001111001111
000111000111
000011000011
000001000001
ret ; Возврат из
подпрограммы
sub P2 ; Объявляем подпрограмму
P2
000000000000 ; Выключить все диоды
111111111111 ; Включить все диоды
ret ; Возврат из
подпрограммы
Как видим, повторяющийся код был записан отдельно и заключён между командами «sub P1» и «ret», где P1— это, так называемое, имя подпрограммы. В местах, где требуется выполнить команды входящие в подпрограмму, следует просто написать «call P1». Эта видоизменённая программа производит в точности такие же действия, что и предыдущая:
Модифицируем программу так, чтобы она занимала минимум места:
CYCLE: ; Объявление
метки CYCLE
sleeps 100 ; Установка паузы между сменой
состояний светодиодов
; Первый и второй блок
call P1 2 ; Выполнение подпрограммы P1 два
раза
; Третий блок
call P2 ; Выполнение команд
подпрограммы P2
sleeps 550 ; Установка паузы между сменой
состояний светодиодов 550 мс
call P2 ; Выполнение команд
подпрограммы P2
off 2 ; Выполнить выключение
всех светодиодов 2 раза с интервалом 550 мс
skip ; Пропустить паузу
перед выполнением следующей смены состояний
goto CYCLE ; Продолжить выполнение команд
начиная с метки CYCLE
sub P1 ; Объявляем подпрограмму
P1
100000100000 ; Включить два LED'а: №1 и №7 остальные
потушить
ssl 4 ; Выполнить 4 раза
"Циклический сдвиг влево с приоритетом 1"
rol ; Выполнить
"Циклический сдвиг влево"
nsl 4 ; Выполнить 4 раза
"Циклический сдвиг влево с приоритетом 0"
ret ; Возврат из
подпрограммы
sub P2 ; Объявляем подпрограмму
P2
off ; Выключить все
диоды
on ; Включить все
диоды
ret ; Возврат из
подпрограммы
Как видим, здесь применены дополнительные способы оптимизации, среди них есть, как и явно полезные (call P1 2 — выполнить подпрограмму 2 раза), так и спорные (ssl 4 — выполнить 4 раза «Циклический сдвиг влево с приоритетом 1») ухудшающие наглядность скрипта.