День #8 адвент-календаря для мейкеров: следим за температурой!

День 8 адвент-календаря для мейкеров: следим за температурой!

Добро пожаловать на восьмой день вашего адвент-календаря «12 проектов Кодмас». Сегодня мы будем измерять температуру окружающей среды и использовать эти показания для создания интересных проектов!

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

С приходом зимы, которая с каждым днём становится всё холоднее, самое время научиться следить за температурой с помощью кода и вашего Pico!

Содержимое коробки #8

В этой коробке вы найдёте:

  • 1x Водонепроницаемый датчик температуры с разъёмами «папа»

  • 1x Резистор 4,7 кОм

  • 3x Провода «папа-папа»

Детали дня 8

Сегодняшний проект

Сегодня мы используем датчик температуры для измерения температуры воздуха в вашем доме, а затем перейдём к более интересным проектам: измерению температуры жидкости и созданию сигнализации, которая предупредит вас, когда в доме становится слишком холодно!

Датчик в вашей коробке — это специальная версия нашего популярного водонепроницаемого датчика температуры. Металлический наконечник содержит внутри сам датчик (а именно DS18B20-совместимый однопроводной (1-wire) датчик) и заключён в защитную оболочку кабеля, что позволяет погружать его в воду и другие жидкости для измерения температуры.

Мы добавили к этой версии разъёмы «папа», чтобы её было удобнее использовать с макетной платой.

Что такое 1-wire?

1-wire — это последовательный протокол связи, позволяющий устройствам общаться с контроллером…

…Хм, давайте объясним по-человечески! 1-wire позволяет специальному устройству, например нашему датчику температуры, разговаривать с контроллером, например нашим Pico, передавая ему данные для использования в программе.

Несмотря на своё название, для работы с 1-wire устройствами вам потребуется как минимум два провода, а в некоторых примерах (например, с нашим датчиком) мы используем три провода. Название связано с передачей данных: для двусторонней связи между устройствами достаточно одного провода.

Собираем схему

Мы снова будем использовать светодиоды и зуммер вместе с датчиком температуры (они отлично сочетаются с самыми разными датчиками и компонентами!), поэтому уберите схему с PIR-датчиком из предыдущего дня, оставив на главной макетной плате только светодиоды и зуммер.

Исходная схема должна выглядеть так:

Исходная схема дня 8

Теперь подключим датчик температуры к мини-макетной плате. У вашего датчика должны быть три провода: красный, жёлтый и белый (белый провод может быть чёрным в зависимости от партии).

Вставьте провода в верхний край мини-макетной платы в порядке белый-жёлтый-красный, как показано на изображении ниже:

Датчик температуры в макетной плате

Далее добавьте резистор, соединив жёлтый и красный провода так, как показано ниже:

Резистор датчика температуры установлен

Теперь нужно добавить три провода для завершения схемы и подключения датчика к нашему Pico:

  • Подключите левую ногу к синей шине GND

  • Подключите среднюю ногу к GPIO 26 (физический вывод 31)

  • Подключите правую ногу к 3,3 В на физическом выводе 36

Ваша схема должна выглядеть примерно так:

Полная схема дня 8

Задание 1: простое измерение температуры

Начнём с минимальной программы для получения одного показания температуры с датчика.

Импорт библиотек

Этот датчик требует нескольких новых импортов, которые берут на себя большую часть сложной работы: библиотека **onewire** и библиотека **ds18x20**. К счастью, они теперь встроены в MicroPython, поэтому нам не нужно ничего дополнительно скачивать.

Код для 1-wire

Мы настраиваем вывод датчика как вход, как делали раньше с другими датчиками, однако этот конкретный 1-wire датчик требует дополнительного кода для корректной работы.

Нам нужно сообщить MicroPython, что мы используем 1-wire датчик DS18B20, с помощью следующей строки в коде ниже: sensor = ds18x20.DS18X20(onewire.OneWire(SensorPin))

Также нам нужно просканировать вывод GPIO на наличие 1-wire устройств. Такие устройства, как наш датчик, имеют уникальный регистрационный номер в своей п**остоянной **п**амяти (**rom). Следующая строка в нашем коде ниже выполняет сканирование датчиков (roms), подключённых к нашему выводу: roms = sensor.scan().

Цикл for

Затем мы используем цикл **while**, содержащий цикл **for**. Мы использовали цикл **for** вчера с датчиком движения при использовании функции **range**, но на этот раз наш диапазон будет roms (количество rom, найденных при сканировании, то есть наш единственный датчик). Цикл for говорит: «для каждого rom, который я найду, сделай это».

Затем код преобразует показания температуры датчика в градусы Цельсия и выводит их, добавляя в конце символ °C. Комментарии в коде должны всё прояснить — попробуйте!

Код

# Импорты
import onewire, ds18x20, time
from machine import Pin

# Устанавливаем вывод данных для датчика
SensorPin = Pin(26, Pin.IN)

# Сообщаем MicroPython, что используем датчик DS18B20 и указываем, к какому выводу он подключён
sensor = ds18x20.DS18X20(onewire.OneWire(SensorPin))

# Ищем датчики DS18B20 (каждый содержит уникальный код rom)
roms = sensor.scan()

while True: # Запускаем бесконечно

    sensor.convert_temp() # Конвертируем единицы датчика в градусы Цельсия

    time.sleep(2) # Ждём 2 секунды (нужно подождать не менее 1 секунды перед снятием показания)

    for rom in roms: # Для каждого найденного датчика (только 1 в нашем случае)

        print((sensor.read_temp(rom)),"°C") # Выводим показание температуры с °C в конце

        time.sleep(5) # Ждём 5 секунд перед повторным запуском цикла

Задание 2: индикаторы температуры

