Пример использования 32-битового интерфейса для организации простейшей MicroLAN – ЧАСТЬ 2

January 22, 2013 by admin Комментировать »

В нашей сети будут функционировать четыре датчика температуры. На вид они неразличимы. Их идентификационные коды1 спрятаны! внутри и прочитать их можно лишь программным путем. Можно, конечно, воспользоваться командой "Исследование ПЗУ" для идентификации всех датчиков сети. Но при этом остается неясным, какому именно физическому датчику соответствует данный код. Мы поступим другим способом. Перед установкой датчиков на кабель сети протестируем каждый из них командой "Чтение ПЗУ". Для этого, поочередно подключая датчики к одному из мастеров, прочитаем его ПЗУ с помощью этой команды.

Ниже представлен листинг программы! на бейсике, которая выполняет единственную функцию: читает ПЗУ подключенного к шине датчика. В этой программе предполагается, что датчик подключается к биту 0 первого канала интерфейса и что используется внешнее питание датчика.

Листинг 1. Программа чтения ПЗУ отдельного датчика

‘Объявляем процедуры

DECLARE SUB ReadROM (Address%, Bit%)

DECLARE FUNCTION SearchForPresence% (Address%, Bit%)

DECLARE SUB Delay ()

‘Объявляем переменные

DIM SHARED FirstAddress AS INTEGER

DIM SHARED SecondAddress AS INTEGER

DIM SHARED ThirdAddress AS INTEGER DIM SHARED FourthAddress AS INTEGER DIM SHARED StatusAddress AS INTEGER

DIM SHARED ReadR0MArray(7) AS INTEGER ‘Массив, содержащий биты

‘команды 33h

‘Определяем численные значения констант и переменных

FirstAddress = &H360

SecondAddress = FirstAddress + 1

ThirdAddress = FirstAddress + 2

FourthAddress = FirstAddress + 3

StatusAddress = FirstAddress + 4

‘Заполняем массив команды "Чтение ПЗУ"

A% = &H33

FOR I% = 7 TO 0 STEP -1

ReadR0MArray(I%) = A% \ 2 Л I%

A% = A% MOD 2 a I%

NEXT I%

‘Запускаем цикл чтения ПЗУ T! = TIMER

DO UNTIL TIMER T! > 1 ‘Устанавливаем время тайм-аута равным 1 сек A% = SearchForPresence(FirstAddress, 0) ‘Проверяем наличие

‘датчика

SELECT CASE A%

CASE 0 ‘Датчик подключен

CALL ReadR0M(FirstAddress, 0) ‘Вызываем процедуру чтения

‘ПЗУ

CASE 1 ‘Датчик не подключен

PRINT "На линии нет датчиков температуры"

END SELECT

IF INKEY$ = CHR$(27) THEN EXIT DO ‘Обеспечиваем выход по

‘клавише "Esc"

LOOP

END

SUB Delay ‘Подпрограмма, формирующая длительность временного ‘слота

FOR I% = 1 TO 40: NEXT I%

END SUB

SUB ReadROM (Address%, Bit%) ‘Подпрограмма чтения ПЗУ DS1820 DO

‘Очищаем строковую переменную для содержимого ПЗУ S$ = ""

‘Проводим инициализацию DO

A% = SearchForPresence(Address%, Bit%)

SELECT CASE A%

CASE 0 EXIT DO CASE ELSE EXIT SUB END SELECT LOOP

‘Выдаем команду "Чтение ПЗУ" (33h)

FOR I% = 0 TO 7

SELECT CASE ReadROMArray(I%)

CASE 0                                   ‘Записываем "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Посылаем 64 временных слота чтения и прочитанные биты ‘складываем в ‘строковую переменную S$

FOR U% = 0 TO 63 OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0

A% = (INP(Address%) AND 2 Л Bit%) / 2 л Bit%

S$ = S$ + RTRIM$(LTRIM$(STR$(A%)))

NEXT U%

‘Вычисляем ЦИК

‘Определяем 8-битовый сдвиговый массив (регистр)

DIM Register(7) AS INTEGER

‘Обнуляем этот массив

FOR I% = 0 TO 7: Register(I%) = 0: NEXT I%

