Определение адресов устройств

Поскольку предполагается, что все устройства изготавливаются самостоятельно, то и все адреса устройствам будем назначать сами. Кроме того, при построении сети и программировании ведущего контроллера адреса устройств, тоже можно записать в память EEPROM самостоятельно. Но могут возникнуть различные непредвиденные ситуации, при которых может потребоваться перепрограммирование адресов устройств.

В протоколе 1-wire есть замечательная команда Saerch_Rom hF0 - определение серийных номеров датчиков. К сожалению, не получится создать подобный алгоритм для протокола RS-485, но можно поступить проще. Предлагается произвести последовательный обмен по сети со всеми устройствами с последовательным увеличением адреса в запросе.

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

То есть, ведомый контроллер передает посылку:

Если устройство с адресом h02 есть в сети, оно ответит на запрос:

Далее нужно записать адрес h02 в EEPROM, вычислить количество переданных устройством байтов, увеличить адрес и снова передать в сеть посылку – запрос на передачу данных.

Если устройства с адресом h02 в сети нет, нужно предусмотреть возможность автоматической смены адреса и формирования следующей посылки.

Программная реализация поиска адресов.

Запуск процедуры определения адресов можно выполнить любым способом:

· по прерыванию при нажатии кнопки;

· при каждом запуске системы (полный автомат);

· при выполнении какого либо условия при запуске.

Пока это не важно. Я выбрал последний вариант – если при старте системы нажата кнопка, запускается процедура определения адресов.

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

Далее подготавливается циклический опрос устройств на шине. Для этого в буфере передачи формируется запрос на чтение.

Прежде всего, понадобится дополнительная ячейка памяти в качестве счетчика адресов (ячейка ByteCountTX). В буфер передачи записывается команда на чтение – RD (h3C), устанавливается счетчик адресов = h01.

Кроме того, для того, чтобы не зациклиться при сканировании адресов навсегда, следует определить максимальное количество адресов в сети (переменная MaxDev = 50). Количество адресов в данной ситуации не обязательно должно быть равно 32 или 64. С одной стороны, нельзя выбирать слишком большое число, так как сканирование большого числа адресов потребует много времени, а с другой стороны, это число можно взять с небольшим запасом (не обязательно, чтобы адреса всех устройств в сети имели четко последовательные значения). При обмене данными по сети могут возникать различные ошибки, для их отслеживания в флаговом регистре flag_reg будет использоваться флаг ошибки – ErrF, и циклический счетчик ошибок – ячейка CountErr в RAM.

Со следующей команды начинается цикл подготовки запроса на чтение (метка Cycle1):

