Стратегия скриптов WndLpt

Предполагаем, что у нас есть панель светодиодов (LED'ов), подключенных непосредственно к LPT порту и выглядит вот так (при включенных LED'ах):

Команда «111111111111»

Команда «111111111111»

либо вот так (при выключенных LED'ах):

Команда «000000000000»

Команда «000000000000»


h_point.gif (172 bytes)

LED — так мы называем светодиод — так проще.

Скрипт — программа, написанная на специализированном языке программирования.

Сценарий — последовательность состояний светодиодов; последовательность команд, управляющих светодиодами.

Программа — последовательность команд управляющих светодиодами в соответствии с требуемым сценарием.

Подпрограмма — повторяющийся кусок кода программы.


 

Мы хотим заставить все LED'ы попеременно загораться и гаснуть, для этого создаём текстовый файл и пишем в него следующие строки:

 

CYCLE:        ; Объявление метки CYCLE
111111111111  ; Включить все 12 LED'ов
000000000000  ; Выключить все 12 LED'ов
goto CYCLE    ; Продолжить выполнение команд начиная с метки CYCLE

 

В первой строке содержится запись «CYCLE:» — ее мы называем «меткой». Она не влияет на светодиоды, но понадобится позже.

Во второй строке содержится двенадцать единиц, каждая из которых предназначена для соответствующего светодиода панели. Эта запись заставляет все LED'ы засветиться.

Вторая строка содержит 12 нулей, и, соответственно, заставляет все LED'ы потухнуть.

Третья строка содержит команду «goto CYCLE», которая заставляет продолжить выполнение скрипта, начиная c ранее обозначенной метки «CYCLE:». Таким образом, образуется бесконечный цикл.

В результате выполнения этого скрипта, панель будет мигать следующим образом:

wndlpt: 111111111111, 000000000000

wndlpt: 111111111111, 000000000000


Слишком быстро? Мельтешит?.. Исправляем:

 

sleeps 500    ; Установка паузы между сменой состояний светодиодов
CYCLE:        ; Объявление метки CYCLE
111111111111  ; Включить все 12 LED'ов
000000000000  ; Выключить все 12 LED'ов
goto CYCLE    ; Продолжить выполнение команд начиная с метки CYCLE

 

Получаем:

wndlpt: 111111111111, 000000000000

wndlpt: 111111111111, 000000000000

Команда "sleeps 500" задаёт паузу между сменой состояний светодиодов в миллисекундах. В данном случае установлена пауза 500 мс.


Простое мигание - это довольно скучно, попробуем что-нибудь посложнее:

 

sleeps 500    ; Установка паузы между сменой состояний светодиодов
CYCLE:        ; Объявление метки CYCLE
100000000000  ; Включить LED №1, все остальные потушить
010000000000  ; Включить LED №2, все остальные потушить
001000000000  ; Включить LED №3, все остальные потушить
000100000000  ; Включить LED №4, все остальные потушить
goto CYCLE    ; Продолжить выполнение команд начиная с метки CYCLE

 

Смотрим:

wndlpt: 100000000000, 010000000000, 001000000000, 000100000000

По этой технологии можно составлять довольно большие сценарии, повторяющиеся циклически, например:

 

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

 

Выглядит так:

Пример работы скрипта программы wndlpt

Пример работы скрипта программы wndlpt


В этом скрипте есть повторяющиеся куски кода, которые значительно увеличивают код не внося ничего нового. Для того чтобы не плодить одни и те же куски по несколько раз существует специальный механизм: подпрограммы. Смотрим:

 

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». Эта видоизменённая программа производит в точности такие же действия, что и предыдущая:

Пример работы скрипта программы wndlpt

Пример работы скрипта программы wndlpt


Модифицируем программу так, чтобы она занимала минимум места:

 

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») ухудшающие наглядность скрипта.



// GUID: {987A951E-427B-4e41-8CA2-8436C754F921}