Raspberry Pi и Pi4J. Урок 9. Работа с Аналого-Цифровым Преобразователем/АЦП ADS1115

Чтобы считать напряжение и преобразовать его к осязаемому цифровому значению используется аналого-цифровой преобразователь (AЦП). В мини-компьютерах Raspberry Pi, Banana Pi, Orange Pi, Nano Pi и др. отсутствуют встроенные АЦП, поэтому для чтения аналоговых сигналов потребуется внешний АЦП. Один из них — это Аналого-Цифровой Преобразователь/АЦП ADS1115.

ADS1115 — это 4-х канальный 16-битный аналого-цифровой преобразователь (АЦП). Преобразователь разработан для обеспечения точности, энергоэффективности, простоты в реализации, выполняет преобразование с программируемыми скоростями обработки данных. Встроенный усилитель с программируемым коэффициентом усиления (PGA), что позволяет проводить точные измерения больших и малых напряжений. ADS1115 имеет входной мультиплексор (MUX), который позволяет выполнять два дифференциальных или четыре несимметричных входных измерения.

В Pi4J есть библиотека для работы с АЦП ADS1115 по I2C/TWI из Java на Raspberry Pi, Banana Pi, Orange Pi, Nano Pi и Odroid. Все классы и интерфейсы находятся в пакете com.pi4j.gpio.extension.ads.*;.

Пока не все возможности АЦП модулей ADS1x15 реализованы, например, нельзя дифференциально измерять напряжение между входами модуля, доступно только измерение относительно земли (GND). Также не реализована возможность использования пина ALERT/READY, используя GPIO для уведомления о событиях. Это было бы более эффективно, чем постоянный опрос доступности данных.

Класс ADS1x15GpioProvider

Это абстрактный класс, что реализует общие методы аналого-цифровых преобразователей серии ADS1x15, ADS1015 и ADS1113/ADS1114/ADS1115.

ADS1x15GpioProvider(int, int)

Конструктор класса.

public ADS1x15GpioProvider(int busNumber, int address) throws UnsupportedBusNumberException, IOException

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

ADS1x15GpioProvider(I2CBus, int)

Конструктор класса.

public ADS1x15GpioProvider(I2CBus bus, int address) throws IOException

Параметры
bus — I2C шина.
address — I2C адрес устройства.
Возвращает
новый экземпляр ADS1x15GpioProvider
Бросает
IOException — если сообщение с шиной I2C не работает.

getProgrammableGainAmplifier(Pin)

Возвращает коэффициент усиления внутреннего усилителя (PGA).

public ProgrammableGainAmplifierValue getProgrammableGainAmplifier(Pin pin)

Параметры
pin — номер пина АЦП.
Возвращает
экземпляр ProgrammableGainAmplifierValue — Коэффициент усиления внутреннего усилителя (PGA).

setProgrammableGainAmplifier(ProgrammableGainAmplifierValue, Pin…)

Настройка коэффициента усиления внутреннего усилителя (PGA).

public void setProgrammableGainAmplifier(ProgrammableGainAmplifierValue pga, Pin...pin)

Параметры
pga — коэффициент усиления внутреннего усилителя (PGA).
pin — номер пина/пинов АЦП.

getEventThreshold(Pin)

Возвращает заданный пину порог события.

public double getEventThreshold(Pin pin)

Параметры
pin — номер пина АЦП.
Возвращает
порог события

setEventThreshold(double, Pin…)

Задаёт минимальное значение порога срабатывания события/й. Другими словами, событие срабатывает, если разница между предыдущим и текущим измерением больше заданного значения.

public void setEventThreshold(double threshold, Pin...pin)

Параметры
threshold — минимальное значение порога срабатывания события/й.
pin — пин АЦП.

getMonitorInterval()

Метод возвращает интервал обновления потока мониторинга (в миллисекундах).

public int getMonitorInterval()

setMonitorInterval(int)

Метод задаёт интервал обновления потока мониторинга (в миллисекундах). Это определяет скорость, с которой контрольный поток будет считывать входные значения из чипа АЦП (значение менее 50 мс не разрешено, по умолчанию — 100 мс).

