В прошлой статье мы познакомились с контроллером Kincony KC868-A8 и его схемотехникой, в этой статье мы разберём программирование его функциональных блоков (входов, реле, температурных датчиков, Ethernet интерфейса и т. д.). Примеры кода из этой статьи вы сможете использовать в своих проектах на KC868-A8.
Мне нравится и Kincony KC868-A4 и KC868-A8, но наш сегодняшний подопытный с его 8-ю цифровыми входами, 8-ю реле на борту, I2C разъёмом и Ethernet интерфейсом смотрится значительно более внушительно и так и просится в какой-нибудь проект по домашней автоматизации. Поэтому мне было интересно разобраться, что там и как устроено, и как всем этим можно управлять.
Разбор программирования KC868-A8 мы начнём с распиновки ESP32 и выяснения, что и как к нему подключено инженерами компании Kincony.
▍ Распиновка KC868-A8
Для начала давайте ознакомимся с полным списком всех функциональных блоков контроллера. Кроме ESP32 (ESP-WROOM-32) модуля, плата Kincony KC868-A8 содержит:
- 8 цифровых опторазвязанных входов («сухой контакт»);
- 2 аналоговых входа 0–5 В;
- 8 реле 10А 220В;
- 4 контакта для подключения температурных и прочих датчиков;
- Разъёмы для подключения модулей приёмника/передатчика на 433 МГц;
- Разъём I2C;
- Ethernet LAN8270A.
Здесь сразу выделяется «фишка» контроллера KC868-A8 — сетевой Ethernet интерфейс на чипе LAN8270A. Наличие этого интерфейса значительно расширяет возможности контроллера, но за это приходится расплачиваться «потерей» 9 GPIO из и без того крайне скудного их набора.
Проблему нехватки свободных пинов микроконтроллера ESP32 инженеры Kincony решили путём использования расширителей портов — в данном случае 8 цифровых входов и 8 реле подключаются к ESP32 через микросхемы PCF8574P расширителей портов с I2C интерфейсом.
Также стоит отметить появление на плате (по сравнению с младшим братом KC868-A4) I2C разъёма для подключения дополнительного оборудования — это значительно расширяет возможности по адаптации контроллера к задачам ваших конкретных проектов.
Ниже представлена распиновка контроллера KC868-A8. В ближних к контроллеру столбцах указаны обозначения линий и подключений из принципиальной схемы, а в дальних — входы и выходы функциональных блоков контроллера KC868-A8.

Здесь нужно пояснить: на данный момент контроллер Kincony KC868-A8 имеет две версии — базовую и модернизированную V1.4. Сама схема распиновки относится к базовому варианту, а изменения, внесённые в версию V1.4, выделены в виде отдельного блока. В моём распоряжении имеется версия контроллера V1.4, поэтому всё дальнейшее повествование будет относиться к ней.
Ещё пара пояснений. Звёздочками (*) на схеме обозначены соединения, которые «запроектированы» инженерами Kincony, но отсутствуют в реальности на плате (по крайней мере, в базовой версии), а загадочные обозначения «DI9» и «DI10» относятся к «цифровым входам» 9 и 10 (после 8-и опторазвязанных цифровых входов на расширителе портов) — всё это креатив (недоработки или переработки) инженеров компании Kincony.
Теперь, после разбора распиновки контроллера, можно приступать к изучению программирования функциональных блоков Kincony KC868-A8.
▍ Программная среда для KC868-A8
Программировать контроллер Kincony KC868-A8 мы будем в среде Arduino 1.8.5. Я здесь не буду останавливаться на установке поддержки ESP32 в Arduino и прочих подготовительных действиях — в интернете есть огромное количество руководств на эту тему. Для работы с контроллером Kincony KC868-A8 нам нужно выбрать вариант «NodeMCU-32S».

