Raspberry Pi и Pi4J. Урок 5. Последовательная шина I2C/TWI

I2C или IIC (Inter-Integrated Circuit), читается «Ай-ту-Си» или «и-два-цэ» по-нашенски — последовательная шина разработана фирмой Philips Semiconductors ещё в 80-х годах прошлого века. Задумывалась, как простая 8-битная шина внутренней связи для создания управляющей электроники. Так как право на его использование стоит денег, все пользуют в свое удовольствие, называя только по другому. В Atmel его зовут TWI, но от этого ничего не меняется.

Данные передаются по двум проводам — провод данных и провод тактов. В сети есть хотя бы одно ведущее устройство (Master), которое инициализирует передачу данных и генерирует сигналы синхронизации. В сети также есть ведомые устройства (Slave), такими как гироскопы, акселерометры, датчики давления, EEPROM-память, дисплеи, которые передают данные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес, по которому ведущий и обращается к нему. Адрес устройства указывается в паспорте (datasheet). К одной шине I2C может быть подключено до 127 устройств, в том числе несколько ведущих. К шине можно подключать устройства в процессе работы, т.е. она поддерживает «горячее подключение».

Pi4J предоставляет возможность работы с последовательной шиной I2C/TWI из Java на Raspberry Pi, Banana Pi, Orange Pi, Nano Pi и Odroid. Все классы и интерфейсы для инициализации и работы с шиной находятся в пакете com.pi4j.io.i2c.*;.

Ниже представлены описания интерфейсов/классов и их методов.

Интерфейс I2CBus

Это абстракция шины I2C. Этот интерфейс позволяет шине возвращать устройство I2C.

getDevice(int)

Возвращает I2C устройство.

Параметры
address — адрес устройства I2C
Возвращает
I2C устройство
Бросает
IOException — в случае, если эта шина не может вернуть I2C устройство.

getBusNumber()

Возвращает
номер шины

close()

Закрывает шину I2C. Обычно это означает закрытие основного файла.

Бросает
IOException — в случае возникновения проблем с закрытием шины I2C.

Интерфейс I2CDevice

Это абстракция устройства I2C. Он позволяет считывать или записывать данные на устройство.

getAddress()

Возвращает адрес, для которого создан этот экземпляр.

write(byte)

Этот метод записывает один байт непосредственно на устройство I2C.

Параметры
b — байт, который будет записан
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

write(byte[], int, int)

Этот метод записывает несколько байтов непосредственно на устройство I2C из заданного буфера при заданном смещении.

Параметры
buffer — буфер данных, который должен быть записан на устройство I2C за один раз
offset — смещение в буфере
size — количество записываемых байтов
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

write(byte[])

Этот метод записывает все байты, включенные в данный буфер, непосредственно на устройство I2C.

Параметры
buffer — буфер данных, который должен быть записан на устройство I2C за один раз
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

write(int, byte)

Этот метод записывает один байт непосредственно на устройство I2C.

Параметры
b — байт, который будет записан
address — локальный адрес в устройстве I2C
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

write(int, byte[], int, int)

Этот метод записывает несколько байтов непосредственно на устройство I2C из заданного буфера при заданном смещении.

Параметры
address — локальный адрес в устройстве I2C
buffer — буфер данных, который должен быть записан на устройство I2C за один раз
offset — смещение в буфере
size — количество записываемых байтов
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

write(int, byte[])

Этот метод записывает все байты, включенные в данный буфер, непосредственно на адрес регистра на устройстве I2C

Параметры
address — локальный адрес в устройстве I2C
buffer — буфер данных, который должен быть записан на устройство I2C за один раз
Бросает
IOException — в случае, если байт не может быть записан на устройство/шину I2C.

read()

Этот метод считывает один байт с устройства I2C. Результат от 0 до 255, если операция чтения была успешной, в противном случае отрицательное число ошибки.

Возвращает
значение байта: положительное число от 0 до 255, если чтение было успешным. Отрицательное число, если чтение не удалось.
Бросает
IOException — в случае, если байты не могут быть прочитан с устройства/шины I2C.

read(byte[], int, int)

Этот метод считывает байты непосредственно из устройства I2C в заданный буфер при запрошенном смещении.

