В мире встраиваемых систем часто возникает задача: собрать данные о температуре из множества точек, но при этом свести к минимуму количество проводов в жгуте. Решение есть — это фирменный интерфейс SMAART Wire™ от Texas Instruments и семейство цифровых датчиков TMP107TMP107-Q1.

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

1. Интерфейс SMAART Wire™: Один провод для всего

SMAART Wire™ — это фирменный последовательный протокол связи от Texas Instruments. По своей сути это полудуплексный UART, работающий по одному проводу. Это означает, что данные передаются в обе стороны, но не одновременно, и для этого используется всего одна сигнальная линия.

1.1 Ключевые особенности:

  • Топология «Daisy-Chain» (последовательная цепь): датчики подключаются друг за другом, как в гирлянде.

  • Масштабируемость: Поддерживает до 32 устройств в одной цепи.

  • Дальность: Сигнал надежно передается на расстояние до 300 метров.

  • Автонастройка скорости (Auto-Baud): Датчик автоматически определяет скорость обмена, что упрощает настройку.

1.2 Физический уровень: всего три провода

Вся магия работает благодаря тому, что между устройствами нужны всего три проводникаDATAVCC и GND.

Для обеспечения надежной работы на больших расстояниях Texas Instruments рекомендует простую, но эффективную схему обвязки:

  • Подтягивающий резистор (4.7 кОм): поднимает линию до логической «1», когда ни одно устройство не передает данные.

  • Резистор 100 Ом: защищает вход RX от повреждений при выбросах напряжения.

  • Резистор 10 Ом: сглаживает фронты сигналов, улучшая целостность данных.

2. Датчики семейства TMP107

Texas Instruments предлагает два основных варианта: TMP107 и его автомобильную версию TMP107-Q1. Оба датчика обладают внушительными характеристиками:

  • Высокая точность: без калибровки достигают ±0.4°C в диапазоне от -20°C до +70°C.

  • Высокое разрешение: 14 бит, что дает шаг в 0.015625°C.

  • Широкий диапазон: работают от -55°C до +125°C.

  • Широкий диапазон питания: от 1.7 В до 5.5 В.

3. Топология Daisy-Chain: Как это работает

В топологии «Daisy-Chain» (последовательная цепь) каждый датчик имеет два порта ввода-вывода (I/O1 и I/O2). Сигнал от хоста (вашего микроконтроллера) проходит через первый датчик, который ретранслирует его дальше, и так до конца цепи.

Главное преимущество такого подхода — автоматическое назначение адресов. Каждому датчику присваивается уникальный 5-битный адрес, который зависит исключительно от его физического положения в цепи.

4. Адресация и EEPROM: Сердце системы

4.1 Структура памяти

Каждый датчик TMP107 оснащен встроенной EEPROM, которая используется для нескольких целей:

  1. <p ">Хранение настроек: конфигурация, верхние и нижние температурные пороги (Trip Level Programming).
  2. Уникальная адресация: здесь хранится тот самый 5-битный адрес, о котором мы говорили.

  3. Пользовательское хранилище8 ячеек по 16 бит (всего 16 байт) полностью в вашем распоряжении. Вы можете хранить там что угодно: серийный номер, калибровочные коэффициенты, пользовательские настройки.

4.2 Важный нюанс: Где же адрес?

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

4.3 Запись в пользовательскую EEPROM

Чтобы записать данные в доступные вам 8 ячеек (адреса 0x060x0D), нужно выполнить специальную процедуру:

  1. Разблокировать EEPROM для записи, установив бит NUS (бит 0 в регистре температуры) в 1.

  2. Записать нужные данные.

  3. Заблокировать EEPROM обратно, записав в NUS 0. Это защитит память от случайных повреждений.

5. Процедура инициализации адресов

Это ключевой момент в настройке системы. Процедура инициализации — это "перепись населения" в вашей цепи датчиков.

5.1 Как это происходит

  1. Хост (Arduino) отправляет калибровочный байт 0x55 для определения скорости.

  2. Затем отправляется команда Address Initialize (байт 0x95).

  3. Далее следует байт, который назначает адрес первому устройству (например, 0x85 для адреса 8).

  4. Хост "отпускает" шину и ждет ответа. Каждый датчик по очереди отвечает своим новым 5-битным адресом.

5.2 Когда нужно запускать инициализацию?

  • При первой сборке: это обязательный шаг для присвоения адресов.

  • После замены датчика: новый датчик имеет заводской адрес 0h, что нарушит уникальность адресов в цепи.

  • После изменения порядка датчиков: их адреса должны соответствовать новому положению в цепи.

5.3 Важное предостережение