‘Начиная с младшего разряда, побитово обрабатываем данные с ‘помощью функции

‘XOR и сдвигового регистра. Проходим все биты, кроме старших ‘восьми. В результате в регистре (массиве) окажется ЦИК.

N% = LEN(S$) 8 FOR I% = 1 TO N%

C% = VAL(MID$(S$, I%, 1))

A% = Register(0) XOR C%

B% = Register(3) XOR A%

C% = Register(4) XOR A%

Register(O) = Register(1)

Register(1) = Register(2)

Register(2) = B%

Register(3) = C%

Register(4) = Register(5)

Register(5) = Register(6)

Register(6) = Register(7)

Register(7) = A%

NEXT l%

‘Преобразуем числовое значение регистра в строковое G$ = ""

FOR l% = O TO 7

G$ = G$ + RTRlM$(LTRlM$(STR$(Register(l%))))

NEXT l%

‘Сравниваем полученную строку со старшими 8-ю битами строки ‘данных. Если эти строки совпадают, то данные приняты верно lF G$ = RlGHT$(S$, 8) THEN EXlT DO ELSE

EXlT SUB END lF LOOP

‘Выводим содержимое ПЗУ на экран ( для удобства сначала одной ‘строкой, а затем в столбик побайтово)

CLS

LOCATE 1, 1: PRlNT S$;

LOCATE 3, 1 FOR l% = O TO 7

PRlNT MlD$(S$, 1 + l% * 8, 8)

NEXT l%

SLEEP END SUB

FUNCTlON SearchForPresence% (Address%, Bit%)

‘Функция проверки присутствия на линии хотя бы одного датчика ‘температуры

‘Ждем пока шина перейдет в высокое состояние OUT StatusAddress, O DO

A% = lNP(Address%) AND 2 Л Bit%

LOOP WHlLE A% = O ‘Сбрасываем нужный бит OUT Address%, 255 2 л Bit%

OUT StatusAddress, 1

‘Задержка на длину импульса сброса

FOR I% = 1 TO 10: Delay: NEXT I%

‘Освобождаем шину

OUT StatusAddress, 0

‘Задержка на восстановление шины

Delay

‘Читаем импульс присутствия SearchForPresence = INP(Address%) AND 2 Л Bit%

‘Ждем пока шина перейдет в высокое состояние OUT StatusAddress, 0 DO

A% = INP(Address%) AND 2 л Bit%

LOOP WHILE A% = 0 END FUNCTION

По поводу этого листинга следует сделать пару замечаний. Во-первых, чтобы не усложнять картину, мы все временные задержки оформили в виде пустых циклов. Это самый простой способ создания в программе временных задержек, но не самый хороший. При использовании пустых циклов длительность задержки целиком зависит от аппаратного обеспечения компьютера. На разных компьютерах вышеприведенная программа будет давать разные задержки. Может сложиться ситуация, когда она вообще не будет работать. Для ее правильного функционирования число пустых циклов для задержек нужно выбирать, исходя из быстродействия конкретного компьютера. На практике это делается путем подбора. Можно, например, ввести в программу процедуру, которая, опираясь на внутренний таймер, определит, сколько времени займет, например, выполнение 1000000 пустых циклов. Разделив затем это число циклов на число микросекунд прошедшего временного интервала, можно получить число пустых циклов, приходящихся на 1 микросекунду. Этим числом можно потом руководствоваться, вводя программные задержки, требуемые однопроводным протоколом обмена. Однако, и здесь никакой гарантии точности отсчета временных интервалов нет. Дело в том, что, в зависимости от конкретных задач, решаемых в данный момент процессором, число пустых циклов в единицу времени будет различным. Тем не менее, наши исследования показали, что такая организация временных интервалов для целей однопроводного протокола дает надежные результаты. Для более грамотного определения временных задержек можно, например, пойти по пути перепрограммирования микросхемы таймера. Второе замечание по поводу вышеприведенного листинга заключается в том, что в нем не отражены! процедуры! сохранения полученного значения ПЗУ в файле в виде, удобном для дальнейшего использования. Программа также не оптимизирована по коду и времени работы. Она служит исключительно для иллюстрации процесса чтения ПЗУ.