Здесь есть ещё один небольшой, но важный момент: в базовом варианте платы NodeMCU-32S I2C интерфейс завязан на пины 21 и 22, а в нашем контроллере Kincony KC868-A8 это пины 4 и 5. Соответственно, в файле
\hardware\espressif\esp32\variants\nodemcu-32s\pins_arduino.h
нужно поменять старое определение
static const uint8_t SDA = 21; static const uint8_t SCL = 22;
на соответствующее нашему KC868-A8
static const uint8_t SDA = 4; static const uint8_t SCL = 5;
иначе ни реле, ни цифровые входы контроллера работать не будут.
Теперь переходим непосредственно к программированию функциональных блоков KC868-A8.
▍ Программирование работы реле
Поскольку для управления работой реле используется расширитель портов на микросхеме PCF8574P, то и обращение к реле в коде отличается от стандартного. Расширитель работает по интерфейсу I2C и для работы с ним нужно установить специальную библиотеку PCF8574_library.
Чип PCF8574P обслуживания реле имеет адрес 0x24 на I2C шине и нужно соответствующим образом инициализировать объект для работы с ним. Сам код управления реле довольно прозрачен:
/* Kincony KC868-A8 Relays example */ #include "Arduino.h" #include "PCF8574.h" #define I2C_RELAYS_ADR 0x24 PCF8574 pcf(I2C_RELAYS_ADR); void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A8 Relays example...")); pcf.pinMode(P0, OUTPUT); pcf.pinMode(P1, OUTPUT); pcf.pinMode(P2, OUTPUT); pcf.pinMode(P3, OUTPUT); pcf.pinMode(P4, OUTPUT); pcf.pinMode(P5, OUTPUT); pcf.pinMode(P6, OUTPUT); pcf.pinMode(P7, OUTPUT); Serial.print("Init PCF8574... "); if (pcf.begin()){Serial.println(F("Ok"));} else {Serial.println(F("Error"));} } void loop() { pcf.digitalWrite(P0, HIGH); Serial.print(F("Relay #")); Serial.print(P0); Serial.println(F(" ON")); delay(10000); pcf.digitalWrite(P0, LOW); Serial.print(F("Relay #")); Serial.print(P0); Serial.println(F(" OFF")); delay(10000); }
И для вас не составит труда реализовать любую логику управления реле контроллера Kincony KC868-A8 на его основе. Результат вывода в Serial тестового скетча управления реле через расширитель портов PCF8574P:

▍ Цифровые входы
Контроллер Kincony KC868-A8 имеет 8 опторазвязанных цифровых входов «сухой контакт», которые подключены через I2C расширитель портов PCF8574P. Как и в случае с реле, программирование цифровых входов осуществляется при помощи библиотеки PCF8574_library.
Чип PCF8574P обслуживания цифровых входов имеет адрес 0x22 на I2C шине. Код, как и в случае с реле, тоже прост и прозрачен и не должен вызвать у вас никаких затруднений:
/* Kincony KC868-A8 Digital input example */ #include "Arduino.h" #include "PCF8574.h" #define I2C_DIGITAL_ADR 0x22 PCF8574 pcf(I2C_DIGITAL_ADR); void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A8 Digital input example...")); pcf.pinMode(P0, INPUT); pcf.pinMode(P1, INPUT); pcf.pinMode(P2, INPUT); pcf.pinMode(P3, INPUT); pcf.pinMode(P4, INPUT); pcf.pinMode(P5, INPUT); pcf.pinMode(P6, INPUT); pcf.pinMode(P7, INPUT); Serial.print("Init PCF8574... "); if (pcf.begin()){Serial.println(F("Ok"));} else {Serial.println(F("Error"));} delay(20); } void loop() { byte val1 = pcf.digitalRead(P0); byte val2 = pcf.digitalRead(P1); byte val3 = pcf.digitalRead(P2); byte val4 = pcf.digitalRead(P3); byte val5 = pcf.digitalRead(P4); byte val6 = pcf.digitalRead(P5); byte val7 = pcf.digitalRead(P6); byte val8 = pcf.digitalRead(P7); if (val1 == LOW) Serial.println("Key1 pressed"); if (val2 == LOW) Serial.println("Key2 pressed"); if (val3 == LOW) Serial.println("Key3 pressed"); if (val4 == LOW) Serial.println("Key4 pressed"); if (val5 == LOW) Serial.println("Key5 pressed"); if (val6 == LOW) Serial.println("Key6 pressed"); if (val7 == LOW) Serial.println("Key7 pressed"); if (val8 == LOW) Serial.println("Key8 pressed"); delay(300); }
Результат работы тестового скетча работы с цифровыми входами через I2C расширитель портов PCF8574P:

