Продолжаем ультимативный гайд по контроллеру 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.
Комментарии (10)
srg27y
03.02.2022 09:03Интерфейс RS232
достаточно спорный момент, для автоматизацыи 485/422 полезнее.
RTFM13
На этот стандарт тьма готовых датчиков, модулей, выключателей и т.п.
Мне только отсутствие шифрования в нем не нравится.
Печалят примеры на ардуине, а не на более найтивном ESP-IDF.
smart_alex Автор
Отсутствие шифрования и обратной связи. Если (очень) нужно использовать что-то готовое — можно работать и с этими модулями на 433 МГц. Если делать что-то своё — я без шифрования и обратной связи просто не представляю беспроводные соединения.
RTFM13
Делать своё - проблема с корпусами. Вплоть до того, что покупается готовое устройство выкидываются потроха и делается своё.
smart_alex Автор
Под «делать что-то своё» я (по привычке) имел в виду беспроводные датчики/актуаторы и собственный беспроводной стек к ним. Кстати, а кто мешает зашифровать данные, передаваемые по 433 и организовать обратную связь для них (на своём протоколе)?
А если говорить о корпусе — комплектный корпус Kincony KC868-A4 мне понравился, он недорогой и продаётся отдельно.
RTFM13
Если отказаться от совместимости с готовыми устройствами, то и смысл теряется.
Про корпус - я уже заказал. )
smart_alex Автор
Логично.
smart_alex Автор
Я — «ардуинщик», поэтому и примеры на Ардуино. :)
advan20092
Можно попробовать переползти на platformio. Все-таки VSCode гораздо удобнее среды ардуино. При этом фреймворк и библиотеки можно продолжить использовать те же самые, как на арудино. Ну и бонусом можно при необходимости делать вставки кода на ESP-IDF API, просто подключая нужные заголовочные файлы.
smart_alex Автор
Я этот перформанс уже проделывал несколько лет назад — и «переполз» обратно на Ардуино. Наверное я единственный, кому Arduino IDE нравится больше Platformio. :)
А вставки кода из ESP-IDF API никто не мешает делать и в Arduino.