Инициализацию не нужно запускать при каждом включении питания! Адреса сохраняются в EEPROM и загружаются при каждом сбросе. EEPROM имеет ограниченный ресурс циклов записи, поэтому частая переинициализация может привести к преждевременному износу датчиков.

6. Практика: Arduino и библиотека SmaartWire

Для работы с датчиками TMP107 в среде Arduino существует готовая библиотека SmaartWire от разработчика Jan Gromeš.

6.1 Базовый код для работы с 15 датчиками

// ============================================================
// Базовый код для работы с 15 датчиками TMP107
// ============================================================

#define NUMBER_OF_SENSORS  15          // Количество датчиков
#define DATA_PIN           4           // Пин для линии DATA

#include <SmaartWire.h>

// Создаём объект
SmaartWire smaartWire(DATA_PIN);
byte sensorAddresses[NUMBER_OF_SENSORS];

// ------------------------------------------------------------
// Инициализация адресов
// ------------------------------------------------------------
void initSensorAddresses() {
    Serial.println("Инициализация адресов...");
    
    // 1. Калибровочная фаза
    smaartWire.write(0x55); // Калибровочный байт[reference:48]
    // 2. Команда Address Initialize
    smaartWire.write(0x95); // Команда инициализации[reference:49]
    smaartWire.write(0x0D); // Address Assign
    
    // 3. Чтение назначенных адресов
    for (int i = 0; i < NUMBER_OF_SENSORS; i++) {
        // Адрес хранится в битах [7:3]
        sensorAddresses[i] = (smaartWire.read() & 0b11111000) >> 3;
    }
    
    delay(1250);
    
    // Вывод адресов
    for (int i = 0; i < NUMBER_OF_SENSORS; i++) {
        Serial.print("Датчик ");
        Serial.print(i);
        Serial.print(" -> адрес: 0x");
        Serial.println(sensorAddresses[i], HEX);
    }
}

// ------------------------------------------------------------
// Чтение температуры
// ------------------------------------------------------------
float readTemperature(byte address) {
    // Калибровочная фаза
    smaartWire.write(0x55);
    // Команда индивидуального чтения
    smaartWire.write(0x02 | (address << 3)); // Individual Read[reference:50]
    // Указатель на регистр температуры (0x00)
    smaartWire.write(0x00 | 0xA0);
    
    // Чтение двух байтов
    byte lsb = smaartWire.read();
    byte msb = smaartWire.read();
    
    // Преобразование 14-битного значения
    int raw = (msb << 6) | (lsb >> 2);
    // Если отрицательная температура (бит 13 = 1)
    if (msb & 0x80) {
        raw = ~((msb << 6) | (lsb >> 2)) + 1;
        raw &= 0x3FFF;
        return (float)raw * -0.015625;
    } else {
        return (float)raw * 0.015625;
    }
}

// ------------------------------------------------------------
// setup()
// ------------------------------------------------------------
void setup() {
    Serial.begin(9600);
    smaartWire.begin(9600);
    
    // Инициализация адресов (выполняется один раз!)
    initSensorAddresses();
}

// ------------------------------------------------------------
// loop()
// ------------------------------------------------------------
void loop() {
    for (int i = 0; i < NUMBER_OF_SENSORS; i++) {
        float temp = readTemperature(sensorAddresses[i]);
        Serial.print("Датчик ");
        Serial.print(i);
        Serial.print(": ");
        Serial.print(temp, 2);
        Serial.println("°C");
    }
    Serial.println("---");
    delay(1000);
}

6.2 Улучшенный подход: инициализация по команде

Чтобы не изнашивать EEPROM датчиков, лучше выполнять инициализацию только по необходимости. Для этого можно добавить проверку флага в EEPROM самого Arduino:

cpp
#include <EEPROM.h>
#define EEPROM_INIT_FLAG_ADDR 0

bool isAddressesInitialized() {
    return EEPROM.read(EEPROM_INIT_FLAG_ADDR) == 0xAA;
}

void setAddressesInitialized() {
    EEPROM.write(EEPROM_INIT_FLAG_ADDR, 0xAA);
}

void setup() {
    // ...
    if (!isAddressesInitialized()) {
        initSensorAddresses();
        setAddressesInitialized();
    }
    // ...
}

7. Заключение

Интерфейс SMAART Wire™ и датчики TMP107 — это мощное и гибкое решение для построения распределенных систем сбора температуры. Возможность подключить до 32 датчиков по трем проводам на расстояние до 300 метров, автоматическая адресация и наличие пользовательской EEPROM делают эту технологию идеальной для промышленной автоматизации, систем климат-контроля и многих других применений.