Всё работает чётко и предсказуемо, так как и должно работать.
▍ Аналоговые входы
Kincony KC868-A8 имеет 2 аналоговых входа для сигналов 0–5 В. С этими входами у KC868-A8 есть некоторая запутанность — в разных версиях платы они разведены по-разному. Мы будем разбирать устройство аналоговых входов для версии V1.4 в которой они подключены к GPIO34 и GPIO35 (в базовой версии это GPIO32 и GPIO33).
Код также предельно прост и сводится к вызову стандартной функции analogRead() и последующему анализу возвращаемых ей значений.
/* Kincony KC868-A8 Analog example */ #include "Arduino.h" #define ANALOG_A1 34 // IO34 (V1.4) #define ANALOG_A2 35 // IO35 (V1.4) void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A8 Analog example...")); pinMode(ANALOG_A1, INPUT); pinMode(ANALOG_A2, INPUT); } void loop() { Serial.printf("Current Reading A1 on Pin%d=%d\n", ANALOG_A1, analogRead(ANALOG_A1)); Serial.printf("Current Reading A2 on Pin%d=%d\n", ANALOG_A2, analogRead(ANALOG_A2)); delay(5000); }
▍ Датчики температуры и влажности
Со входами для датчиков у KC868-A8 тоже есть некоторая путаница — в разных версиях платы они тоже разведены по-разному. В версии V1.4 это пины 14, 13, 32, 33. К этим GPIO могут быть подключены датчики температуры, влажности или любые другие датчики, подходящий по типу подключения. Нужно только помнить, что на плате уже установлена подтяжка линий данных к напряжению питания.
Для работы с датчиками температуры DS18B20 требуются библиотеки DS18B20 и OneWire. Ниже приведён код для одного датчика DS18B20, подключённого к плате KC868-A8 на GPIO14.
/* Kincony KC868-A8 DS18B20 example */ #include <DS18B20.h> #define LOW_ALARM 30 #define HIGH_ALARM 40 DS18B20 ds(14); // 14, 13, 32, 33 (V1.4) void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A8 DS18B20 example...")); ds.doConversion(); while (ds.selectNext()) { ds.setAlarms(LOW_ALARM, HIGH_ALARM); } } void loop() { ds.doConversion(); while (ds.selectNextAlarm()) { Serial.print("Alarm Low: "); Serial.print(ds.getAlarmLow()); Serial.println(" °C"); Serial.print("Alarm High: "); Serial.print(ds.getAlarmHigh()); Serial.println(" °C"); Serial.print("Temperature: "); Serial.print(ds.getTempC()); Serial.println(" °C\n"); } delay(2000); }
В коде выставляются пороги срабатывания и, в случае выхода контролируемой температуры за определённые значения, в Serial выводится соответствующее сообщение.