- увеличивается счетчик адресов и переписывается его значение в буфер передачи (обратите внимание, что изначально мы установили значение счетчика адреса = h01 (адрес ведущего контроллера), а этой командой мы его увеличили, и теперь сканирование начнется с адреса h02;

- поскольку произошло увеличение счетчика, проверяется его переполнение (если текущий адрес не равен MaxDev, работа продолжается, иначе – просканированы все допустимые адреса и нужно выйти из данной программы);

- вычисляется контрольная сумма посылки, и ее значение записывается в буфер передачи (контрольная сумма вычисляется по алгоритму CRC8;

- устанавливается счетчик циклической ошибки – CountErr =3.

С метки Cycle2 начинается цикл обмена данными по сети:

- если в предыдущем цикле обмена произошли ошибки, флаг ErrF в регистре flag_reg будет установлен, его необходимо сбросить, и соответственно выключить светодиод ошибки;

- поскольку длинна запроса на чтение всегда равна 3 байта, устанавливается счетчик – countbyte = 3;

- запускается работа модуля USART, разрешением прерывания UDRIE и разрешением прерываний глобально…

Далее обмен данными выполняется только на прерываниях, программа контроллера на это время зацикливается, ожидая пока не закончится передача данных (пока не будет включен приемник модуля – установлен бит RXEN в регистре UCSRB).

Для подготовки к приему данных нужно установить счетчик битов. Поскольку мы точно не знаем количество битов, которое передаст устройство, возьмем большее значение – countbyte = 15.

Далее прием данных выполняется только по прерыванию RXCIE, программа контроллера на это время зацикливается, ожидая пока не закончится прием данных (пока не будет выключен приемник модуля – сброшен бит RXEN в регистре UCSRB).

Поскольку значение счетчика байтов больше чем посылка от любого устройства, переключение модуля USART произойдет по срабатыванию прерывания от Т/С0.

В любом случае, после того как модуль USART переключится на передачу, программа выходит из цикла ожидания, и распределяет полученные данные по

После обмена данными программа проверяет точку записи. Если устройства с определенным ранее адресом в сети нет, точка записи будет равна нулю. В этом случае уменьшается циклический счетчик ошибок, и программа возвращается по метке Cycle2, производя повторный обмен по сети. После трех попыток обмена счетчик ошибок станет равен нулю. При этом программа перейдет по метке Cycle1, где увеличивается адрес устройства и вычисляется новое значение контрольной суммы, формируя, таким образом, новый запрос на передачу данных для следующего устройства. Обмен данными повторяется сначала до тех пор, пока при формировании посылки адрес устройства не будет равен максимальному значению. При этом программа перейдет по метке ExitRI, выключит светодиод режима определения адресов и выйдет из данного модуля.

Если обмен данными с устройством произойдет, хотя бы частично, в ячейке точки записи будет находиться количество принятых байтов посылки, а в буфере приема первый байт укажет тип устройства, а при верно полученных данных регистр crc8 должен быть = 0! Если это не так, программа, как и в первом случае, уменьшит циклический счетчик ошибки, и перейдет по метке Cycle2.

Если данные приняты правильно, и регистр crc8 = 0, программа распределит адрес устройства в EEPROM.

Для того, чтобы определить, к какому типу принадлежит устройство, считывается первый байт из буфера приема (байт типа устройства), выделяется старшая тетрада (в данном случае нам не важно сколько кнопок на панели или сколько каналов у диммера), и в адресную пару Z загружается адрес начала таблицы соответствия типа устройства и блока устройств в EEPROM. Эта таблица находится в файле tables.inc и выглядит следующим образом:

В первом столбце находятся допустимые типы устройств (только старшая тетрада), во втором и третьем столбцах адреса счетчиков количества устройств (сравните с таблицей распределения адресов в EEPROM), в последнем столбце находится максимальное количество устройств данного типа.

Программа считывает первый байт таблицы, и сравнивает его с байтом типа устройства. Если данные не совпадают, адрес в регистре Z увеличивается на 3, и снова считывается первый байт таблицы, только уже из следующей строки.

Если данные совпадут, или будет достигнут конец таблицы (END = hFF), программа перейдет по метке Equal_Type. Здесь в адресную пару Х из таблицы загружаются второй и третий байты из таблицы (адрес счетчика устройств в EEPROM), и считывается максимальное количество датчиков данного типа.

Обратите внимание, если полученный тип устройства не совпадает с данными в таблице, происходит обработка адреса этого устройства как дополнительного устройства.

Далее считывается количество уже определенных адресов устройств, и проверяется переполнение счетчика. Если значение счетчика больше или равно максимальному значению, адрес устройства не записывается, а программа переход по метке Cycle1, где происходит формирование запроса на передачу данных для следующего устройства.

Если значение счетчика не превышено, счетчик увеличивается на 1 и записывается в EEPROM. Адрес Х увеличивается на 1 (устанавливается адрес первого устройства данного типа) и происходит циклическое вычисление точки записи адреса устройства. При этом, до тех пор, пока счетчик не равен единице, адрес в Х увеличивается на 2 (байт адреса и байт длинны принимаемой посылки). Когда значение счетчика станет = 1, происходит переход по метке RecAddr, где переписывается адрес устройства из счетчика адресов (ячейка ByteCountTX) в ячейку EEPROM с адресом определенным в Х. Далее значение Х увеличивается на 1, и количество принятых байтов (точка записи PointRX) переписывается в следующую ячейку EEPROM.

После этого происходит возврат в начало цикла формирования запроса на передачу данных по метке Cycle1.

После сканирования адресов устройств, количество которых определенно переменной MaxDev, происходит выход из процедуры.