Теперь, когда основы разобраны, используем эти показания для управления светодиодами, которые дадут нам визуальную индикацию температуры.

Пример ниже возвращает наши светодиоды и использует цикл **while** с несколькими условиями оператора **if** для управления светодиодами в зависимости от температуры: красный — если температура опускается ниже 18°C, янтарный — если она находится в комфортном диапазоне 18°C–22°C, и зелёный — если превышает 22°C.

Мы уже рассматривали циклы while, операторы if, if/elif и диапазоны в предыдущих коробках, поэтому код в этом примере должен быть вам очень знаком.

Возьмите несколько стаканов воды при разной температуре (никакого кипятка!) и попробуйте опустить водонепроницаемый конец датчика в каждый из них, наблюдая за изменением показаний и загоранием разных светодиодов. Держите Pico как можно дальше от воды… вода и электроника не лучшие друзья…

Код

# Импорты
import onewire, ds18x20, time
from machine import Pin

# Настраиваем выводы светодиодов
red = Pin(18, Pin.OUT)
amber = Pin(19, Pin.OUT)
green = Pin(20, Pin.OUT)

# Устанавливаем вывод данных для датчика
SensorPin = Pin(26, Pin.IN)

# Сообщаем MicroPython, что используем датчик DS18B20 и указываем, к какому выводу он подключён
sensor = ds18x20.DS18X20(onewire.OneWire(SensorPin))

# Ищем датчики DS18B20 (каждый содержит уникальный код rom)
roms = sensor.scan()

while True: # Запускаем бесконечно

    time.sleep(5) # Ждём 5 секунд между показаниями

    for rom in roms: # Для каждого найденного датчика (только 1 в нашем случае)

        sensor.convert_temp() # Конвертируем единицы датчика в градусы Цельсия
        time.sleep(1) # Всегда ждём 1 секунду после конвертации

        reading = sensor.read_temp(rom) # Снимаем показание температуры

        print(reading) # Выводим показание

        if reading <= 18: # Если показание меньше или равно 18

            red.value(1) # Красный ВКЛ
            amber.value(0)
            green.value(0)

        elif 18 < reading < 22: # Если показание между 18 и 22

            red.value(0)
            amber.value(1) # Янтарный ВКЛ
            green.value(0)

        elif reading >= 22: # Если показание больше или равно 22

            red.value(0)
            amber.value(0)
            green.value(1) # Зелёный ВКЛ

Задание 3: температурная сигнализация

Теперь мы можем снова добавить наш зуммер и функцию сигнализации в код, создав интересный проект температурной тревоги.

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

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

Код

Пример сигнализации ниже похож на вчерашнюю сигнализацию движения: он использует функцию сигнализации для включения светодиодов и звука зуммера, когда температура опускается ниже 18°C — измените 18 на значение, подходящее для вашего проекта или сценария.

Мы добавили как можно больше комментариев, чтобы помочь вам вспомнить, что делает каждый раздел:

# Импорты
import onewire, ds18x20, time
from machine import Pin, PWM

# Настраиваем выводы светодиодов
red = Pin(18, Pin.OUT)
amber = Pin(19, Pin.OUT)
green = Pin(20, Pin.OUT)

# Настраиваем вывод зуммера как ШИМ
buzzer = PWM(Pin(13))

# Устанавливаем коэффициент заполнения ШИМ на 0% при старте программы
buzzer.duty_u16(0)

# Устанавливаем вывод данных для датчика
SensorPin = Pin(26, Pin.IN)

# Сообщаем MicroPython, что используем датчик DS18B20 и указываем, к какому выводу он подключён
sensor = ds18x20.DS18X20(onewire.OneWire(SensorPin))

# Ищем датчики DS18B20 (каждый содержит уникальный код rom)
roms = sensor.scan()

def alarm(): # Наша функция сигнализации

    buzzer.duty_u16(10000) # Увеличиваем коэффициент заполнения зуммера (громкость)

    for i in range(5): # Запускаем 5 раз

        buzzer.freq(5000) # Высокий тон

        # Светодиоды ВКЛ
        red.value(1)
        amber.value(1)
        green.value(1)

        time.sleep(0.2) # Ждём 0,2 секунды

        buzzer.freq(1000) # Низкий тон

        # Светодиоды ВЫКЛ
        red.value(0)
        amber.value(0)
        green.value(0)

        time.sleep(0.2) # Ждём 0,2 секунды

    buzzer.duty_u16(0) # Отключаем зуммер (громкость на 0)

while True: # Запускаем бесконечно

    time.sleep(5) # Ждём 5 секунд между показаниями

    for rom in roms: # Для каждого найденного датчика (только 1 в нашем случае)

        sensor.convert_temp() # Конвертируем единицы датчика в градусы Цельсия
        time.sleep(1) # Всегда ждём 1 секунду после конвертации

        reading = sensor.read_temp(rom) # Снимаем показание температуры

        print(reading) # Выводим показание

        if reading < 18: # Если показание меньше 18

            alarm() # Вызываем функцию сигнализации

День #8 завершён!

Ещё один день, ещё один освоенный компонент! Теперь в вашем растущем арсенале деталей для создания проектов появился датчик температуры, и мы уверены, что вы будете использовать его снова и снова.

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

Так что же мы изучили в день #8? Сегодня вы:

  • Собрали схему с датчиком температуры

  • Научились использовать датчик температуры с MicroPython и Pico

  • Использовали свой первый 1-wire компонент и 1-wire библиотеку

  • Создали монитор температуры и систему температурной сигнализации

  • Узнали больше о циклах for

Как всегда, сохраните схему в безопасном месте до завтра (ничего не разбирайте пока) и до встречи завтра — нас ждёт ещё больше веселья!

Схемы подключения на макетной плате созданы с помощью Fritzing.