Библиотека DS18B20 содержит различные примеры использования датчиков температуры DS18B20 — вы можете подобрать наиболее подходящий для вашего проекта.
▍ Приёмник/передатчик 433 МГц
Здесь мы не будем подробно останавливаться на использовании приёмника и передатчика на 433 МГц, вы можете прочитать об этом в статье о плате KC868-A4. Упомяну только, что в KC868-A8 приёмник и передатчик подключены на GPIO15 и GPIO2.
А в том случае, если вам не нужна работа с беспроводной передачей данных на 433 МГц, вы можете использовать GPIO15 и GPIO2 для подключения каких-то своих компонентов (см. схемотехнику KC868-A8 из предыдущей статьи).
▍ Ethernet LAN8270A
Контроллер Kincony KC868-A8 имеет на борту чип Ethernet интерфейса LAN8270A и возможность подключения и работы по проводной Ethernet сети. При этом ESP32 даёт возможность работы по беспроводному Wi-Fi интерфейсу. То есть у нас появляется возможность подключать наш контроллер либо по проводному Ethernet, либо по беспроводному Wi-Fi, либо и по тому и по другому интерфейсу одновременно. Это позволяет очень гибко организовать управление контроллером в различных ситуациях (например, в случае потери связи по беспроводному каналу и т. п.).
Использование Ethernet интерфейса совместно с ESP32 довольно просто. Вначале нужно указать соответствующие библиотеки:
#include <ETH.h> #include <SPI.h>
Затем тип используемой микросхемы:
#define ETH_TYPE ETH_PHY_LAN8720
Пины управления:
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT #define ETH_MDC_PIN 23 #define ETH_MDIO_PIN 18
И прочие настройки интерфейса:
#define ETH_POWER_PIN -1 #define ETH_ADDR 0 #define NRST 5
Далее идёт код тестового скетча, который инициализирует Ethernet интерфейс и производит запросы к сайту в интернете.
/* Kincony KC868-A8 Ethernet example */ #include <ETH.h> #include <SPI.h> #define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT #define ETH_POWER_PIN -1 #define ETH_TYPE ETH_PHY_LAN8720 #define ETH_ADDR 0 #define ETH_MDC_PIN 23 #define ETH_MDIO_PIN 18 #define NRST 5 static bool eth_connected = false; void WiFiEvent(WiFiEvent_t event) { switch (event) { case SYSTEM_EVENT_ETH_START: Serial.println("ETH Started"); ETH.setHostname("esp32-ethernet"); break; case SYSTEM_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; case SYSTEM_EVENT_ETH_GOT_IP: Serial.print("ETH MAC: "); Serial.print(ETH.macAddress()); Serial.print(", IPv4: "); Serial.print(ETH.localIP()); if (ETH.fullDuplex()) {Serial.print(", FULL_DUPLEX");} Serial.print(", "); Serial.print(ETH.linkSpeed()); Serial.println("Mbps"); eth_connected = true; break; case SYSTEM_EVENT_ETH_DISCONNECTED: Serial.println("ETH Disconnected"); eth_connected = false; break; case SYSTEM_EVENT_ETH_STOP: Serial.println("ETH Stopped"); eth_connected = false; break; default: break; } } // WiFiEvent( ) void testClient(const char *host, uint16_t port) { Serial.print("\nconnecting to "); Serial.println(host); WiFiClient client; if (!client.connect(host, port)) { Serial.println("connection failed"); return; } client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); while (client.connected() && !client.available()); while (client.available()) { Serial.write(client.read()); } Serial.println("closing connection\n"); client.stop(); } void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A8 Ethernet example...")); WiFi.onEvent(WiFiEvent); pinMode(NRST, OUTPUT); digitalWrite(NRST, 0); delay(200); digitalWrite(NRST, 1); delay(200); digitalWrite(NRST, 0); delay(200); digitalWrite(NRST, 1); ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); } void loop() { if (eth_connected) { testClient("baidu.com", 80); } delay(10000); }
Здесь: инициализируется отслеживание сетевых событий.
WiFi.onEvent(WiFiEvent);
Производится запуск чипа LAN8270A (что в нашем случае излишне, поскольку на KC868-A8 пин NRST вообще не подключён к ESP32).
pinMode(NRST, OUTPUT); digitalWrite(NRST, 0); delay(200); digitalWrite(NRST, 1); delay(200); digitalWrite(NRST, 0); delay(200); digitalWrite(NRST, 1);
И запускается Ethernet интерфейс с соответствующими параметрами:
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
Далее в цикле отправляются запросы к сайту в интернете:
void loop() { if (eth_connected) { testClient("baidu.com", 80); } delay(10000); }
А саму работу по отправке запросов выполняет функция testClient().
void testClient(const char *host, uint16_t port) { Serial.print("\nconnecting to "); Serial.println(host); WiFiClient client; if (!client.connect(host, port)) { Serial.println("connection failed"); return; } client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); while (client.connected() && !client.available()); while (client.available()) { Serial.write(client.read()); } Serial.println("closing connection\n"); client.stop(); }
Громоздкая структура
void WiFiEvent(WiFiEvent_t event) { switch (event) { case SYSTEM_EVENT_ETH_START: Serial.println("ETH Started"); ETH.setHostname("esp32-ethernet"); break; case SYSTEM_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; case SYSTEM_EVENT_ETH_GOT_IP: Serial.print("ETH MAC: "); Serial.print(ETH.macAddress()); Serial.print(", IPv4: "); Serial.print(ETH.localIP()); if (ETH.fullDuplex()) {Serial.print(", FULL_DUPLEX");} Serial.print(", "); Serial.print(ETH.linkSpeed()); Serial.println("Mbps"); eth_connected = true; break; case SYSTEM_EVENT_ETH_DISCONNECTED: Serial.println("ETH Disconnected"); eth_connected = false; break; case SYSTEM_EVENT_ETH_STOP: Serial.println("ETH Stopped"); eth_connected = false; break; default: break; } } // WiFiEvent( )
отвечает за анализ, интерпретацию и визуализацию сетевых Ethernet событий.
Результат работы тестового скетча контроллера Kincony KC868-A8 по Ethernet интерфейсу:

Всё работает чётко и предсказуемо: в процессе тестирования не было замечено никаких проблем с сетевой работой связки ESP32 и LAN8270A.
▍ Заключение
В этой статье мы рассмотрели примеры программирования различных функциональных блоков контроллера Kincony KC868-A8. Следующую статью мы посвятим разбору более сложных примеров работы с KC868-A8 и подробно разберём проблематику работы по двум интерфейсам — проводному Ethernet и беспроводному Wi-Fi.
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/652883/

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