public void setMonitorInterval(int monitorInterval)

Параметры
monitorInterval — интервал обновления потока мониторинга (в миллисекундах).

getImmediateValue(Pin)

Метод используется «монитором» (ADCMonitor), чтобы получить текущее напряжение с указанного пина АЦП. Напряжение измеряется между одним из входов и общим проводом (GND), а дифференциальное измерение библиотека не поддерживает.

public double getImmediateValue(Pin pin) throws IOException

Параметры
pin — пин АЦП.
Возвращает
текущее значение от АЦП.
Бросает
IOException — если сообщение с шиной I2C не работает.

ADCMonitor

Этот класс/поток используется для активного мониторинга прерываний GPIO. Монитор запускается при создании экземпляра класса ADS1x15GpioProvider.

private class ADCMonitor extends Thread {}

Класс ADS1115GpioProvider

Этот GPIO провайдер расширяет абстрактный класс ADS1x15GpioProvider и реализует интерфейс GpioProvider, для работы с пинами АЦП ADS1115, как с родными пинами Pi4J.

ADS1115GpioProvider(int, int)

Конструктор класса.

public ADS1115GpioProvider(int busNumber, int address) throws UnsupportedBusNumberException, IOException

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

ADS1115GpioProvider(I2CBus, int)

Конструктор класса.

public ADS1115GpioProvider(I2CBus bus, int address) throws IOException

Параметры
bus — I2C шина.
address — I2C адрес устройства.
Возвращает
новый экземпляр ADS1115GpioProvider
Бросает
IOException — если сообщение с шиной I2C не работает.

Класс ADS1115Pin

Класс ADS1115Pin содержит 4 экземпляра пинов АЦП ADS1115: INPUT_A0, INPUT_A1, INPUT_A2 и INPUT_A3.

createAnalogInputPin(int, String)

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

private static Pin createAnalogInputPin(int address, String name)

Параметры
address — номер пина (0-3).
name — имя пина.
Возвращает
новый экземпляр Pin

Подключение АЦП ADS1115 к Orange Pi PC

Поскольку эта библиотека не поддерживает дифференциальное измерение, я привёл только один пример, напряжение измеряется между одним из входов и общим проводом (GND).

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

Можно подключить по одному переменному резистору на каждый вход датчика, если хотите проверить все входы. АЦП ADS1115 подключён к порту номер 1, так как адрес 0x48 на порту 0 резервирован. Но можно менять адрес АЦП с помощью пина ADDR и подключить устройство на порт 0.

Схема подключения АЦП ADS1115 к Orange Pi

Пример программы

Приведённая ниже программа считывает данные с датчика и выводит результаты в терминал. Обратите внимание на следующую строку:

gpioProvider.setEventThreshold(500, ADS1115Pin.ALL);

я установил порог в 500 (макс.: ‭32767‬). Если вам нужно, чтобы событие сработало при любом изменении значений с датчика, тогда установите 0 вместо 500:

gpioProvider.setEventThreshold(0, ADS1115Pin.ALL);

Пример кода:

import java.io.IOException;
import java.text.DecimalFormat;

import com.pi4j.gpio.extension.ads.ADS1115GpioProvider;
import com.pi4j.gpio.extension.ads.ADS1115Pin;
import com.pi4j.gpio.extension.ads.ADS1x15GpioProvider.ProgrammableGainAmplifierValue;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinAnalogInput;
import com.pi4j.io.gpio.event.GpioPinAnalogValueChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerAnalog;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;

public class ADS1115Example {