Наконец, приведем листинг программы, обеспечивающей опрос четырех датчиков нашей сети (рис. 6.4), вывод значений температуры! на экран монитора, а также вывод каждые четверть часа значений температуры в файл с привязкой к реальным времени и дате. Иными словами, эта программа позволяет осуществить постоянный мониторинг температуры четырех точек объекта и зафиксировать эти температуры в файле.

Листинг 2. Программа опроса четырех датчиков температуры

‘Объявляем процедуры

DECLARE SUB ConvertAndReadTemperature (Address%, A$, N%, M%, T$) DECLARE FUNCTION SearchForPresence% (Address%, Bit%)

DECLARE SUB FillCommandArrays ()

DECLARE SUB Delay ()

‘Объявляем переменные DIM SHARED FirstAddress AS INTEGER DIM SHARED SecondAddress AS INTEGER DIM SHARED ThirdAddress AS INTEGER DIM SHARED FourthAddress AS INTEGER DIM SHARED StatusAddress AS INTEGER

DIM SHARED ConvertTemperatureArray(7) AS INTEGER ‘Массив, ‘содержащий биты команды 44h

DIM SHARED MatchROMArray(7) AS INTEGER ‘Массив, содержащий биты ‘команды 55h

DIM SHARED ReadScratchpadArray(7) AS INTEGER ‘Массив, содержащий ‘биты команды BEh

DIM SHARED UniqueCodesArray(3) AS STRING * 64 ‘Массив, содержащий ‘коды ПЗУ подключенных датчиков

DIM SHARED Temperature(3) AS SINGLE ‘Массив для хранения значений ‘температур

DIM SHARED ErrorFlag AS INTEGER ‘Флаг факта ошибочного чтения

‘Подключаем файлы, содержащие объявления функций ‘форматирования времени ‘$INCLUDE: ‘datim.bi’

‘$INCLUDE: ‘format.bi’

‘Определяем численные значения констант и переменных

CONST TRUE = -1

CONST FALSE = 0

FirstAddress = &H360

SecondAddress = FirstAddress + 1

ThirdAddress = FirstAddress + 2

FourthAddress = FirstAddress + 3

StatusAddress = FirstAddress + 4

‘Вызываем подпрограмму заполнения массивов команд FillCommandArrays

‘Заполняем содержимым ПЗУ подключенных датчиков соответствующий ‘массив

UniqueCodesArray(0) = "000010001000110110100000100111000000000000000000000000000100 0011"

UniqueCodesArray(1) = "000010001001111111011010100111000000000000000000000000001000 0100"

UniqueCodesArray(2) = "000010000011011000000010100111000000000000000000000000001110 1110"

UniqueCodesArray(3) = "000010001100100010011000100111000000000000000000000000001011 0101"

‘Рабочий цикл опроса датчиков и фиксации их показаний CLS

LOCATE 1,  1: PRINT                            "Температура          первого датчика        =          ";

LOCATE 2,  1: PRINT                            "Температура          второго датчика         =          ";

LOCATE 3,  1: PRINT                            "Температура          третьего датчика       =          ";

LOCATE 4,  1: PRINT                            "Температура  четвертого датчика = ";

DO

ErrorFlag = 0 T$ = TIME$

FOR U% = 0 TO 3 SELECT CASE U%

CASE 0, 2

CALL ConvertAndReadTemperature(FirstAddress, UniqueCodesArray(U%), U%, 0, T$)

CASE 1, 3

CALL ConvertAndReadTemperature(FirstAddress, UniqueCodesArray(U%), U%, 1, T$)

END SELECT NEXT U%

IF ErrorFlag = 0 THEN

LOCATE 1, 34: PRINT USING "+###.#"; Temperature(0);

LOCATE 2, 34: PRINT USING "+###.#"; Temperature(l);

LOCATE 3, 34: PRINT USING "+###.#"; Temperature(2);

LOCATE 4, 34: PRINT USING "+###.#"; Temperature(3);

END IF

SELECT CASE MID$(T$, 4, 5) ‘Каждые четверть часа пишем

‘показания в файл CASE "00:00", "15:00", "30:00", "45:00"

SELECT CASE ErrorFlag CASE 0 A# = Now#

