Другая «жизнь» LPT порта.
Александр
Новожилов, г.Троицк, u10753@dialup.podolsk.ru
Не ожидал, что моя первая статья вызовет такой
интерес среди программистов и электронщиков, т.к. я получил массу писем с
вопросами и продолжаю их получать до сих пор, хотя прошло уже почти три года с
момента написания статьи. Кроме того в первой статье
был допущен ряд неточностей. Это все и побудило меня
на написание более подробной статьи на эту тему, в которой я постараюсь
ответить на большинство вопросов уважаемых читателей и исправить те неточности,
которые были допущены в первой статье. Пусть не обижаются на меня читатели
первой статьи, но мы снова рассмотрим подробно каждый контактик
и битик нашего LPT порта. В первой части статьи будет рассмотрена теория, во
второй и последующих (если они будут) мы будем рассматривать электронные
устройства, которые можно «подцепить» к этому порту.
Ø
В тексте вы
встретитесь с общепринятой аббревиатурой записывания чисел.
Ø
Например, 10102
- двойка в нижнем индексе указывает, что число 5 представлено в двоичном
исчислении,
Ø
12410 – десятка в нижнем индексе, говорит о том, что число 124
десятичное.
Это так… на всякий случай
Как показала практика, все программы, правильно написанные и дополненные соответствующими библиотеками (vbio32.dll, inpout32.dll, dlportio.dll и т.д.) работают на большинстве компьютеров с операционными системами семейства Windows. Я проверял работу всех своих программ (Visual Basic5.0, 6.0) на Win95, 98, Me, 2000, XP HE, XP Prof и даже в DOS6.22 (QBasic) – все работает прекрасно. В DOS-е вообще никаких библиотек не надо, там все и так работает. Сразу оговорюсь, что vbio32.dll и inpout32.dll НЕ БУДУТ РАБОТАТЬ ПОД Win2000, но совершенно спокойно будут работать под Win95, 98, Me.
Кстати, взять любую из этих библиотек вы можете здесь. Мне захотелось попробовать dlportio.dll и в данный момент я работаю с этой библиотекой. Ну и последнее, перед написанием программ необходимо правильно объявить библиотеку, которую вы используете.
Ø
Для inpout32.dll
Private
Declare Function Inp Lib "inpout32.dll" Alias
"Inp32" (ByVal
PortAddress As
Integer) As Integer
Private
Declare Sub Out Lib "inpout32.dll" Alias
"Out32" (ByVal
PortAddress As
Integer, ByVal Value
As Integer)
Ø
Для dlportio.dll
Private
Declare Function DlPortReadPortUchar Lib "dlportio.dll" (ByVal Port As Long) As Byte
Private
Declare Sub DlPortWritePortUchar Lib "dlportio.dll" (ByVal Port As Long, ByVal Value As Byte)
Чем отличается Private от Public я писать не буду.
Параллельный порт для связи с принтером (или другим устройством) имеет базовый адрес &H378 (LPT1), &H278 (LPT2), &H3BC (LPT3). В данной статье мы будем рассматривать только LPT1. Адресное пространство данного порта занимает диапазон &H378-&H37F.
· Адрес &H378 называется базовым и служит для записи (чтения, но об этом попозже) данных в порт, на линии D0-D7.
· Адрес &H379 (базовый+1) предназначен для чтения битов состояния с устройства, подключенного к LPT-порту (принтер, сканер и т.д)
·
Адрес &H37A (базовый+2)
служит для записи битов управления устройства, подключенного к LPT-порту (принтер, сканер и
т.д.).
На приведенных ниже таблицах «расшифрованы» контакты и сигналы каждого из адресов
Контакты 18-25 – «земля» (общий, GND, GROUND
и т.д.)
Рассмотрим программирование каждого из адресов.
·
Базовый адрес &H378 (LPT1) позволяет записывать данные в порт
на линии D0-D7 в диапазоне от 0 до 255.
·
Записываем в порт число 69
Код следующий. Для тех, кто
использует |
||
inpout32.dll |
dlportio.dll |
DOS |
Out &H378,
69 |
DlPortWritePortUchar &H378, 69 |
OUT &H378,
69 |
*********************************************************************************************************
·
Адрес &H379 служит для чтения битов состояния.
·
Читаем состояние порта по адресу &H379
Ø
При чтении адреса
&H379 необходимо помнить, что первые три бита – не
используются и всегда имеют значение лог. «1», а 7-й бит – инверсный. В
результате если все контакты 15, 13, 12, 10, 11 посадить на «землю», то при
чтении информации вы получите на первых трех битах (которые не используются)
1+2+4 и на 7-м бите (контакт 11-инверсный, значит, при замыкании на землю будет
лог. «1») +128 итого 135. Об этом не надо забывать. Во второй части статьи мы
остановимся на этом более подробно.
inpout32.dll |
dlportio.dll |
DOS |
Dim A as IntegerA = Inp(&H379) |
Dim A as IntegerDlPortReadPortUchar(&H379) |
DEFINT A-ZA=INP(&H379) |
*********************************************************************************************************
·
Адрес &H37A служит для
записи битов управления.
·
Записываем сигнал -STROBE (бит управления 0)
Код следующий. Для тех, кто
использует |
||
inpout32.dll |
dlportio.dll |
DOS |
Out &H37A, 10 |
DlPortWritePortUchar &H37A, 10 |
OUT &H37A, 10 |
Почему 10? Давайте посмотрим в табличку.
(-STROBE)
20 |
(-AUTO)
21 |
(INIT)
22 |
(-SELECT
IN) 23 |
(Сигналы) биты |
Контакт 1 |
Контакт 14 |
Контакт 16 |
Контакт 17 |
|
0 |
1 |
0 |
1 |
01012 |
0 |
2 |
0 |
8 |
0+2+0+8=10 |
Сигналы STROBE, AUTO, SELECT IN – инверсные, значит, чтобы на выходе контактов разъема 1, 14, 17 получить логическую «1» надо подать на эти биты логический «0», т.е. подали одно – получили противоположное. Сигнал INIT прямой (не инверсный), поэтому логическая «1» на контакте 16 появится тогда, когда мы подадим на этот бит логическую «1», т.е. что подали, то и получили.
Попытаемся получить на контактах 1,17 – низкий уровень сигнала «0», а на контактах 14 и 16 высокий уровень сигнала «1», т.е. на выходе контактов 1,14,16,17 будет присутствовать 0 1 1 0 (610).
На нулевой бит (-STROBE) подаем «1» (на контакте 1 будет «0»), на первый бит (-AUTO) подаем «0» (на контакте 14 будет «1»), на второй бит (INIT) подаем «1» (на контакте 1 будет «1») и, наконец, на третий бит (-SELECT IN) подаем «1» (на контакте 17 будет «0»), т.е. мы записали по адресу &H37A число 10112,-это 1310. Значит, чтобы на выходе получить 6 надо подать 13.
Для удобства привожу таблицу со всеми возможными комбинациями чисел от 0 до 15
Подаваемый
сигнал |
Получаемый
сигнал |
||||||||
Десятичное число |
(-STROBE) 20 |
(-AUTO) 21 |
(INIT) 22 |
(-SELECT IN) 23 |
контакт 1 |
контакт 14 |
контакт 16 |
контакт 17 |
Десятичное число |
|
1 |
2 |
4 |
8 |
1 |
2 |
4 |
8 |
|
0 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
11 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
10 |
2 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
1 |
9 |
3 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
8 |
4 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
15 |
5 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
1 |
14 |
6 |
0 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
13 |
7 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
1 |
12 |
8 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
0 |
3 |
9 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
2 |
10 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
0 |
1 |
11 |
1 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
12 |
0 |
0 |
1 |
1 |
1 |
1 |
1 |
0 |
7 |
13 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
6 |
14 |
0 |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
5 |
15 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
4 |
Ну и, наконец, последнее в этой части статьи. Если ваш компьютер поддерживает стандарт EPP, то четвертым битом по адресу &H37A вы сможете разрешить прерывание (для LPT1 это IRQ7) от принтера, только не спрашивайте меня что это такое, я все равно ничего не знаю про прерывания. А вот пятым битом 1101012 , например, подав число 4310, вы устанавливаете шину D0-D7 в режим ПРИЕМА данных. При этом все разряды (контакты 2-9) принимают значение логической «1». Чтобы подать на нужный контакт логический «0» надо замкнуть его через сопротивление 240 – 360 Ом на «землю». Таким образом, через LPT порт компьютера мы получаем в стандартном виде устройство с 12-ю выходными сигналами и 5-ю входными, а при переводе порта в режим EPP мы получаем 4 выходных сигнала и 13 входных сигналов.
Режим SPP (12 выходов и 5 входов) |
|
Режим EPP (4 входа и 13 выходов) |
||
Сигнал |
Направление |
|
Сигнал |
Направление |
D0 |
Выход |
|
D0 |
Вход |
D1 |
Выход |
|
D1 |
Вход |
D2 |
Выход |
|
D2 |
Вход |
D3 |
Выход |
|
D3 |
Вход |
D4 |
Выход |
|
D4 |
Вход |
D5 |
Выход |
|
D5 |
Вход |
D6 |
Выход |
|
D6 |
Вход |
D7 |
Выход |
|
D7 |
Вход |
ERROR |
Вход |
|
ERROR |
Вход |
SELECT |
Вход |
|
SELECT |
Вход |
PAPER END |
Вход |
|
PAPER END |
Вход |
ACK |
Вход |
|
ACK |
Вход |
-BUSY |
Вход |
|
-BUSY |
Вход |
-STROBE |
Выход |
|
-STROBE |
Выход |
-AUTO |
Выход |
|
-AUTO |
Выход |
INIT |
Выход |
|
INIT |
Выход |
-SELECT IN |
Выход |
|
-SELECT IN |
Выход |
Для записи сигналов на LPT порт я рекомендую собрать схему (рис.1), состоящую из восьми переключателей и восьми резисторов сопротивлением 270 Ом - 1 кОм. При данном положении переключателей (кнопок) SW1-SW8 на всех верхних контактах присутствует логическая «1», при замыкании любого – на соответствующем контакте появится логический «0». Контакты можно подключать непосредственно к шине D0-D7 (контакты 2-9, адрес &H378) или к ERROR, SELECT, PAPER END, ACK и –BUSY (контакты 15, 13, 12, 10 и 11, адрес &H379).
рис.1
Для отображения данных идущих с LPT порта рекомендую следующую схему.
рис.2
Резисторы R1-R8 номиналом 270 - 330 Ом, светодиоды любые, скажем АЛ307Б. Питания такая схема не требует, все и так будет светиться. Я себе вывел вообще все сигналы, сразу все видно. А вообще настоятельно рекомендую скачать программу LPT 3D HARD Analyzer. Написал ее Валерий Ковтун. С помощью этой программы … в общем сами увидете.
Давайте соберем генератор прямоугольных импульсов на микросхеме К561ЛА7. Питание генератора +5В. Дело в том, что удобнее все устройства собирать, например, на 155, 555 серии, чтобы сигналы имели ТТЛ уровень. Логический «ноль» 0-0,8В и лог «единица» 2,4-4,2В. Удобство 561 серии заключается в универсальности питания - она одинаково хорошо работает от +3В до +12В. Поэтому выбор микросхем остается на ваш вкус, вопрос лишь в том, чтобы получить прямоугольные импульсы амплитудой не более +5В. Схема простого генератора импульсов изображена на рисунке 3.
рис.3
Сам генератор собран на элементах D1.1-D1.3, а элемент D1.4 я просто использовал для более «красивых» фронтов выходных импульсов. R1, R2, C1 – частотозадающие элементы. При данных параметрах элементов частота генерации составляет приблизительно 5-7 Гц. Для наглядности работу генератора можно представить в виде следующего графика:
рис.4
Выход инвертора D1.4 соединен с 2 контактом LPT разъема (шина D0). Перед использованием генератора, необходимо перевести шину D0-D7 в режим приема данных. Для этого на адрес &H37A мы посылаем 43.
Код следующий. Для тех, кто
использует |
||
inpout32.dll |
dlportio.dll |
DOS |
Out &H37A, 43 |
DlPortWritePortUchar &H37A, 43 |
OUT &H37A, 43
|
, а после этого начинаем опрашивать порт &H378.
Код следующий. Для тех, кто
использует |
||
inpout32.dll |
dlportio.dll |
DOS |
Dim A as IntegerA = Inp(&H378) |
Dim A as IntegerDlPortReadPortUchar(&H378) |
DEFINT A-ZA=INP(&H378) |
Переменная A будет принимать значение то 254, то 255. Почему?
D0 |
D1 |
D2 |
D3 |
D4 |
D5 |
D6 |
D7 |
|
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
|
1 |
2 |
4 |
8 |
16 |
32 |
64 |
128 |
|
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
255 |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
254 |
Дело в том, что после перевода шин D0-D7 в режим приема данных, на них выставляется уровень логической единицы (желтый ряд).
При появлении на шине D0 уровня лог «0» (голубой ряд) - первый бит принимает значение нуля, значит 0+21+22+23+24+25+26+27 = 254.
Таким образом, мы можем отследить изменение сигнала на шине D0, ну а если мы посчитаем количество изменений за 1 секунду, то мы получим… правильно - цифровой частотомер. Зная количество пришедших импульсов в секунду можно сказать о частоте в Герцах.
Итак, программа частотомер. На форме должны быть 3 кнопки и Label. Кнопка 1 пуск частотомер, Кнопка 2 стоп, Кнопка 3 – выход, Label – индицирует частоту.
*******************************************
Для тех, кто использует inpout32.dll
Option Explicit
'объявление библиотеки для работы с
адресами порта
Private
Declare Function Inp Lib
"inpout32.dll" Alias "Inp32" (ByVal
PortAddress As Integer) As Integer
Private
Declare Sub Out Lib "inpout32.dll" Alias "Out32" (ByVal PortAddress As Integer, ByVal Value As
Integer)
'объявление библиотеки для подсчета миллисекунд
Private
Declare Function GetTickCount Lib
"kernel32" () As Long
Dim FTV As Long 'начальное
значение системного времени
Dim STV As Long 'конечное
значение системного времени
Dim FV As Integer 'FV-начальное
состояние порта
Dim SV As Integer 'SV-сравниваемое
состояние порта
Dim cntr 'счетчик импульсов
Dim J As Integer 'J=1
счет разрешен, J=0 счет не разрешен
Private
Sub Command1_Click()
Out &H37A,
43 'переводим шины D0-D7 в режим чтения
FTV = GetTickCount 'запомнили
системное время в миллисекундах
J = 1 'счет - разрешить
FV = Inp(&H378) 'считали состояние порта
SV = FV 'SV равно состоянию порта
cntr = 0 'счетчик в ноль
Do While J
<> 0
DoEvents
STV = GetTickCount 'запоминаем
текущее системное время
If STV > FTV + 1000 Then
FrequencyShow 'если прошла секунда, отображаем результат
FV = Inp(&H378) 'постоянно опрашиваем адрес &H378
If FV <> SV Then 'если состояние порта изменилось
SV = FV 'SV
равно состоянию порта
cntr = cntr + 0.5 'счетчик + 0.5
End If
If J = 0 Then Exit Do 'если пользователь нажал Стоп
End Sub
Private
Sub Command2_Click()
'остановка цикла
'если пользователь нажал Стоп
J = 0
End Sub
Private
Sub Command3_Click()
J = 0 'счет – стоп
Out &H37A, 0 'восстанавливаем
состояние шины D0-D7
Unload Me
'выход из программы
End Sub
Public Sub FrequencyShow()
Label1.Caption = Int(cntr) & " Hz" 'отображаем
результат
cntr = 0
'счетчик в ноль
Pause (0.2)
'задержка. Нужна
для измерения малых частот
FTV = GetTickCount 'запомнили системное время в миллисекундах
End Sub
'Подпрограмма задержки. Формат вызова: Pause(число секунд)
Public
Sub Pause(Value As Single)
Dim
Start, Finish
Start =
Timer
Do While Timer < Start + Value
DoEvents
Finish =
Timer
End Sub
*******************************************
Для тех, кто использует dlportio.dll
Option Explicit
'объявление библиотеки для работы с
адресами порта
Private
Declare Function DlPortReadPortUchar Lib
"dlportio.dll" (
Private
Declare Sub DlPortWritePortUchar Lib
"dlportio.dll" (
'объявление библиотеки для подсчета миллисекунд
Private
Declare Function GetTickCount Lib
"kernel32" () As Long
Dim FTV As Long 'начальное
значение системного времени
Dim STV As Long 'конечное
значение системного времени
Dim FV As Integer 'FV-начальное
состояние порта
Dim SV As Integer 'SV-сравниваемое
состояние порта
Dim cntr 'счетчик импульсов
Dim J As Integer 'J=1
счет разрешен, J=0 счет не разрешен
Private
Sub Command1_Click()
DlPortWritePortUchar &H37A, 43 'переводим шины D0-D7 в режим чтения
FTV = GetTickCount 'запомнили системное время в миллисекундах
J = 1 'счет - разрешить
FV = DlPortReadPortUchar
(&H378) 'считали состояние порта
SV = FV 'SV равно состоянию порта
cntr = 0 'счетчик в ноль
Do While J
<> 0
DoEvents
STV = GetTickCount 'запоминаем
текущее системное время
If STV > FTV + 1000 Then
FrequencyShow 'если прошла секунда, отображаем результат
FV = DlPortReadPortUchar (&H378) 'постоянно
опрашиваем адрес &H378
If FV <> SV Then 'если состояние порта изменилось
SV = FV 'SV
равно состоянию порта
cntr = cntr + 0.5 'счетчик + 0.5
End If
If J = 0 Then Exit Do 'если пользователь нажал Стоп
End Sub
Private
Sub Command2_Click()
'остановка цикла
'если пользователь нажал Стоп
J = 0
End Sub
Private
Sub Command3_Click()
J = 0 'счет –
стоп
DlPortWritePortUchar &H37A, 0 'восстанавливаем
состояние шины D0-D7
Unload Me
'выход из программы
End Sub
Public Sub FrequencyShow()
Label6.Caption = Int(cntr) & " Hz" 'отображаем
результат
cntr = 0
'счетчик в ноль
Pause (0.2)
'задержка. Нужна
для измерения малых частот
FTV = GetTickCount 'запомнили системное время в миллисекундах
End Sub
'Подпрограмма задержки. Формат вызова: Pause(число секунд)
Public
Sub Pause(Value As Single)
Dim
Start, Finish
Start =
Timer
Do While Timer < Start + Value
DoEvents
Finish =
Timer
End Sub
*******************************************
И все? Спросите ВЫ. Да и все. Вот и вся программа, которая почему-то работает.
Ø
Как видите код
практически один и тот же для разных библиотек, поэтому далее на примерах мы
будем рассматривать код только с библиотекой dlportio.dll
Если внимательно проанализировать код программы частотомер, можно заметить, что к счетчику прибавляется 0.5,
cntr = cntr + 0.5,
а не 1. Дело в том, что данный код
программы считает переход состояния порта как из 1 в 0, так и
наоборот из 0 в 1, поэтому чтобы считать
частоту надо или прибавлять 0.5 , а потом выводить
Или прибавлять 1
cntr = cntr + 1,
А потом выводить
Вот такая математика.
Кстати, а вы не пробовали посадить какой-нибудь датчик на вращающийся вал какого-нибудь двигателя. Наверное, с помощью этой программы у вас получится прекрасный тахометр J
Ну что, поехали дальше.
Берем тот же генератор импульсов и вместо резистора R2 или R1 впаиваем терморезистор (автор статьи сходил в автомагазин и за 30 руб. купил термодатчик от ВАЗ-2101). Этот термодатчик меняет свое сопротивление в зависимости от температуры (3200 Ом при температуре +140С и 143 Ома при температуре +1000С.) Раз мы меняем сопротивление, то меняется и частота генератора, значит мы получаем преобразователь температура-частота, т.е. цифровой термометр. Хочу обратить ваше внимание на то, что изменение сопротивления в зависимости от температуры, происходит не линейно, что видно на следующем графике,
рис.5
поэтому «объяснить» компьютеру, что 100 импульсов это 20 градусов, а 110 импульсов – это 21 градус будет не очень просто, но тем не менее возможно. Вопрос только в размерах кода и алгоритме.
Если вместо резистора поставить датчик топлива от бензобака, то мы получим индикатор уровня жидкости. Отстраивать такой индикатор удобнее следующим образом:
1. Замеряем частоту импульсов при пустой емкости
2. Доливаем какой-то объем (в зависимости от того, какую градацию – точность вы хотите получить) и опять замеряем частоту
3. И так до самого верха вашей емкости.
А можно построить индикатор уровня жидкости по другому принципу, если собрать конструкцию на рисунке ниже.
рис.6
Если меняется уровень жидкости, то меняется и положение поплавка с магнитом, стало быть замыкаются (размыкаются ) соответствующие герконы. Трубку лучше всего использовать тонкостенную пластиковую. Схема данного устройства такова:
рис.7
Обрабатывать информацию с такого устройства можно по следующему алгоритму.
Ø
Некоторые могут мне
возразить, что не обязательно переводить шины D0-D7 в режим чтения, и так все будет работать. На это могу
ответить только следующее – кто хочет, пусть не переводит. Дискутировать на
этот предмет – не буду. Если порт &H378
не стоит в режиме приема данных и на используемом контакте (в нашем случае 2 – D0 ) присутствует логическая «1»,
то генератор работать не будет. Выходной ток шины D0-D7 в режиме передачи данных больше,
чем выходной ток КМОП микросхемы (561ЛА7), поэтому генерации не будет. Конечно,
если закоротить пинцетом контакт на землю, то никакого тока не хватит. Но мне
кажется, не трудно набрать лишнюю строчку кода и сделать так, как советуют
разработчики компьютерного железа.
Давайте теперь рассмотрим обратный процесс, т.е. процесс передачи данных с компьютера на ваше устройство. Возьмем для примера все тот же генератор импульсов, только немного изменим его схему.
рис.8
После подачи питания на генератор мы вдруг обнаружим, что генератор-то не работает. А будет он работать только тогда, когда на входе 2 элемента D1.1 появится уровень логической «1».
DlPortWritePortUchar &H378, 1
И все сразу заработало. Вот вам генератор, управляемый компьютером. Ну, генератор это все мелко, хотя надо отдать должное этому устройству – в очень многих электронных схемах за основу взят именно генератор импульсов. А не подключить ли нам что-нибудь посерьезнее к компьютеру.
Вот такая схема
рис.9
Вход данного устройства подключаем к любому понравившемуся нам выходу, например к D3, вход GND соединяем с общим проводом разъема, а вот +12В придется взять от отдельного источника питания. Реле можно взять автомобильное. Вообще все параметры элементов могут быть совершенно другими (я брал то, что было под рукой)
DlPortWritePortUchar &H378, 8
или
DlPortWritePortUchar &H378, 9
или
DlPortWritePortUchar &H378, 10
Главное, чтобы на шине D3 была лог «1». Реле сработает, а вот что вы к нему подцепите – это уже ваше дело. Вообще при коммутации высоковольтных устройств необходимо (на всякий случай) предохраниться от короткого замыкания, от пробоя на корпус, в общем сделать так. Чтобы в случае аварии ваш чудесный LPT порт не сгорел. Поэтому для таких подключений удобно использовать гальваническую развязку порта и вашего устройства, например, через оптопару.
рис.10
Если в вашем устройстве все «сгорит», то через свет – увы, ток не пройдет, не придумали еще такого.
Каждый из вас наверняка сталкивался в своей жизни с флоппи, CD и т.д. дисководами, принтерами, сканерами, в общем, устройствами, в состав которых входит шаговый двигатель. Вот сейчас будем его включать. На рисунке ниже схема, которую я нашел в интернете. Пусть простит меня автор, я не даю ссылку на него (просто не помню, где я ее нашел), но если он увидит эту статью, то узнает свою схему.
На самом деле все честно, все работает. Можно выложить еще кучу всяких схем, но нам сейчас важно понять не принцип работы схемы, а принцип подачи управляющих сигналов на двигатель. На диаграмме ниже – это видно.
На каждую из обмоток двигателя поочередно подаются импульсы, иногда на двух обмотках сразу присутствует высокий уровень сигнала. Если вы посмотрите на левую часть диаграммы и заметите D0-D3, то сразу поймете куда я клоню.
Вот что мы имеем в конечном итоге, ну и, конечно же, компьютер с LPT портом. Питание для двигателя придется делать самому, причем для каждого типа двигателя - свое. В соответствии с диаграммой на входы A, B, C, D мы подаем последовательно 3, 2, 6, 4, 12, 8, 9, 1 через &H378. Причем откуда начинать не критично, вопрос в сохранении последовательности и повторении ее по «кругу» или столько, сколько нужно. Если же изменить направление последовательности (задом-наперед), вращение двигателя будет в противоположную сторону. Данная последовательность дает команду двигателю делать полушаги (это зависит от конструкции двигателя), для управления полным шагом последовательность будет такой 3, 6, 12, 9.
И тут мне на глаза попался семисегментный индикатор на светодиодах от калькулятора. Решение пришло моментально.
Вот как устроен такой индикатор.
Для простоты я нарисовал 4-х разрядный (в моем индикаторе их 12) семисегментный индикатор на светодиодах. На разряды 1-4 подаем 0, а на сегменты подаем + питание (для каждого типа индикатора свои параметры питания). Все сегменты объединены, поэтому зажигать такой индикатор нужно динамической индикацией. Кто хоть раз сам собирал электронные часы, тот знает, что это такое, но на всякий случай рассмотрим это по подробнее.
Шаг 1. На первый разряд подается низкий уровень сигнала, а на сегментах (высоким уровнем) выставляется код цифры, которую мы хотим увидеть.
Шаг 2. На второй разряд подается низкий уровень сигнала, а на сегментах (высоким уровнем) выставляется код цифры, которую мы хотим увидеть.
Шаг 3. На третий разряд подается низкий уровень сигнала, а на сегментах (высоким уровнем) выставляется код цифры, которую мы хотим увидеть.
Шаг 4. На четвертый разряд подается низкий уровень сигнала, а на сегментах (высоким уровнем) выставляется код цифры, которую мы хотим увидеть.
И опять по новой шаг 1, 2 и т.д. Все это происходит очень быстро, поэтому наши глаза не успевают увидеть мерцание цифр.
Берем наш индикатор и разряды 1, 2, 3, 4 сажаем на STROBE(1), AUTO(14), INIT(16), SELECT IN(17). Это будет управление разрядами, а сегменты A, B, C, D, E, F, G сажаем на D0, D1, D2, D3, D4, D5, D6. Чтобы зажечь в первом разряде, например 1 (сегменты B,C) надо подать на адрес &H378 число 6, а на адрес &H37A – 197.
А вот и готовая программа – электронные часы.
На форме 2 кнопки. Первая запускает часы, вторая останавливает. Параметр Z = 0.004 подбирал опытным путем. Если задержку не ставить, то цифры сливаются, слишком быстро все происходит, и светодиод не успевает погаснуть.
Option Explicit
'объявление библиотеки для работы с адресами LPT порта
Private Declare Function DlPortReadPortUchar Lib “dlportio.dll” (ByVal Port As Long) As Byte
Private Declare Sub DlPortWritePortUchar Lib «dlportio.dll» (ByVal Port As Long, ByVal Value As Byte)
Dim I, J As
Integer
Dim Z As
Single
Dim A As
String
Private Sub Command1_Click()
J
= 1 'разрешение
цикла
Z
= 0.004 'задержка
Do While J <> 0
DoEvents
A = Mid$(Time$, 5, 1)
'считываем единицы минут
DlPortWritePortUchar
&H37A, 197 'разрешаем засветиться первому разряду
writetime 'отображаем
единицы минут
A = Mid$(Time$, 4, 1)
'считываем десятки минут
DlPortWritePortUchar
&H37A, 198 'разрешаем засветиться второму разряду
writetime 'отображаем
десятки минут
A = Mid$(Time$, 2, 1)
'считываем единицы часов
DlPortWritePortUchar
&H37A, 192 'разрешаем засветиться третьему
разряду
writetime 'отображаем
единицы часов
A = Mid$(Time$, 1, 1)
'считываем десятки часов
DlPortWritePortUchar
&H37A, 204 'разрешаем засветиться четвертому
разряду
writetime
'отображаем десятки часов
If J = 0 Then Exit Do
DlPortWritePortUchar &H378, 0
End Sub
Public Sub writetime()
Select Case Val(A)
Case Is = 0
I
= 63 'код 0
для семисегментного индикатора
Case Is = 1
I = 6
'код 1 для семисегментного
индикатора
Case Is = 2
I = 91
'код 2 для семисегментного
индикатора
Case Is = 3
I = 79
'код 3 для семисегментного
индикатора
Case Is = 4
I = 102
'код 4 для семисегментного
индикатора
Case Is = 5
I = 109
'код 5 для семисегментного
индикатора
Case Is = 6
I = 125
'код 6 для семисегментного
индикатора
Case Is = 7
I = 7
'код 7 для семисегментного
индикатора
Case Is = 8
I = 255
'код 8 для семисегментного
индикатора
Case Is = 9
I = 239
'код 9 для семисегментного
индикатора
End Select
DlPortWritePortUchar
&H378, I 'пишем
код для семисегментного индикатора
Pause (Z) 'задержка
End Sub
Private Sub Command2_Click()
J = 0
DlPortWritePortUchar &H378, 0
End Sub
'Процедура задержки. Формат вызова: Pause(число секунд)
Public Sub Pause(Value As Single)
Dim Start, Finish
Start = Timer
Do While Timer < Start + Value
DoEvents
Finish = Timer
End Sub
Вот так это в жизни работает.
Я не буду описывать подключение люминесцентных индикаторов, но скажу честно пробовал – работает. На сетки разрядов подавал положительный потенциал, нить накала заземлил, а на сегменты подавал 1 через D0-D6. Все светится. ЖКИ индикаторы не пробовал, надо придумать, где взять 64 Гц. Если кто подключит - буду рад получить от вас схему. Кстати интересная мысль – можно сделать бегущую строку на светодиодах для отображения буквенно-цифровой информации. В общем, лишний раз убеждаюсь, что этот порт – прекрасный инструмент для творчества.
Вот еще небольшая тема насчет электродвигателей. Не у всех есть шаговые двигатели, да и не всегда это удобно и нужно. Давайте попробуем обойтись простым двигателем с редуктором, например для точного перемещения некоторого устройства в горизонтальной плоскости. Пусть это будет карандаш или фломастер. Двигатель связан с понижающим редуктором, который в свою очередь связан с осью имеющей резьбу. На оси с резьбой жестко закреплен диск с металлическими секторами (контактными площадками или прорезями для оптики), например, такой
или
Это уже не
принципиально, важно то, что, зная шаг резьбы, например, шаг
Идем дальше. Программа управления двигателем работает, например, по такому алгоритму.
Управление идет через шины D0-D7 и/или через порт &H37A, команды от исполнительных устройств (датчиков) приходят на &H379 и/или &H378. В общем, дальше ваша фантазия и возможности. Тот же принцип логично использовать для перемещения каретки в перпендикулярной плоскости. И вот вам станок с перемещением в двух направлениях. Т.е. построить дома станок с ЧПУ (числовым программным управлением) вполне РЕАЛЬНО.
Хочется чего-нибудь такого – не земного. Хочу коммутировать сигналы с моего музыкального центра. Ага. Давайте попробуем…
Берем для примера СЧЕТВЕРЕННЫЙ ДВУНАПРАВЛЕННЫЙ ПЕРЕКЛЮЧАТЕЛЬ. Звучит, конечно, ужасно, но на деле все просто. Сие устройство есть ничто иное, как программируемый выключатель.
Микросхема 561(564)КТ3 представляет собой действительно 4 электронных ключа, которыми можно управлять, подавая на входы 3, 5, 6, 12 уровень логической «1», тем самым, замыкая контакты 1-2, 4-3, 8-9, 11-10. Значит у нас в руках уже коробочка с блоком питания и с микросхемой подключенной к разъемам с сигналами, ну и, конечно же, компьютер, с красиво оформленной программой. В общем, все друзья в отпаде. Хотим так коммутируем, хотим эдак. Направление сигналов не принципиально. Только не забудьте на 14 ножку подать питание +9В, а 7 ножку соединить с общим корпусом, ну и не надо коммутировать этой микросхемой 220В.
Небольшой комментарий.
При подключении видео сигналов, возможно (возможно, это при большой длине кабеля, но не обязательно) влияние каналов, коммутирующих видео сигналы, друг на друга. Ниже приведена схема для коммутации видео сигнала с различных источников на один телевизор. Для коммутации звуковых сигналов необходимо добавить по микросхеме на каждый канал звука. Итого 3 микросхемы.
Управляющие входы всех микросхем надо объединить в соответствии с источниками. Например, на первый вход коммутатора подается сигнал с видеокамеры, значит, управляющие входы CH1 всех трех микросхем должны быть объединены. И так для каждого из каналов.
При программировании коммутатора не забудьте, что каждый канал (видео, правый звук, левый звук) уникален и смешивать их нельзя. Если смешать видео сигналы (одновременно подключив два источника на выход), то телевизор не сможет синхронизоваться по видео сигналу. Если смешать звук, то в лучшем случае вы получите наложение одного звука на другой. Поэтому если вы, например, решили для коммутации использовать выходы 2, 3, 4, 5 LPT-разъема, то по адресу &H378 надо подавать 1, 2, 4, 8, но никак не 3 или 5. Ну, вы меня понимаете J