Параметры
buffer — буфер данных, который должен считываться с устройство I2C за один раз
offset — смещение в буфере
size — количество байт для чтения
Возвращает
количество прочитанных байтов
Бросает
IOException — в случае, если байт не может быть прочитан с устройства/шины I2C.

read(int)

Этот метод считывает один байт с устройства I2C.

Параметры
address — локальный адрес в устройстве I2C
Возвращает
значение байта: положительное число от 0 до 255, если чтение было успешным. Отрицательное число, если чтение не удалось.
Бросает
IOException — в случае, если байт не может быть прочитан с устройства/шины I2C.

read(int, byte[], int, int)

Этот метод считывает байты, начиная с заданного адреса в устройстве I2C в буфере при запрошенном смещении.

Параметры
address — локальный адрес в устройстве I2C
buffer — буфер данных, который должен считываться с устройство I2C за один раз
offset — смещение в буфере
size — количество байт для чтения
Возвращает
количество прочитанных байтов
Бросает
IOException — в случае, если байт не может быть прочитан с устройства/шины I2C.

read(byte[], int, int, byte[], int, int)

Этот метод записывает и считывает байты в / из устройства I2C одним вызовом метода

Параметры
writeBuffer — буфер данных, который должен быть записан на устройство I2C за один раз
writeOffset — смещение в буфере
writeSize — количество записываемых байтов
readBuffer — буфер данных, который должен считываться с устройство I2C за один раз
readOffset — смещение в буфере
readSize — количество байт для чтения
Возвращает
количество прочитанных байтов
Бросает
IOException — в случае, если байт не может быть прочитан/записан с/на устройство/шину I2C .

ioctl(…)

Запускает ioctl на этом устройстве.

Класс I2CConstants

Это константы, взяты непосредственно из ядра linux (i2c-dev.h i2c.h). Они должны использоваться с расширенным I2C ioctl.

Класс I2CFactory

I2C factory — он возвращает экземпляры интерфейса I2CBus.

getInstance(int)

Создаёт новый экземпляр I2CBus.
Тайм-аут блокировки шины для эксклюзивной связи устанавливается в DEFAULT_LOCKAQUIRE_TIMEOUT.

Параметры
busNumber — номер шины.
Возвращает
новый экземпляр I2CBus
Бросает
UnsupportedBusNumberException — если данный номер шины не поддерживается базовой системой.
IOException — если сообщение с шиной I2C не работает.

getInstance(int, long, TimeUnit)

Создаёт новый экземпляр I2CBus.

Параметры
busNumber — номер шины.
lockAquireTimeout — таймаут для блокировки шины.
lockAquireTimeoutUnit — единицы измерения для lockAquireTimeout.
Возвращает
новый экземпляр I2CBus
Бросает
UnsupportedBusNumberException — если данный номер шины не поддерживается базовой системой.
IOException — если сообщение с шиной I2C не работает.

setFactory(I2CFactoryProvider)

Позволяет изменить поставщика для фабрики.

Параметры
factoryProvider — новый поставщик.

getBusIds()

Выдаёт все доступные номера шины I2C из sysfs.

Возвращает
Возвращает найденные номера шин I2C или null
Бросает
IOException — если извлечение из интерфейса sysfs не удалась.

Интерфейс I2CFactoryProvider

I2C factory provider — он возвращает экземпляры интерфейса I2CBus.

getBus(int, long, TimeUnit)

Создаёт новый экземпляр I2CBus.

Параметры
busNumber — номер шины.
lockAquireTimeout — таймаут для блокировки шины.
lockAquireTimeoutUnit — единицы измерения для lockAquireTimeout.
Возвращает
новый экземпляр I2CBus
Бросает
UnsupportedBusNumberException — если данный номер шины не поддерживается базовой системой.
IOException — если сообщение с шиной I2Cне работает.

Подключение DS3231 к Orange Pi PC по I2C

Для проверки работоспособности я взял часы реального времени DS3231, так как они первые попались под руку, ещё с этим чипом очень легко работать.

Описание регистров DS3231

Ниже в таблице представлен перечень регистров часов реального времени:

Адрес D7 D6 D5 D4 D3 D2 D1 D0 Функция Пределы
0x00 0 10 секунд Секунды Секунды 00-59
0x01 0 10 минут Минуты Минуты 00-59
0x02 0 12/24 AM/PM 10 часов Час Часы 1-12 + AM/PM или 00-23
10 часов
0x03 0 0 0 0 0 День День недели 1-7
0x04 0 0 10 число Число Дата 01-31
0x05 Century 0 0 10 месяц Месяц Месяцы/век 01-12 + Век
0x06 10 лет Год Годы 00-99
0x07 A1M1 10 секунд Секунды Секунды, 1-й будильник 00-59
0x08 A1M2 10 минут Минуты Минуты, 1-й будильник 00-59
0x09 A1M3 12/24 AM/PM 10 часов Час Часы, 1-й будильник 1-12 + AM/PM или 00-23
10 часов
0x0A A1M4 DY/DT 10 число День День недели, 1-й будильник 1-7
Число Дата, 1-й будильник 01-31
0x0B A2M2 10 минут Минуты Минуты, 2-й будильник 00-59
0x0C A2M3 12/24 AM/PM 10 часов Час Часы, 2-й будильник 1-12 + AM/PM или 00-23
10 часов
0x0D A2M4 DY/DT 10 число День День недели, 2-й будильник 1-7
Число Дата, 2-й будильник 01-31
0x0E EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE Регистр настроек (Control)
0x0F OSF 0 0 0 EN32kHz BSY A2F A1F Регистр статуса (Status)
0x10 SIGN DATA DATA DATA DATA DATA DATA DATA Регистр подстройки частоты (Aging Offset)
0x11 SIGN DATA DATA DATA DATA DATA DATA DATA Регистр температуры, старший байт
0x12 DATA DATA 0 0 0 0 0 0 Регистр температуры, младший байт

Информация о времени хранится в двоично-десятичном формате, то есть каждый разряд десятичного числа (от 0 до 9) представляется группой из 4-х бит. В случае одного байта, младший полубайт отсчитывает единицы, старший десятки и т. д.

Схема подключения

Raspberry Pi и Pi4J. Урок 5. Последовательная шина I2C (Orange Pi One + DS3231)

Пример 1 — запись данных

I2C шина является адресной, так что каждое подключаемое устройство имеет свой адрес. Адрес устройства в шестнадцатеричной системе равен 0x68 — это 104 в десятичной. Объявляем константу:

Так как данные будут записаны только в регистры даты и времени (от 0x00 до 0x06), объявляем только их:

Поскольку мы не используем платформу Raspberry Pi, мы должны явно указывать платформу, в моём случае — это Orange Pi.

Чтобы работать с I2C устройствами, надо создать экземпляр I2CBus с помощью метода getInstance класса I2CFactory, где параметр — это номер шины.

Создаём экземпляр I2CDevice с помощью метода getDevice, где параметр — это адрес устройства. Таким образом можно создать объект для каждого подключённого устройства.

Для записи данных на устройство используем методы write.

Ниже приведён пример программы, которая устанавливает время и дату на часах. Получить время можно с помощью LocalDateTime.now();.

Проверяем код:

  1. создаём java файл и вставляем код;
  2. компилируем файл;
  3. запускаем программу.

Пример 2 — чтение данных

Для чтения данных с устройства используем методы read.

Читаем данные температуры. Текущее значение температуры хранится в регистрах с адресами 0x11 и 0x12, старший и младший байт соответственно, значение температуры в регистрах периодически обновляется. Установлено левое выравнивание, разрешение составляет 10 бит или 0,25°C/LSB, то есть в старшем байте находится целая часть температуры, а 6, 7-й биты в младшем регистры составляют дробную часть. В старшем байте 7-й бит указывает знак температуры, например, значению 00011010 01 соответствует температура +26.25 °C, значению 11111100 10 температура -4.5 °C.

Этот пример программы считывает и выводит в консоль данные даты, времени и температуры.

Проверяем код:

  1. создаём java файл и вставляем код;
  2. компилируем файл;
  3. запускаем программу.

Результат

Raspberry Pi и Pi4J. Урок 5. Последовательная шина I2C-TWI - чтение данныхКак мы видим, данные успешно получены, так что Pi4J можно использовать для работы с I2C.

Похожие записи

Комментарии 1

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *