
Продолжаем ультимативный гайд по контроллеру Kincony KC868-A4, начатый в предыдущей статье. Сегодня мы подробно разберём распиновку KC868-A4 и познакомимся с принципами программирования компонентов (функциональных блоков) этого контроллера. Все примеры будут сопровождаться готовым рабочим кодом, который вы можете использовать в своих проектах.
Начнём мы с распиновки центрального модуля ESP32-S и разбора того, что и как подключено к нему инженерами компании Kincony.
▍ Распиновка KC868-A4
Микроконтроллер ESP32 всем хорош, но есть у него один врождённый недостаток — крайне малое число свободных GPIO контактов. И каждый, кто хочет спроектировать контроллер на ESP32 или хотя бы просто применить его в своём более-менее развитом проекте, вынужден каким-то образом решать эту проблему.
Приходится либо применять расширители портов, либо пытаться как-то «вместить невмещаемое» и пытаться по крохам распределять имеющиеся GPIO и отказываться от тех или иных компонентов, которые могли бы быть установлены на плату.
Инженеры компании Kincony так и сделали — постарались подобрать набор из, на их взгляд, наиболее востребованных компонентов (функциональных блоков), куда вошли:
- 4 цифровых входа
- 4 аналоговых входа
- 2 аналоговых выхода
- 4 реле
- Датчик(и) температуры/влажности
- Интерфейс RS232
- Модули (R/T) 433 МГц
- Инфракрасные (IR) модули (R/T)
- Пищалка (buzzer)
Этот набор забрал все свободные GPIO контроллера ESP32, больше не осталось ни одного контакта, к которому вы могли бы подключить что-то своё. Например, индикатор, который не помешал бы любому контроллеру.
Но глядя на то, что инженеры Kincony установили на плату KC868-A4, можно сказать, что у них получилось довольно сбалансированное решение для небольших проектов и целей обучения программированию микроконтроллеров.
Проблема заключается в том, что если вы захотите подключить какую-то свою деталь или модуль к KC868-A4, то без паяльника и соответствующей квалификации у вас ничего не получится — свободных для подключения GPIO просто нет.
С другой стороны, идеология подобных контроллеров и не предусматривает подобных вольностей со стороны пользователей — вы покупаете готовое решение и просто используете тот набор возможностей, которое оно предоставляет.
Итак, ниже представлено сочинение инженеров компании Kincony на тему «Как я распределил GPIO контакты ESP32», записанное мной в виде таблицы. В ближних к контроллеру столбцах указаны обозначения линий и подключений из принципиальной схемы (см. предыдущую статью), а в дальних — входы и выходы функциональных блоков контроллера KC868-A4.

В целом неплохо, основным достоинством такого расклада GPIO я бы назвал то, что всё это реально работает и не мешает друг другу.
Если бы проектированием Kincony KC868-A4 занимался я, то я бы в первую очередь избавился от подключения беспроводных модулей на 433 МГц, как архаичного, в пользу чего-нибудь более современного, типа nRF24 или LoRa, вывел бы контакты для подключения оборудования по I2C и SPI и повесил бы цифровые входы/выходы на расширители портов. А также добавил бы блок часов реального времени и вывел блок реле в отдельный модуль на DIN-рейку. Но тогда это был бы уже совсем другой контроллер, поэтому давайте спустимся с небес на землю и продолжим разбор Kincony KC868-A4.
С распределением GPIO контактов ESP32 всё более-менее понятно и теперь, вооружившись этой информацией, давайте приступим к собственно программированию отдельных функциональных блоков Kincony KC868-A4 и начнём мы с программной среды.
▍ Программная среда для KC868-A4
Программировать контроллер Kincony KC868-A4 можно в любой подходящей для этого среде — вы можете использовать для этого вашу любимую IDE, я же буду приводить примеры для среды Arduino 1.8.5. При этом предполагается, что вы обладаете необходимой квалификацией и знакомы с работой в Arduino IDE и умеете программировать микроконтроллер ESP32.
Для работы с Kincony KC868-A4, из всего списка поддерживаемых контроллеров вам нужно выбрать вариант «NodeMCU-32S». Это прозрачно намекает на то, что Kincony KC868-A4 является расширенной и дополненной различной периферией версией NodeMCU-32S.

Остальные настройки видны на скриншоте, вам нужно выставить у себя такие же (кроме номера порта, который у вас будет своим). Теперь переходим к разбору примеров программирования функциональных блоков контроллера Kincony KC868-A4.
▍ Программируем реле KC868-A4
Начнём мы конечно с управления реле, как с самого простого и востребованного функционала подобных контроллеров. Реле, как это видно на вышеприведённой схеме распиновки, подключены к GPIO 2, 15, 5, 4. Для примера управления реле контроллера Kincony KC868-A4 создадим скетч, который по очереди переключает реле, создавая эффект «бегущего огня».
/* Kincony KC868-A4 Relays example */ byte pins[] = {2, 15, 5, 4}; byte pos = 0; void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 Relays example...")); pinMode(pins[0], OUTPUT); pinMode(pins[1], OUTPUT); pinMode(pins[2], OUTPUT); pinMode(pins[3], OUTPUT); } void clear() { digitalWrite(pins[0], LOW); digitalWrite(pins[1], LOW); digitalWrite(pins[2], LOW); digitalWrite(pins[3], LOW); } void change(byte n) { clear(); digitalWrite(pins[n], HIGH); } void loop() { change(pos); Serial.print(F("ON Relay #")); Serial.println(pos); delay(10000); pos++; if (pos > 3) {pos = 0;} }
Этого примера вполне достаточно, чтобы вы на его основе могли реализовать любую логику управления реле контроллера Kincony KC868-A4. Вот результат вывода в Serial нашего тестового скетча:

▍ Buzzer и Tone
Как я уже отметил ранее, плата Kincony KC868-A4 снабжена приятным дополнением в виде пьезоэлектрического излучателя. Он может помочь вам сделать удобное звуковое оповещение о различных состояниях (авария, какие-то события и т. д.) контроллера. Вот простой пример работы с пищалкой.
/* Kincony KC868-A4 Buzzer example */ #define BUZZER_PIN 18 void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 Buzzer example...")); pinMode(BUZZER_PIN, OUTPUT); } void loop() { digitalWrite(BUZZER_PIN, HIGH); delay(500); digitalWrite(BUZZER_PIN, LOW); delay(500); }
Вышеприведённого примера достаточно для простого привлечения внимания к контроллеру при возникновении какого-либо события, но если использовать тоновую окраску звучания, то можно выделить каждый тип события своим отдельным звуком (мелодией). Вот пример использования различных тонов при оповещении.
/* Kincony KC868-A4 Buzzer Tone example */ #define BUZZER_PIN 18 const int TONE_PWM_CHANNEL = 0; void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 Buzzer Tone example...")); ledcAttachPin(BUZZER_PIN, TONE_PWM_CHANNEL); } void loop() { ledcWriteNote(TONE_PWM_CHANNEL, NOTE_C, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_D, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_E, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_F, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_G, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_A, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_B, 4); delay(500); ledcWriteNote(TONE_PWM_CHANNEL, NOTE_C, 5); delay(500); }
▍ DAC
Kincony KC868-A4 снабжён двумя цифро-аналоговыми преобразователями (DAC), которые могут формировать напряжение в диапазоне от 0 до 10 вольт. Это может пригодиться для управления различным оборудованием. Ниже приведён пример генерации постоянного напряжения 5 вольт на выходе DAC1 контроллера.
/* Kincony KC868-A4 DAC example */ #define DAC1 26 #define DAC2 25 void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 DAC example...")); int value = 127; // 255 = 10V dacWrite(DAC1, value); } void loop() { }
Понятно, что генерация постоянного напряжения — это только небольшая область применения DAC, в основном востребована динамическая генерация (периодических) сигналов. Далее вы можете видеть пример кода для генерации пилообразного сигнала на выходе DAC1.
/* Kincony KC868-A4 DAC Saw example */ #define DAC1 26 #define DAC2 25 byte value = 0; void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 DAC Saw example...")); } void saw() { value++; } void loop() { dacWrite(DAC1, value); saw(); }
Небольшой модификацией этого кода вы можете добиться генерации сигналов контроллером Kincony KC868-A4 практически любой формы.

▍ Цифровые входы
Контроллер Kincony KC868-A4 имеет 4 опторазвязанных цифровых входа «сухой контакт», которые подключены на GPIO 36, 39, 27 и 14. Обслуживание этих входов предельно просто и осуществляется практически одной функцией digitalRead() — вы получаете текущее состояние любого из входов контроллера и далее используете его в коде по своему усмотрению.
/* Kincony KC868-A4 Digital Input example */ #define INPUT_PIN1 36 #define INPUT_PIN2 39 #define INPUT_PIN3 27 #define INPUT_PIN4 14 void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 Digital Input example...")); pinMode(INPUT_PIN1, INPUT); } void loop() { Serial.println(digitalRead(INPUT_PIN1)); delay(10); }
▍ Аналоговые входы
Kincony KC868-A4 имеет 4 «аналоговых» входа, которые подключены на GPIO 32, 33, 34 и 35. Как уже было отмечено в первой статье, формированием уровней для сигналов 0–5 В и 4-20 мА занимаются входные каскады, которые формируют 2 входа для напряжения (GPIO 32 и 33) и 2 входа для тока (GPI 34 и 35). В коде работа с обоими типами входных сигналов не различается, она осуществляется функцией analogRead() с разрешением 4096.
/* Kincony KC868-A4 Analog Input example */ #define ANALOG_PIN1 32 // INA1 0-5V #define ANALOG_PIN2 33 // INA2 0-5V #define ANALOG_PIN3 34 // INA3 4-20 mA #define ANALOG_PIN4 35 // INA4 4-20 mA int value1 = 0; void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 Analog Input example...")); pinMode(ANALOG_PIN1, INPUT); } void loop() { value1 = analogRead(ANALOG_PIN1); // 0-4096 delay(1000); Serial.printf("Value on pin %d = %d\n", ANALOG_PIN1, value1); }
▍ Датчики температуры и влажности
Kincony KC868-A4 имеет колодку 3V, S, GND для подключения датчика температуры DS18B20. К этой колодке можно также подключить сеть из нескольких датчиков DS18B20, датчик влажности или любой другой датчик, подходящий по типу подключения. Нужно только помни��ь, что на плате уже установлена подтяжка линии данных к напряжению питания.
Для работы с датчиками температуры DS18B20 требуются библиотеки DS18B20 и OneWire. Ниже приведён код для одного датчика DS18B20, подключённого к плате KC868-A4.
/* Kincony KC868-A4 DS18B20 example */ #include <DS18B20.h> #define LOW_ALARM 30 #define HIGH_ALARM 40 DS18B20 ds(13); void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 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 МГц
Как вы уже знаете, в состав контроллера Kincony KC868-A4 входят модули приёмника и передатчика на 433 МГц. Эти модули могут быть использованы для управления различной техникой и приёма данных с датчиков, использующих диапазон 433 МГц для передачи своих сигналов.
Приёмник подключен на GPIO 19 контроллера, а передатчик на GPIO 21. Для работы с беспроводной передачей и приёмом данных используется популярная библиотека RC-Switch. Вот пример посылки данных и управляющих команд беспроводным модулем на 433 МГц контроллера Kincony KC868-A4.
/* Kincony KC868-A4 433 Transmit example */ #include <RCSwitch.h> RCSwitch mySwitch = RCSwitch(); #define DELAY_MS 500 void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 433 Transmit example...")); mySwitch.enableTransmit(digitalPinToInterrupt(21)); } void loop() { mySwitch.switchOn ("11111", "00010"); delay(DELAY_MS); mySwitch.switchOff("11111", "00010"); delay(DELAY_MS); mySwitch.send(5393, 24); delay(DELAY_MS); mySwitch.send("000000000001010100010001"); delay(DELAY_MS); mySwitch.sendTriState("00000FFF0F0F"); delay(DELAY_MS); }
Наглядная визуализация работы этого скетча в программе SDRSharp. Видны посылки в эфир данных контроллером каждые 500 миллисекунд.