  /**
   * @param args
   */
  public static void main(String[] args) {
    try {
      System.out.println("<--Pi4J--> ADS1115 GPIO Example ... started.");

      /*
       * формат чисел для вывода данных
       */
      final DecimalFormat df = new DecimalFormat("#.##");
      final DecimalFormat pdf = new DecimalFormat("###.#");
      /*
       * создаем gpio контроллер
       */
      GpioController gpio = GpioFactory.getInstance();
      /*
       * создаем пользовательский provider GPIO ADS1115
       */
      final ADS1115GpioProvider gpioProvider = new ADS1115GpioProvider(I2CBus.BUS_1, ADS1115GpioProvider.ADS1115_ADDRESS_0x48);
      /*
       * создаём аналоговые входные пины от ADS1115
       */
      GpioPinAnalogInput analogInputPin0 = gpio.provisionAnalogInputPin(gpioProvider, ADS1115Pin.INPUT_A0, "MyAnalogInput-A0");
      GpioPinAnalogInput analogInputPin1 = gpio.provisionAnalogInputPin(gpioProvider, ADS1115Pin.INPUT_A1, "MyAnalogInput-A1");
      GpioPinAnalogInput analogInputPin2 = gpio.provisionAnalogInputPin(gpioProvider, ADS1115Pin.INPUT_A2, "MyAnalogInput-A2");
      GpioPinAnalogInput analogInputPin3 = gpio.provisionAnalogInputPin(gpioProvider, ADS1115Pin.INPUT_A3, "MyAnalogInput-A3");
      /*
       * ВНИМАНИЕ !! Для всех аналоговых входных контактов важно установить PGA
       * (программируемый коэффициент усиления внутреннего усилителя). (Вы
       * можете опционально установить каждый вход на другое значение).
       * Измеренное входное напряжение никогда не должно превышать это значение!
       */
      gpioProvider.setProgrammableGainAmplifier(ProgrammableGainAmplifierValue.PGA_4_096V, ADS1115Pin.ALL);
      /*
       * Определяем пороговое значение для каждого вывода для событий изменения
       * аналогового значения. Важно установить этот порог достаточно высоким,
       * чтобы программа не захлебнулась событиями изменения для незначительных
       * изменений
       */
      gpioProvider.setEventThreshold(500, ADS1115Pin.ALL);
      /*
       * Определите интервал обновления потока мониторинга (в миллисекундах).
       * Это определяет скорость, с которой контрольный поток будет считывать
       * входные значения из чипа АЦП (значение менее 50 мс не разрешено)
       */
      gpioProvider.setMonitorInterval(300);
      /*
       * создаем слушатель изменения значения входного напряжения
       */
      GpioPinListenerAnalog listener = new GpioPinListenerAnalog() {
        @Override
        public void handleGpioPinAnalogValueChangeEvent(GpioPinAnalogValueChangeEvent event) {
          /* необработанное значение */
          double value = event.getValue();

          /* в процентах */
          double percent = ((value * 100) / ADS1115GpioProvider.ADS1115_RANGE_MAX_VALUE);

          /*
           * приблизительное напряжение (* масштабируется на основе настройки
           * PGA)
           */
          double voltage = gpioProvider.getProgrammableGainAmplifier(event.getPin()).getVoltage() * (percent / 100);

          /* выводим данные */
          System.out.println(" (" + event.getPin().getName() + ") : VOLTS=" + df.format(voltage) + "  | PERCENT=" + pdf.format(percent) + "% | RAW=" + value + "       ");
        }
      };
      analogInputPin0.addListener(listener);
      analogInputPin1.addListener(listener);
      analogInputPin2.addListener(listener);
      analogInputPin3.addListener(listener);
      /*
       * Оставляем программу работать 5 минут
       */
      Thread.sleep(5 * 60 * 1000);

      /*
       * останавливаем все действия / потоки GPIO, отключая контроллер GPIO
       * (этот метод принудительно завершает работу всех потоков мониторинга
       * GPIO и запланированных задач)
       */
      gpio.shutdown();

      System.out.println("Exiting ADS1115GpioExample");
    } catch (UnsupportedBusNumberException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

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

  1. создаём java файл и вставляем код:
    nano ADS1115Example.java
  2. компилируем файл:
    javac -classpath .:classes:/opt/pi4j/lib/'*' ADS1115Example.java
  3. запускаем программу:
    sudo java -classpath .:classes:/opt/pi4j/lib/'*' ADS1115Example

Результат

Подключение АЦП ADS1115 к Orange Pi PC - Результат

Материалы

ADS1115 — 16-битный Аналого-Цифровой Преобразователь с I2C интерфейсом. Модуль RI038
Pi4J/pi4j · GitHub
Скачать документацию Datasheet ADS1115.pdf

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

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

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