Шина 1-Wire служит целям, похожим на цели шины I2C (глава 7), то есть она обеспечивает возможность взаимодействий микроконтроллеров с периферийными устройствами посредством минимального количества линий передачи данных. Стандарт 1-Wire, разработанный в компании Dallas Semiconductor, свел потребность в линиях до логического минимума — всего одной. Шина имеет более низкое быстродействие, чем I2C, но обладает интересной особенностью — паразитным питанием (parasitic power), позволяющее подключать периферийные устройства к микроконтроллеру всего двумя проводами: GND (ground — земля) и комбинированным проводом питания и передачи данных.
Шина 1-Wire поддерживается более узким диапазоном устройств, чем I2C. Большинство из них производят компании Dallas Semiconductor и Maxim. К их числу относятся устройства идентификации картриджей для принтеров, флеш-память и ЭСППЗУ, а также АЦП. Однако наибольшую популярность среди устройств 1-Wire у радиолюбителей завоевал температурный датчик DS18B20 компании Dallas Semiconductor.
Аппаратная часть 1-Wire
На рис. 8.1 показано, как подключить датчик DS18B20 к плате Arduino, используя всего два контакта и режим паразитного питания DS18B20.
Рис. 8.1. Подключение устройства 1-Wire к плате Arduino
1-Wire — это именно шина, а не соединение «точка–точка». К ней можно подключить до 255 устройств, взяв за основу схему, изображенную на рис. 8.1. Если вы пожелаете использовать устройство в режиме нормального питания, то сопротивление 4,7 кОм можно убрать, а вывод Vdd датчика DS18B20 вместо GND соединить непосредственно с контактом 5 В на плате Arduino.
Протокол 1-Wire
Так же как I2C, интерфейс 1-Wire использует понятия ведущего и ведомого устройств. Микроконтроллер играет роль ведущего, а периферийные устройства — ведомых. Каждое ведомое устройство еще на заводе получает уникальный идентификационный номер, который часто называют адресом, чтобы его можно было идентифицировать на шине, к которой подключено множество ведомых. Адрес имеет размер 64 бита, что позволяет иметь примерно 1,8 × 1019 разных идентификационных номеров.
Подобно I2C, протокол 1-Wire предусматривает переключение режима работы шины ведущим устройством на ввод и вывод, чтобы иметь возможность двусторонних взаимодействий. Однако в шине 1-Wire отсутствует отдельная линия передачи тактовых сигналов, поэтому нули и единицы передаются длинными и короткими импульсами. Импульс длительностью 60 мкс обозначает 0, а длительностью 15 мкс — 1.
Обычно линия данных находится под напряжением с уровнем HIGH, но, когда микроконтроллеру (ведущему) требуется послать команду устройству, он генерирует специальный импульс сброса с уровнем LOW длительностью не менее 480 мкс. Вслед за ним следует последовательность импульсов 1 и 0.
Библиотека OneWire
Работу с интерфейсом 1-Wire здорово упрощает библиотека OneWire, которая доступна по адресу http://playground.arduino.cc/Learning/OneWire.
Инициализация 1-Wire
Чтобы инициализировать Arduino как ведущее устройство на шине 1-Wire, сначала нужно подключить библиотеку OneWire:
#include
Затем создать экземпляр OneWire и указать, какой контакт Arduino будет использоваться как линия данных на шине 1-Wire. Эти два действия можно объединить в одну команду, а в роли линии данных использовать любой контакт на плате Arduino — достаточно просто передать номер контакта в виде параметра:
OneWire bus(10);
В данном случае роль линии данных шины будет играть контакт D10.
Сканирование шины
Поскольку каждое ведомое устройство, подключенное к шине, имеет уникальный идентификационный номер, присвоенный на заводе, нужен какой-то способ определить адреса устройств, подключенных к шине. Было бы неблагоразумно «зашивать» адреса устройств в скетч, потому что в случае замены новое ведомое устройство будет иметь уже другой адрес и скетч не сможет обращаться к нему. Поэтому ведущее устройство (Arduino) должно создать своеобразную опись устройств на шине. Здесь следует отметить, что первые 8 бит в адресе определяют «семейство», которому принадлежит устройство, то есть по ним можно определить, является ли устройство, например, датчиком DS18B20 или относится к какому-то другому типу.
В табл. 8.1 перечислены некоторые из наиболее известных кодов семейств для шины 1-Wire. Полный список можно найти на странице http://owfs.sourceforge.net/family.html.
Таблица 8.1. Коды семейств устройств для шины 1-Wire
Код семейства (шестнадцатеричный) | Семейство | Описание |
---|---|---|
06 | iButton 1993 | Идентификационный ключ |
10 | DS18S20 | Высокоточный температурный датчик с разрешающей способностью 9 бит |
28 | DS18B20 | Высокоточный температурный датчик с разрешающей способностью 12 бит |
1C | DS28E04-100 | ЭСППЗУ емкостью 4 Кбайт |
В библиотеке OneWire имеется функция search, которую можно использовать для поиска всех ведомых устройств на шине. Следующий пример выводит адреса всех устройств на шине в монитор последовательного порта:
// sketch_08_01_OneWire_List
#include
OneWire bus(10);
void setup()
{
Serial.begin(9600);
byte address[8]; // 64 бита
while (bus.search(address))
{
for(int i = 0; i < 7; i++)
{
Serial.print(address[i], HEX);
Serial.print(" ");
}
// проверить контрольную сумму
if (OneWire::crc8(address, 7) == address[7])
{
Serial.println(" CRC OK");
}
else
{
Serial.println(" CRC FAIL");
}
}
}
void loop()
{
}
На рис. 8.2 показан результат выполнения этого скетча при наличии двух температурных датчиков DS18B20, подключенных к Arduino. Обратите внимание на то, что оба устройства имеют один и тот же код семейства в первом байте, равный 28 (в шестнадцатеричном формате).
Рис. 8.2. Список ведомых устройств 1-Wire
Для работы функции search требуется массив размером 8 байт, куда она могла бы поместить следующий найденный адрес. После последнего обнаруженного устройства она возвращает 0. Это позволяет выполнять итерации в цикле while, как в предыдущем примере, пока не будут определены все адреса. Последний байт адреса в действительности является циклической контрольной суммой (Cyclic Redundancy Check, CRC), позволяющей проверить целостность адреса. Библиотека OneWire включает специальную функцию для проверки контрольной суммы CRC.
Использование DS18B20
Следующий пример иллюстрирует использование библиотеки OneWire с температурным датчиком DS18B20. На рис. 8.3 изображена схема подключения DS18B20 к плате Arduino. Обратите внимание на то, что у самого датчика всего три контакта и он имеет вид обычного транзистора.
Рис. 8.3. Схема подключения DS18B20 к Arduino
Для датчика температуры компании Dallas Semiconductor имеется собственная библиотека, упрощающая операцию запроса температуры и декодирования результата. Библиотека DallasTemperature доступна для загрузки по адресу https://github.com/milesburton/Arduino-Temperature-Control-Library.
// sketch_08_02_OneWire_DS18B20
#include
#include
const int busPin = 10;
OneWire bus(busPin);
DallasTemperature sensors(&bus);
DeviceAddress sensor;
void setup()
{
Serial.begin(9600);
sensors.begin();
if (!sensors.getAddress(sensor, 0))
{
Serial.println("NO DS18B20 FOUND!");
}
}
void loop()
{
sensors.requestTemperatures();
float tempC = sensors.getTempC(sensor);
Serial.println(tempC);
delay(1000);
}
Этот скетч выводит в окно монитора последовательного порта температуру в градусах Цельсия, прочитанную с единственного датчика температуры (рис. 8.4).
Рис. 8.4. Вывод температуры, прочитанной с датчика DS18B20
В этом примере используется только один датчик температуры, но его легко можно распространить на случай с несколькими датчиками. Библиотека DallasTemperature сама определяет адреса устройств с помощью OneWire в функции getAddress, вторым параметром которой передается номер позиции датчика. Чтобы добавить второй датчик, нужно определить новую переменную для хранения его адреса и затем определить адрес вызовом getAddress. Пример с использованием двух датчиков можно загрузить с сайта книги, где он хранится под именем sketch_08_03_OneWire_DS18B20_2.
В заключение
В этой главе вы познакомились с шиной 1-Wire и узнали, как использовать ее для подключения популярного температурного датчика DS18B20.
В следующей главе мы исследуем еще одну разновидность последовательного интерфейса с названием SPI.