Итак, сегодня мы рассмотрим две особые команды интерфейса 1-wire, предназначенные для поиска устройств на шине, а также алгоритм поиска устройств с помощью этих команд.
Почему мы алгоритм именно рассмотрим, а не напишем? Да потому что он, вообще-то говоря уже написан. «Максимкины» инженеры накатали для этого специальный документ AN187, который лежит в сети в открытом доступе. Единственный его недостаток в том, что написан он на буржуинском, что, согласитесь, не очень удобно. Вот этот недостаток мы сегодня и исправим, ну и плюс, как всегда, некоторые подробности и объяснения по поводу того, откуда у этого алгоритма растут ноги.
Итак, первая команда называется «Search ROM» и имеет шестнадцатиричный код 0xF0. Она предназначена для поиска вообще всех подключенных к шине 1-Wire устройств.
Вторая команда называется «Alarm Search» и имеет шестнадцатиричный код 0xEC. Она предназначена для поиска всех подключенных к шине 1-Wire устройств, находящихся в состоянии Alarm.
Логика работы у обеих команд одинаковая. После того, как мастер отправляет в сеть одну из этих команд, все Slave-устройства, подпадающие под критерий поиска (то есть для команды «Search ROM» — вообще все устройства сети, а для команды «Alarm Search» — устройства, находящиеся в состоянии Alarm), начинают обмениваться с мастером информацией по следующему алгоритму:
1) Slave передаёт мастеру младший бит ROM
2) Slave передаёт мастеру инверсную копию младшего бита ROM и ждёт ответ от мастера
3) Если мастер присылает в ответ тот же самый бит, который Slave посылал ему в пункте 1, то Slave повторяет шаги 1,2 для следующего бита ROM, в противном случае Slave прекращает обмен данными с мастером
Теперь давайте мы эту логику пока запомним и немного от неё отвлечёмся. Рассмотрим просто произвольные двоичные числа. Ну, скажем, 8-битные. Ну, например такие: 10001010, 00110011, 10001100, 11001001. Всю группу этих двоичных чисел можно изобразить в виде двоичного дерева, ветвями которого являются биты в соответствующих разрядах, а узлами — места, после которых биты отличаются (то есть после которых ветвь раздваивается).
По такому принципу можно составить деревья как от младших битов к старшим, так и наоборот, но мы будем рисовать от младших битов к старшим (смотрим рисунок справа). Очевидно, что аналогичное двоичное дерево мы можем постоить для любой группы двоичных чисел, любой разрядности.
Видео:55. Знакомство с интерфейсом 1-wire (Урок 46. Теория)Скачать
Далее, вспоминаем основы программирования, а конкретно, — алгоритм прямого обхода двоичных деревьев. Что нам нужно для обхода некоего произвольного дерева? Всего две вещи: a) знать, где находятся узлы; б) уметь выбирать то или иное направление обхода.
А вот теперь вернёмся к логике работы команд поиска, описанной нами в самом начале статьи. И подумаем вот о чём:
1) Поскольку шина общая, то посылаемые мастером команды будут видеть сразу все устройства на шине. И, соответственно, отвечать будут тоже сразу все устройства, причём все одновременно, поскольку передача данных синхронизируется мастером.
2) Архитектура шины 1-Wire такова, что доминантным является низкий уровень сигнала на шине. То есть, если какие-то устройства будут выставлять на шине низкий уровень, а какие-то — высокий, то победят те, кто выставлял низкий уровень, и, соответственно, на шине установится низкий уровень.
Эти две особенности шины 1-Wire, в сочетании с логикой работы команд поиска, дают нам механизм определения узлов в двоичном дереве, составленном из ROM-адресов устройств, отвечающих заданным критериям поиска.
Тут всё очень просто. Со стороны мастера, когда он читает биты от slave-устройств, возможны следующие ситуации:
- Мастер считывает с шины 01. Это означает, что все устройства, участвующие в обмене данными, послали ему биты 01 (текущий бит ROM = 0, его инверсная копия = 1);
- Мастер считывает с шины 10. Это означает, что все устройства, участвующие в обмене данными, послали ему биты 10 (аналогично первому пункту, только наоборот);
- Мастер считывает с шины 00. Это означает, что какие-то устройства послали ему 01, а какие-то 10 (в обоих случаях победили те, кто посылал нули). Это означает, что перед мастером находится узел двоичного дерева, то есть на этой ветви существуют такие ROM-адреса, у которых следующий бит равен нулю и такие, у которых следующий бит равен единице;
- Есть ещё вариант, когда мастер считывает с шины 11. Казалось бы, такая ситуация является невероятной, однако она тоже возможна, например, если устройства, с которыми мастер решил продолжить разговор, отключились.
Читайте также: Тойота чайзер размеры шин
Видео:1-Wire ScannerСкачать
Осталось только найти механизм выбора направления обхода. Ну, тут уж всё очевидно, — такой механизм предоставляется нам третьим пунктом логики работы команд поиска. Ответ от мастера — это и есть выбор направления. Отправляя в шину в качестве ответа ноль или единицу, мастер как раз и решает с какой группой устройств он «продолжит разговор», по какой ветке он дальше пойдёт.
Теперь рассмотрим одну особенность алгоритма обхода двоичного дерева, характерную для шины 1-Wire. Особенность эта заключается в том, что мы можем двигаться по дереву только вперёд и каждый новый маршрут должны проходить с самого начала. То есть для каждого нового маршрута нужно заново посылать в шину Reset, команду поиска и доходить до того узла, на котором нам сейчас нужно повернуть в другую сторону. Соответственно, нам нужно будет как-то запоминать, где и куда мы в последний раз поворачивали.
Ну вот, пожалуй все важные моменты будущего алгоритма обхода двоичного дерева адресов ROM мы уже рассмотрели и теперь можем, наконец, этот алгоритм как-то формализовать. Давайте этим и займёмся, но для начала условимся в дальнейшем, для удобства, называть поворот в ветку, обозначающую нулевой бит, — поворотом налево, а поворот в ветку, обозначающую единичный бит, — поворотом направо. Кроме того, давайте уровень узла договоримся считать равным разряду битов, перед которыми этот узел расположен.
Всё, переходим к самому алгоритму.
I) Определимся с переменными, которые нам понадобятся:
- ROM[64] — массив, в котором по мере заполнения будет формироваться очередной найденный ROM;
- CRC — переменная, в которой мы будем вычислять CRC (подробнее про вычисление CRC можно прочитать здесь)
- SlaveBit, ISlaveBit — очередной бит и его инверсная копия, считанные с шины мастером;
- Step — переменная, показывающая, на каком шаге поиска мы находимся (бит какого разряда мы сейчас ищем);
- LastDev — флаг, показывающий, что мы нашли последний девайс (дальше продолжать поиск не нужно);
- MasterBit — переменная, в которой будет записан ответ от мастера (она определяет дальнейшее направление поиска);
- LastFork — уровень, на котором расположена последняя развилка, из которой мы поворачивали влево при предыдущем проходе по дереву (в этот раз на ней нужно повернуть направо);
- LastFamilyFork — здесь хранится уровень последней развилки, относящейся к семейству устройств (младший байт ROM)
- ZeroFork — сюда пишем уровни всех развилок, в которых мастер при текущем проходе по дереву отвечал нулём (поворачивал налево), в конце прохода отсюда мы узнаем уровень последней такой развилки.
Читайте также: Какие шины для пежо 308 зимние
II) Составим блок-схему процедуры прохода по одному из маршрутов:
Ну вот, теперь, используя приведённую выше блок-схему, легко можно реализовать алгоритм обхода двоичного дерева ROM-адресов, то есть найти все устройства, отвечающие критериям поиска, заданным соответствующей командой.
Для этого нужно инициализировать переменную LastDev значением 0, переменную LastFork значением -1 и выполнять составленную по блок-схеме процедуру столько раз, сколько потребуется, до тех пор, пока очередное выполнение не завершится с ошибкой (при этом каждый раз после успешного выполнения процедуры мы будем получать новое значение ROM).
Видео:62. 1 Wire команда SEARCH ROM (Урок 53. Теория)Скачать
Более того, если инициализировать значение ROM каким-либо номером, LastDev — нулём, а LastFork любым значением >64, то однократное выполнение процедуры позволяет проверить, есть ли на шине девайс с заданным номером. Если такого девайса нет, то выполнение процедуры завершится с ошибкой (на каком-то этапе мастер получит с шины две единицы).
Если записать в первый байт ROM код семейства, в остальные байты ROM — нули, LastFork инициализировать любым значением >64, а LastDev значением 0, то выполнение процедуры столько раз, сколько потребуется, до тех пор, пока очередное выполнение не завершится с ошибкой, позволит найти все устройства заданного семейства, отвечающие заданному командой критерию поиска.
Вот в общем-то и всё. Пример реализации описанного алгоритма можно посмотреть в программе для программирования микросхем памяти DS2430, исходники которой можно скачать в подразделе «полезные программы для ПК«.
STM32 + 1-wire. Поиск устройств
В этой статье хочу рассказать про поиск устройств на шине 1-wire. У новичков это вызывает неподдельный ужас, вплоть до того, что начинаются выделения отдельных ножек для каждого 1-wire устройства. Но на самом деле не так все страшно.
Для начала вспомним, как же осуществляется чтение бита данных от slave-устройств 1-wire.
Сначала мастер на определенный промежуток времени прижимает линию к земле, сообщая устройствам что пора бы уже что-то посылать. Если устройство хочет передать «1», то оно ничего не делает. А если хочет передать «0», то в определенный момент времени тянет линию к земле. В принципе, кроме как тянуть линию к земле, устройства больше ничего и не могут сделать.
Видео:64. Алгоритмы поиска 1 Wire устройств (Урок 55. Теория)Скачать
Получается, что бит «0» — доминантный. То есть, если два устройства одновременно пошлют биты «1» и «0», то мастер увидит на линии только «0». Собственно, этим и пользуются при поиске устройств.
Поиск происходит побитно. Все начинается с самого младшего бита. Мастер посылает Reset на линию, потом посылает команду с кодом 0F — Search ROM. После этой команды все устройства готовят свой первый бит идентификатора к предъявлению.
Итак, все готовы. Мастер читает с шины два бита. Все устройства посылают сначала свой первый бит, а потом комплементарный (обратный данному) бит. В чем пафос данного алгоритма? Устройство, которое посылает 1 ничем не отличается от неактивного устройства. И чтобы их как-то расшевелить, надо чтобы устройство послало 0. А чтобы при этом передать какую-то информацию, то устройство передает ноль либо при первом, либо при втором чтении. В зависимости от бита своего уникального идентификатора.
Какие могут быть варианты:
приняты биты 11 — в этом случае никакое устройство на шине не передало «0». Это означает, что либо устройств нет, либо мы где-то запутались в процессе поиска. В любом случае критическая ситуация.
Приняты биты 10 — это означает, что в едином порыве все активные устройства передали сначала «1», а потом «0», и соответствующий бит в идентификаторе у всех активных устройств «1».
Приняты биты 01 — все то же самое, что и в предыдущей ситуации, только бит «0»
А теперь самое интересное — приняты биты 00. Это означает коллизию — одновлеменно высказались устройства с битом «0» и битом «1» в соответствующем разряде. Помните про доминантный бит?
Читайте также: Технология ремонта боковых порезов легковых шин
Как же разрулить коллизию? А просто — следующим ходом мастер отсылает всем устройствам оперделенный бит. Например «1». В этом случае все устройства, у которых в текущем разряде находится «0» просто отключаются и в дальнейших выборах не участвуют. То есть количество активных устройств уменьшается. Ясное дело, что если у всех устройств установлен одинаковый бит в текущем разряде (ситуации 10 и 01), то мы именно этот бит и передаем, чтобы не поломать весь процесс.
И таким образом, когда мы пройдем все 64 бита, у нас будет выбрано одно-единственное устройство.
Видео:63. Методика поиска адресов 1 Wire устройств (Урок 54. Теория)Скачать
Теперь наша задача перебрать все устройства на шине, чтобы потом обращаться к каждому поименно.
Попробуем представить процедуру выбора в виде дерева. Для упрощения я взял четырехбитные номера и всего четыре устройства:
Для того, чтобы обойти все дерево используем следующий алгоритм:
Если ветка одна, то идем по ней (в соотвествующем разряде у всех активных устройств биты совпадают, или всего одно активное устройство)
Если веток две, то сначала идем по правой (где бит 1), и запоминаем развилку.
Как только прошли все разряды, возвращаемся к запомненной развилке и идем налево
Как только перебрали все развилки, останавливаемся.
Попробуем походить:
Reset, 0F
первый бит: от устройств дружно приходит 10 — у всех наших устройств в младшем бите установлена 1, просто идем по этой ветке
второй бит: приходит 00 — коллизия. Идем вправо (мы туде еще не ходили) и запоминаем 2
Как только мы шагнули вправо, устройства №2 и №3 выпали из дальнейшей процедуры поиска и нам не мешают.
третий бит: опять коллизия. Опять идем вправо и запоминаем развилку (бит 3). Отметим, что устройство №1 тоже выпало из поиска
четвертый бит: все устройства (у нас оно одно) рапортуют 10 — бит1.
Итого сложился идентификатор 1111. Записываем его и возвращаемся на предыдущую развилку. Но вернуться так просто нам не получится, надо начинать процесс сначала.
Вторая итерация:
Reset, 0F
первый бит: от устройств дружно приходит 10 — у всех наших устройств в младшем бите установлена 1, просто идем по этой ветке
второй бит: приходит 00 — коллизия. Идем вправо, нам надо добраться до следующего ветвления. Запоминаем 2
третий бит: поскольку мы добрались до развилки 3 и мы направо уже ходили, то идем налево
четвертый бит: опять осталось одно устройство и мы распознали устройство №1
Третья и четвертая итерация аналогично.
Видео:Опрос дискретных входов по шине 1-wire. Длина шины 300 метровСкачать
А вот, соответственно, и процедура. Все дерево if-ов написано неоптимально, а точно в соответствии с нашим алгоритмом. Оптимизированные функции поиска можно найти в аппноте от Maxim. Разобравшись, уже можно модифицировать как угодно.
тут можно заметить две переменные — lastCollision и currentColision. Первая переменная — это последняя коллизия из предыдущей итерации, в которой мы пошли направо. Она нужна для того, чтобы в текущей итерации мы пришли точно к нужной развилке и свернули налево, в еще нехоженую сторону. А currentCollision запоминает последнюю развилку в текущей итерации, на которой мы повернули направо. Чтобы в следующей итерации уже идти до нее.
- Свежие записи
- Нужно ли менять пружины при замене амортизаторов
- Скрипят амортизаторы на машине что делать
- Из чего состоит стойка амортизатора передняя
- Чем стянуть пружину амортизатора без стяжек
- Для чего нужны амортизаторы в автомобиле
📸 Видео
Лекция 309. 1-wire интерфейсСкачать
65. Программа поиска адреса 1 wire устройства (Урок 56. Теория)Скачать
Удаленное управление реле по шине 1-wire.Скачать
Программирование МК ESP32. Урок 38. RMT. 1-Wire. Поиск устройстваСкачать
66. Программа определения адресов 1 wire устройств на ассемблере (Урок 57. Теория)Скачать
Метеостанция ч.1.1. Осциллограммы с шины 1-Wire. Читаем коды.Скачать
Удаленный мониторинг переменного тока через интернет по шине 1-wire.Скачать
Протокол обмена данными 1-Wire (Microlan)Скачать
STM32. 1-WIRE. DS18B20. Температура. Measure Temp, Read ROM, Write Scratchpad and EEPROM. Set Alarm.Скачать
Лекция "Интерфейсы (часть II). I2C. 1-Wire"Скачать
Программирование МК ESP32. Урок 39. RMT. 1-Wire. Поиск устройства по известному ROM-кодуСкачать
Датчик атмосферного давления BMP180. Передача данных по шине 1-wire.Скачать
FLProg урок внеплановый#7 I2C OneWireСкачать
Arduino и 1 wire: ds2408 + ds2406Скачать