Аналогичным образом вы можете использовать примеры приёма (GPIO 19) сигналов в диапазоне 433 МГц, идущие в составе библиотеки RC-Switch.
▍ Инфракрасные (IR) приёмник и передатчик
Завершим мы обзор программных модулей Kincony KC868-A4 примером работы с приёмником (GPIO 23, IRD) и излучателем (GPIO 22, IRS) инфракрасных сигналов. Используя эти приёмник и передатчик, вы можете организовать управление любой техникой, которая использует инфракрасные пульты для своей работы. Вы можете как записывать коды от ваших пультов управления, так и выдавать их (коды) в эфир для управления вашим оборудованием.
Для работы с инфракрасными приёмником и передатчиком используется библиотека Arduino-IRremote. Рассмотрим пример, созданный на её основе. В этом тестовом скетче мы будем принимать инфракрасный сигнал от бытового пульта управления, идентифицировать этот сигнал (производителя оборудования, частоту сигнала, протокол управления, и код нажатой клавиши), а также посылать в эфир записанный сигнал, нажимая на функциональную клавишу контроллера Kincony KC868-A4.
Исходные данные:
- IR приёмник: GPIO 23
- IR излучатель: GPIO 22
- Функциональная кнопка: GPIO 0
- STATUS_PIN используется в скетче для индикации событий, но поскольку в Kincony KC868-A4 задействованы практически все GPIO ESP32 (и также занят GPIO2), то встроенный светодиод (D2) переопределён на (условно) свободный пин D12.
Полный код скетча содержит 2 файла: основной (ir_example.ino) и файл с настройками (PinDefinitionsAndMore.h). В файле PinDefinitionsAndMore.h нужно изменить номера GPIO в соответствии с распиновкой контроллера Kincony KC868-A4 (строки с настройками помечены тремя восклицательными знаками).
#define LED_BUILTIN 12 // !!! #define IR_RECEIVE_PIN 23 // !!! #define IR_SEND_PIN 22 // !!! #define APPLICATION_PIN 0 // !!!
Полный код файла PinDefinitionsAndMore.h
/* * PinDefinitionsAndMore.h * * Contains pin definitions for IRremote examples for various platforms * as well as definitions for feedback LED and tone() and includes * * Copyright (C) 2021 Armin Joachimsmeyer * armin.joachimsmeyer@gmail.com * * This file is part of IRremote https://github.com/Arduino-IRremote/Arduino-IRremote. * * Arduino-IRremote is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>. * */ /* * Pin mapping table for different platforms * * Platform IR input IR output Tone * ----------------------------------------- * DEFAULT/AVR 2 3 4 * ATtinyX5 0 4 3 * ATtiny167 9 8 5 // Digispark pro number schema * ATtiny167 3 2 7 * ATtiny3217 10 11 3 // TinyCore schema * ATtiny1604 2 PA5/3 % * SAMD21 3 4 5 * ESP8266 14 // D5 12 // D6 % * ESP32 15 4 27 * BluePill PA6 PA7 PA3 * APOLLO3 11 12 5 */ #define LED_BUILTIN 12 // !!! //#define _IR_MEASURE_TIMING // For debugging purposes. // #if defined(ESP8266) #define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D4) is active LOW #define IR_RECEIVE_PIN 14 // D5 #define IR_RECEIVE_PIN_STRING "D5" #define IR_SEND_PIN 12 // D6 - D4/pin 2 is internal LED #define IR_SEND_PIN_STRING "D6" #define _IR_TIMING_TEST_PIN 13 // D7 #define APPLICATION_PIN 0 // D3 #define tone(...) void() // tone() inhibits receive timer #define noTone(a) void() #define TONE_PIN 42 // Dummy for examples using it #elif defined(ESP32) #include <Arduino.h> #define TONE_LEDC_CHANNEL 1 // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. void tone(uint8_t _pin, unsigned int frequency){ ledcAttachPin(_pin, TONE_LEDC_CHANNEL); ledcWriteTone(TONE_LEDC_CHANNEL, frequency); } void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ ledcAttachPin(_pin, TONE_LEDC_CHANNEL); ledcWriteTone(TONE_LEDC_CHANNEL, frequency); delay(duration); ledcWriteTone(TONE_LEDC_CHANNEL, 0); } void noTone(uint8_t _pin){ ledcWriteTone(TONE_LEDC_CHANNEL, 0); } #define IR_RECEIVE_PIN 23 // !!! #define IR_SEND_PIN 22 // !!! #define TONE_PIN 27 // D27 25 & 26 are DAC0 and 1 #define APPLICATION_PIN 0 // !!! #elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) // BluePill in 2 flavors // Timer 3 blocks PA6, PA7, PB0, PB1 for use by Servo or tone() #define IR_RECEIVE_PIN PA6 #define IR_RECEIVE_PIN_STRING "PA6" #define IR_SEND_PIN PA7 #define IR_SEND_PIN_STRING "PA7" #define TONE_PIN PA3 #define _IR_TIMING_TEST_PIN PA5 #define APPLICATION_PIN PA2 #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". saves 370 bytes program space and 38 bytes RAM for digistump core #define IR_RECEIVE_PIN 0 #define IR_SEND_PIN 4 // Pin 2 is serial output with ATtinySerialOut. Pin 1 is internal LED and Pin3 is USB+ with pullup on Digispark board. #define TONE_PIN 3 #define _IR_TIMING_TEST_PIN 3 #elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut" // For ATtiny167 Pins PB6 and PA3 are usable as interrupt source. # if defined(ARDUINO_AVR_DIGISPARKPRO) #define IR_RECEIVE_PIN 9 // PA3 - on Digispark board labeled as pin 9 //#define IR_RECEIVE_PIN 14 // PB6 / INT0 is connected to USB+ on DigisparkPro boards #define IR_SEND_PIN 8 // PA2 - on Digispark board labeled as pin 8 #define TONE_PIN 5 // PA7 #define _IR_TIMING_TEST_PIN 10 // PA4 # else #define IR_RECEIVE_PIN 3 #define IR_SEND_PIN 2 #define TONE_PIN 7 # endif #elif defined(__AVR_ATtiny88__) // MH-ET Tiny88 board #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program space // Pin 6 is TX pin 7 is RX #define IR_RECEIVE_PIN 3 // INT1 #define IR_SEND_PIN 4 #define TONE_PIN 9 #define _IR_TIMING_TEST_PIN 8 #elif defined(__AVR_ATtiny3217__) #define IR_RECEIVE_PIN 10 #define IR_SEND_PIN 11 #define TONE_PIN 3 #define APPLICATION_PIN 5 #elif defined(__AVR_ATtiny1604__) #define IR_RECEIVE_PIN 2 // To be compatible with interrupt example, pin 2 is chosen here. #define IR_SEND_PIN 3 #define APPLICATION_PIN 5 #define tone(...) void() // Define as void, since TCB0_INT_vect is also used by tone() #define noTone(a) void() #define TONE_PIN 42 // Dummy for examples using it # elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \ || defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \ || defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \ || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \ || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__) #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 13 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 #elif defined(ARDUINO_ARCH_APOLLO3) #define IR_RECEIVE_PIN 11 #define IR_SEND_PIN 12 #define TONE_PIN 5 #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 3 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 #elif defined(TEENSYDUINO) #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 3 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 #elif defined(__AVR__) // Default as for ATmega328 like on Uno, Nano etc. #define IR_RECEIVE_PIN 2 // To be compatible with interrupt example, pin 2 is chosen here. #define IR_SEND_PIN 3 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM) #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 3 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 // On the Zero and others we switch explicitly to SerialUSB #define Serial SerialUSB // Definitions for the Chinese SAMD21 M0-Mini clone, which has no led connected to D13/PA17. // Attention!!! D2 and D4 are switched on these boards!!! // If you connect the LED, it is on pin 24/PB11. In this case activate the next two lines. //#undef LED_BUILTIN //#define LED_BUILTIN 24 // PB11 // As an alternative you can choose pin 25, it is the RX-LED pin (PB03), but active low.In this case activate the next 3 lines. //#undef LED_BUILTIN //#define LED_BUILTIN 25 // PB03 //#define FEEDBACK_LED_IS_ACTIVE_LOW // The RX LED on the M0-Mini is active LOW #elif defined (NRF51) // BBC micro:bit #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 3 #define APPLICATION_PIN 1 #define _IR_TIMING_TEST_PIN 4 #define tone(...) void() // no tone() available #define noTone(a) void() #define TONE_PIN 42 // Dummy for examples using it #else #warning Board / CPU is not detected using pre-processor symbols -> using default values, which may not fit. Please extend PinDefinitionsAndMore.h. // Default valued for unidentified boards #define IR_RECEIVE_PIN 2 #define IR_SEND_PIN 3 #define TONE_PIN 4 #define APPLICATION_PIN 5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN 7 #endif // defined(ESP8266) #if !defined (FLASHEND) #define FLASHEND 0xFFFF // Dummy value for platforms where FLASHEND is not defined #endif /* * Helper macro for getting a macro definition as string */ #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x)
Полный код файла ir_example.ino
/* Kincony KC868-A4 IR example * ReceiveAndSend.cpp * * * Record and play back last received IR signal at button press. * The logic is: * If the button is pressed, send the IR code. * If an IR code is received, record it. * * An example for simultaneous receiving and sending is in the UnitTest example. * * An IR detector/demodulator must be connected to the input IR_RECEIVE_PIN. * * A button must be connected between the input SEND_BUTTON_PIN and ground. * A visible LED can be connected to STATUS_PIN to provide status. * * Initially coded 2009 Ken Shirriff http://www.righto.com * * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote. * */ #include <Arduino.h> /* * Define macros for input and output pin etc. */ #include "PinDefinitionsAndMore.h" //#define EXCLUDE_EXOTIC_PROTOCOLS // saves around 900 bytes program space #include <IRremote.hpp> int SEND_BUTTON_PIN = APPLICATION_PIN; int STATUS_PIN = LED_BUILTIN; int DELAY_BETWEEN_REPEAT = 50; // On the Zero and others we switch explicitly to SerialUSB #if defined(ARDUINO_ARCH_SAMD) #define Serial SerialUSB #endif struct storedIRDataStruct { // Storage for the recorded code IRData receivedIRData; // extensions for sendRaw uint8_t rawCode[RAW_BUFFER_LENGTH]; // durations if raw uint8_t rawCodeLength; // length of code } sStoredIRData; int lastButtonState; void storeCode(IRData *aIRReceivedData); void sendCode(storedIRDataStruct *aIRDataToSend); void setup() { Serial.begin(115200); Serial.println(F("Start Kincony KC868-A4 IR example...")); // Just to know which program is running on my Arduino //Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // Start the receiver, enable feedback LED, take LED feedback pin from the internal boards definition IrSender.begin(IR_SEND_PIN, ENABLE_LED_FEEDBACK); // Specify send pin and enable feedback LED at default feedback LED pin pinMode(STATUS_PIN, OUTPUT); /* Serial.print(F("Ready to receive IR signals of protocols: ")); printActiveIRProtocols (&Serial); Serial.print(F("at pin ")); #if defined(ARDUINO_ARCH_STM32) || defined(ESP8266) Serial.println(IR_RECEIVE_PIN_STRING); #else Serial.println(IR_RECEIVE_PIN); #endif Serial.print(F("Ready to send IR signals at pin ")); #if defined(ARDUINO_ARCH_STM32) || defined(ESP8266) Serial.println(IR_SEND_PIN_STRING); #else Serial.print(IR_SEND_PIN); #endif Serial.print(F(" on press of button at pin ")); Serial.println(SEND_BUTTON_PIN); Serial.print(F("LED_BUILTIN: ")); Serial.println(LED_BUILTIN); Serial.print(F("STATUS_PIN: ")); Serial.println(STATUS_PIN); Serial.print(F("TONE_PIN: ")); Serial.println(TONE_PIN); Serial.print(F("IR_RECEIVE_PIN: ")); Serial.println(IR_RECEIVE_PIN); Serial.print(F("IR_SEND_PIN: ")); Serial.println(IR_SEND_PIN); Serial.print(F("APPLICATION_PIN: ")); Serial.println(APPLICATION_PIN); */ } // setup // Stores the code for later playback in sStoredIRData void storeCode(IRData *aIRReceivedData) { if (aIRReceivedData->flags & IRDATA_FLAGS_IS_REPEAT) {Serial.println(F("Ignore repeat")); return;} if (aIRReceivedData->flags & IRDATA_FLAGS_IS_AUTO_REPEAT) {Serial.println(F("Ignore autorepeat")); return;} if (aIRReceivedData->flags & IRDATA_FLAGS_PARITY_FAILED) {Serial.println(F("Ignore parity error")); return;} sStoredIRData.receivedIRData = *aIRReceivedData; // Copy decoded data if (sStoredIRData.receivedIRData.protocol == UNKNOWN) { Serial.print(F("Received unknown code and store ")); Serial.print(IrReceiver.decodedIRData.rawDataPtr->rawlen - 1); Serial.println(F(" timing entries as raw ")); IrReceiver.printIRResultRawFormatted(&Serial, true); // output the results in RAW format sStoredIRData.rawCodeLength = IrReceiver.decodedIRData.rawDataPtr->rawlen - 1; IrReceiver.compensateAndStoreIRResultInArray(sStoredIRData.rawCode); // store current raw data in dedicated array for later usage } else { IrReceiver.printIRResultShort(&Serial); sStoredIRData.receivedIRData.flags = 0; // clear flags -esp. repeat- for later sending Serial.println(); } } // storeCode( ) void sendCode(storedIRDataStruct *aIRDataToSend) { if (aIRDataToSend->receivedIRData.protocol == UNKNOWN) { // raw IrSender.sendRaw(aIRDataToSend->rawCode, aIRDataToSend->rawCodeLength, 38); // 38 KHz Serial.print(F("Sent raw ")); Serial.print(aIRDataToSend->rawCodeLength); Serial.println(F(" marks or spaces")); } else { IrSender.write(&aIRDataToSend->receivedIRData, NO_REPEATS); // write func switch for different protocols Serial.print(F("Sent: ")); printIRResultShort(&Serial, &aIRDataToSend->receivedIRData); } } void loop() { int buttonState = digitalRead(SEND_BUTTON_PIN); // active LOW if (lastButtonState == LOW && buttonState == HIGH) { Serial.println(F("Button released")); IrReceiver.start(); // re-enable receiver } // Check for static button state if (buttonState == LOW) { IrReceiver.stop(); // Button pressed send stored data or repeat Serial.println(F("Button pressed, now sending")); digitalWrite(STATUS_PIN, HIGH); if (lastButtonState == buttonState) { sStoredIRData.receivedIRData.flags = IRDATA_FLAGS_IS_REPEAT; } sendCode(&sStoredIRData); digitalWrite(STATUS_PIN, LOW); delay(DELAY_BETWEEN_REPEAT); // Wait a bit between retransmissions } else if (IrReceiver.available()) { // Button is not pressed, check for incoming data storeCode(IrReceiver.read()); IrReceiver.resume(); } lastButtonState = buttonState; } // loop
Результат работы скетча: сначала мы принимаем IR сигнал от пульта и декодируем его, а затем посылаем в эфир (дублируем), нажимая на кнопку «USER» контроллера Kincony KC868-A4.

▍ Заключение
Во второй статье цикла мы рассмотрели «атомарные» примеры программирования различных функциональных блоков контроллера Kincony KC868-A4. Используя эту информацию, вы можете легко начать программировать контроллер под свои задачи — всё расписано «от и до»: фото, схемы, распиновка, примеры кода, ссылки на библиотеки, скриншоты, пояснения и т. д.
В следующей статье мы рассмотрим более сложные примеры работы с KC868-A4, такие, как работа с беспроводной Wi-Fi частью и удалённое управление контроллером через интернет при помощи мессенджеров Telegram и/или Whatsapp.