D$ = FormatD$(A#, "dd-mm-yyyy")

T$ = FormatD$(A#, "hh:mm:ss")

X$ = D$ + "_" + T$

FileNumber = FREEFILE

FileName$ = MID$(D$, 7, 4) + MID$(D$, 4, 2) + MID$(D$, 1,

2) + ".dat"

OPEN FileName$ FOR APPEND AS FileNumber PRINT #FileNumber, TAB(0); A#; TAB(19); X$;

FOR I% = 0 TO 3

PRINT #FileNumber, TAB(39 + I% * 7); USING "+###.#";

Temperature(I%);

NEXT I%

CLOSE FileNumber BEEP

DO UNTIL MID$(TIME$, 7, 2) <> "00": LOOP CASE ELSE END SELECT CASE ELSE END SELECT

IF INKEY$ = CHR$(27) THEN EXIT DO LOOP END

SUB ConvertAndReadTemperature (Address%, ROMCode$, Unit%, Bit%,

T$)

‘Подпрограмма выдачи заданий датчикам на преобразование ‘температуры и съем информации с них

Temperature(Unit%) = 0 ‘Проводим инициализацию DO

A% = SearchForPresence(Address%, Bit%)

SELECT CASE A%

CASE 0 EXIT DO CASE ELSE EXIT SUB END SELECT

‘Выдаем команду "Выбор ПЗУ" (55h)

FOR I% = 0 TO 7

SELECT CASE MatchROMArray(I%)

CASE 0                                        ‘Записываем "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Выдаем 64-битовый код нужного датчика FOR I% = 1 TO 64

SELECT CASE VAL(MID$(ROMCode$, I%, 1))

CASE 0                                        ‘Записываем  "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Записываем в DS1820 команду 44h ("Преобразование температуры") FOR I% = 0 TO 7

SELECT CASE ConvertTemperatureArray(I%)

CASE 0                                        ‘Записываем  "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Ждем 500 мс пока происходит преобразование SELECT CASE T$

CASE "24:00:00"

T! = 0: DO UNTIL TIMER T! > .5: LOOP CASE ELSE

T! = TIMER: DO UNTIL TIMER T! > .5: LOOP END SELECT

‘Проводим инициализацию DO

A% = SearchForPresence(Address%, Bit%) SELECT CASE A%

CASE 0 EXIT DO CASE ELSE EXIT SUB END SELECT LOOP

‘Выдаем команду "Выбор ПЗУ" (55h)

FOR I% = 0 TO 7

SELECT CASE MatchROMArray(I%)

CASE 0                                        ‘Записываем "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Выдаем 64-битовый код нужного датчика FOR I% = 1 TO 64

SELECT CASE VAL(MID$(ROMCode$, I%, 1)) CASE 0       ‘Записываем           "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay

END SELECT NEXT I%

‘Записываем команду BEh ("Чтение СОП") в DS1820 FOR I% = 0 TO 7

SELECT CASE ReadScratchpadArray(I%)

CASE 0                                        ‘Записываем  "0"

OUT Address%, 0 OUT StatusAddress, 1 Delay

OUT StatusAddress, 0 CASE 1 ‘Записываем        "1"

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0 Delay END SELECT NEXT I%

‘Читаем девять байтов полной СОП датчика в строковую переменную S$ S$ = ""

FOR U% = 0 TO 71

OUT Address%, 0 OUT StatusAddress, 1 OUT StatusAddress, 0

A% = (INP(Address%) AND 2 Л Bit%) / 2 л Bit%

S$ = S$ + RTRIM$(LTRIM$(STR$(A%)))

NEXT U%

‘Вычисляем ЦИК

‘Определяем 8-битовый сдвиговый массив (регистр)

DIM Register(7) AS INTEGER

‘Обнуляем этот массив

FOR I% = 0 TO 7: Register(I%) = 0: NEXT I%

‘Начиная с младшего разряда, побитово обрабатываем данные с ‘помощью функции XOR и сдвигового регистра. Проходим все биты, ‘кроме старших восьми. В результате в регистре (массиве) окажется ‘ЦИК.

N% = LEN(S$) 8 FOR I% = 1 TO N%

C% = VAL(MID$(S$, I%, 1))

A% = Register(0) XOR C%

B% = Register(3) XOR A%

C% = Register(4) XOR A%

Register(0) = Register(1)

Register(1) = Register(2)

Register(2) = B%

Register(3) = C%

Register(4) = Register(5)

Register(5) = Register(6)

Register(6) = Register(7)

Register(7) = A%

NEXT I%

‘Преобразуем числовое значение регистра в строковое G$ = ""

FOR I% = 0 TO 7

G$ = G$ + RTRIM$(LTRIM$(STR$(Register(I%))))

NEXT I%

‘Сравниваем полученную строку со старшими 8-ю битами строки ‘данных. Если эти строки совпадают, то данные приняты верно IF G$ = RIGHT$(S$, 8) THEN A% = TRUE ELSE

A% = FALSE ErrorFlag = 1 EXIT SUB END IF

‘Вычисляем значения температуры SELECT CASE A%

CASE TRUE

L$ = MID$(S$, 1, 8)

H$ = MID$(S$, 9, 8)

T% = 0

SELECT CASE INSTR(H$, "1") ‘Если в старшем байте "1", то T° < 0 CASE 0

FOR I% = 8 TO 1 STEP -1

T% = T% + VAL(MID$(L$, I%, 1)) * 2 Л (I% 1)

NEXT I%

Temperature(Unit%) = T% / 2 CASE ELSE

FOR I% = 8 TO 1 STEP -1

T% = T% + VAL(MID$(L$, I%, 1)) * 2 л (I% 1)

NEXT I%

Temperature(Unit%) = (T% 256) / 2 END SELECT CASE FALSE END SELECT END SUB

SUB Delay ‘Подпрограмма временной задержки (задает длительность ‘временного ‘слота)

FOR I% = 1 TO 40: NEXT I%

END SUB

SUB FillCommandArrays ‘Подпрограмма заполнения массивов,

‘содержащих коды команд

‘Заполняем массив команды "Выбор ПЗУ (55h)"

A% = &H55

FOR I% = 7 TO 0 STEP -1

MatchROMArray(I%) = A% \ 2 Л I%

A% = A% MOD 2 a I%

NEXT I%

‘Заполняем массив команды "Преобразование температуры (44h)" A% = &H44

FOR I% = 7 TO 0 STEP -1

ConvertTemperatureArray(I%) = A% \ 2 Л I%

A% = A% MOD 2 a I%

NEXT I%

‘Заполняем массив команды "Чтение СОП (BEh)"

A% = &HBE

FOR I% = 7 TO 0 STEP -1

ReadScratchpadArray(I%) = A% \ 2 Л I%

A% = A% MOD 2 a I%

NEXT I%

END SUB

FUNCTION SearchForPresence% (Address%, Bit%)

‘Функция проверки присутствия на линии хотя бы одного датчика ‘температуры

‘Ждем пока шина перейдет в высокое состояние OUT StatusAddress, 0 DO

A% = INP(Address%) AND 2 Л Bit%

LOOP WHILE A% = 0 ‘Сбрасываем нужный бит OUT Address%, 255 2 л Bit%

OUT StatusAddress, 1

‘Задержка на длину импульса сброса

FOR I% = 1 TO 10: Delay: NEXT I%

‘Освобождаем шину

OUT StatusAddress, 0

‘Задержка на восстановление шины

Delay

‘Читаем импульс присутствия SearchForPresence = INP(Address%) AND 2 Л Bit%

‘Ждем пока шина перейдет в высокое состояние OUT StatusAddress, 0 DO

A% = INP(Address%) AND 2 л Bit% LOOP WHILE A% = 0 END FUNCTION

Источник: Карначёв А.С., Белошенко В.А., Титиевский В.И., Микролокальные сети: интеллектуальные датчики, однопроводный интерфейс, системы сбора информации. Донецк: ДонФТИ НАНУ Украины, 2000. 199с. с ил.

Оставить комментарий

микросхемы мощности Устройство импульсов питания пример приемника провода витков генератора выходе напряжение напряжения нагрузки радоэлектроника работы сигнал сигнала сигналов управления сопротивление усилитель усилителя усиления устройства схема теория транзистора транзисторов частоты