# Умная розетка ![](/assets/images/iot/08/smart_socket.png) Иногда нужно дистанционно контролировать розетку, например чтобы включить чайник к вашему приходу домой. Это просто! Можно использовать реле для этой цели. ![](/assets/images/iot/08/relay.png) Но сеть переменного тока 220&nbsp;В опасна для человека, и мы не будем работать с сетью 220&nbsp;В в этом курсе. Мы даже не будем использовать реле, так как управлять реле из программы точно так же как и светодиодом! Да и просто розетка, управляемая через интернет или с мобильного приложения - это всего лишь розетка, и ничего умного в ней нет. В любом случае, мы собираемся построить ***умную*** розетку. Мы будем управлять встроенным светодиодом, включая нашу розетку на некоторый период времени, а затем отключая. Время в секундах, оставшееся до отключения будет показываться на светодиодном индикаторе. ![](/assets/images/iot/08/7segmend_2digit_74hc595.png) Это светодиодный модуль, построенный на основе сдвиговых регистров 74HC595. ![](/assets/images/iot/08/shift_register.jpg) Сдвиговый решистр — очень распространенное устройство, которое часто применяется для упрощения работы со светодиодными индикаторами, с линейками и с матрицами светодиодов. Все эти устройства состоят из множества светодиодов, и если управлять ими напрямую, потребуется занять много выводов контроллера. Регистр называется сдвиговым, потому что при добавлении каждого нового бита в него, мы как бы сдвигаем все остальные в сторону. * Q0-Q7 — выходы каждой из 8 ячеек; * VCC — питание микросхемы, 5В; * GND — земля; * DS — линия данных; * ST_CP — линия синхроимпульса для передачи данных из внутренних ячеек, во внешние; * SH_CP — линия синхроимпульса для передачи данных из DS во внутренние ячейки; * OE — инверсный, разрешение на вывод данных с внешних ячеек; * Q7′ — выход регистра, который необходимо соединить с DS следующего регистра для создания цепочки. У регистра есть один вход данных и два входа синхронизации. Синхроимпульс SH_CP запоминает текущее состояние входа данных DS. Другими словами, если на DS в момент синхронизации был высокий уровень HIGH, то в первой ячейке регистра сохранится 1. В противном случае, сохранится 0. Но надо отметить, что на самом деле сдвиговый регистр 74HC595 содержит не 8, а целых 16 ячеек памяти! Первые 8 ячеек заполняются последовательно, а вот другие 8 носят особую функцию. Второй слой ячеек соединяется непосредственно с выходами Q0-Q7, и чтобы переместить бит из первого слоя во второй, нам потребуется второй синхроимпульс ST_CP. Это может немного путать, но зато такой двухслойный регистр дает нам очень полезную возможность. Мы можем неторопливо заполнять ячейки первого слоя памяти, при этом на выходе регистра всё еще будут старые значения. После того, как мы заполним весь регистр, просто отправим на ST_CP импульс, и выходы регистра одновременно обновятся. Теперь подробнее про алгоритм работы с синхроимпульсами. Вот так выглядит временная диаграмма регистра 74HC595: ![](/assets/images/iot/08/shift_register_timing.jpg) Необходимо отметить, что порядок следования импульсов очень важен. Сначала мы устанавливаем на выводе DS нужный уровень сигнала, и только потом делаем импульс на SH_CP. ### Схема подключения Схема подключения индикатора - весьма проста ![](/assets/images/iot/08/socket.svg) | WeMos D1 | Индикатор | |----------|-----------| | 3V3 | VCC | | GND | GND | | D8 | SDI | | D7 | SCLK | | D6 | LOAD | ### Пример программы ```c // Подключение к контроллеру #define LATCH D6 // LOAD на индикаторе #define SCLK D7 #define SDI D8 long delayMS = 1000; // Задержка в мс = период изменения счета long lastTmrUpd = 0; // Время последнего обновления значения индикатора в мс int tmrDefValue = 99; // Значение с которого начинается обратный отсчет int tmrValue; // Текущее показание таймера // Набор цифр и знаков unsigned char Num[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF}; unsigned char Seg[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; void setup() { pinMode(LATCH, OUTPUT); pinMode(SCLK, OUTPUT); pinMode(SDI, OUTPUT); // Устанавливаем значение таймера по умолчанию tmrValue = tmrDefValue; } void loop() { long now = millis(); // Сравниваем текущее время с моментом последнего обновления таймера, если пора - обновляем его значение if (now - lastTmrUpd > delayMS) { if (--tmrValue < 0) tmrValue = tmrDefValue; // Разрешаем последовательную передачу digitalWrite(LATCH, LOW); // Передаем младший разряд (единицы секунд) shiftOut(SDI, SCLK, MSBFIRST, Num[tmrValue%10]); // Передаем старший разряд (десятки секунд) shiftOut(SDI, SCLK, MSBFIRST, Num[tmrValue/10]); // Запрещаем последовательную передачу digitalWrite(LATCH, HIGH); // Обновляем время последнего обновления lastTmrUpd = now; } } ``` ### Готовое устройство ![](/assets/images/iot/08/socket.jpg) ## Задача 1. Дополните программу управлением встроенным светодиодом (**BUILTIN_LED**) - светодиод должен гореть, пока идет отсчет времени. 2. Устройство должно подписаться на топик **itschool/smart_socket/ctrl** для приема числа секунд, на которое нужно включить розетку. Значение 0 - отключение. 3. Публиковать в топик **itschool/smart_socket/end_time** время, через которое произойдет отключение. 4. *Предусмотреть индикацию (например, символами 'Er'), если полученное в топике **itschool/smart_socket/ctrl** число лежит вне диапазона 0...99.* [к списку задач](iot/summer/tasks)