#define LOOP_SIZE 100 // Буфер (кольцевой) сбора таймингов
#define PIN_RECEIVER 2 // Пин приемника 433/415/IR
void handleInterrupt(); // IRAM_ATTR для ESP8266/32
void isMatch(); // IRAM_ATTR для ESP8266/32
uint32_t availableRC(); // IRAM_ATTR для ESP8266/32
// Определяем структуры
struct TimingData {
uint16_t timing; // Хранение времени
bool pinStatus; // Хранение статуса пина
};
TimingData TIMINGS[LOOP_SIZE];
uint8_t LOOPINDEX = 0; // Индекс полченных таймингов публичный
struct FirstSecond {
uint8_t n0; // Первый Тайминг { 1, }
uint8_t n1; // Второй Тайминг { , 1 }
};
struct Protocol {
uint16_t pulse; // Преамбула
FirstSecond pre; // Преамбула
FirstSecond b1 ; // Эталон таймига соответствует биту 1
FirstSecond b0; // Эталон таймига соответствует биту 0
const char* name; // Имя протакола
};
//Определяем массив с протоколами
const Protocol pro[] = {
{560, {16, 8 }, { 1, 3 }, { 1, 1 }, "Nec" }, //1-Protocol { { 9000, 4500 }, { 526, 1686 }, { 526, 526 }, "wokwi" },
// { { 9000, 2200 }, { 560, 0 }, { 0, 0 }, "Nec-repeat" }, //2
// { { 520, 7150 }, { 536, 0 }, { 0, 0 }, "Canon" }, //3
// { { 8400, 4200 }, { 530, 1600 }, { 530, 530 }, "JVC" }, //4 при повторе преамбула отсутствует
// { { 4500, 4500 }, { 650, 1500 }, { 650, 650 }, "Samsung" }, //5
// { { 4000, 4000 }, { 500, 2000 }, { 500, 500 }, "RCA" }, //6
// { { 3600, 1500 }, { 400, 1200 }, { 400, 400 }, "Panasonic" }, //7
// { { 3200, 3200 }, { 800, 2400 }, { 800, 800 }, "Funai" }, //8 при повторе преамбула отсутствует
// { { 2400, 600 }, { 1200, 600 }, { 600, 600 }, "Sony" }, //9
// { { 890, 890 }, { 900, 900 }, { 900, 900 }, "RC5" }, //10
// { { 2670, 890 }, { 450, 450 }, { 450, 450 }, "RC6" }, //11
// { { 500, 2500 }, { 500, 500 }, { 500, 500 }, "Nokia" }, //12
// { { 420, 280 }, { 0, 0 }, { 0, 0 }, "RC-MM" }, //13
{350, {1, 31}, {1, 3}, {3, 1}, "protocol 1"}, // protocol 1 //14
// { { 650, 6500 }, { 650, 1300 }, { 1300, 650 }, "protocol 2" }, //15
// { { 3000, 7100 }, { 400, 1100 }, { 900, 600 }, "protocol 3" }, //16
// { { 380, 2280 }, { 380, 1140 }, { 1140, 380 }, "protocol 4" }, //17
// { { 3000, 7000 }, { 500, 1000 }, { 1000, 500 }, "protocol 5" }, //18
};
static const uint8_t PROTO_COUNT = sizeof(pro) / sizeof(pro[0]);
// ######################################################
// ######################################################
void setup() {
Serial.begin(921600);
Serial.println("21-01-2025:: Определение посылки RC 433/415/IR");
attachInterrupt(digitalPinToInterrupt(PIN_RECEIVER), handleInterrupt, CHANGE);
delay(100);
}
// ######################################################
// ######################################################
void loop() {
static uint32_t a;
if (( a = availableRC())) {
uint32_t t = micros();
Serial.println(a, HEX);
Serial.println("Время: " + (String)(micros() - t));
}
// индикатор работы контроллера
uint32_t t = micros();
static uint32_t tt = t;
if ((t - tt) > 5e6) {
Serial.println("work!");
tt = t;
}
}
// ######################################################
// ######################################################
uint8_t isMatch(const uint16_t time0, const uint16_t time1, int8_t proto) { // IRAM_ATTR для ESP8266/32
const uint8_t tolerance = 60; // Допуск
proto = abs(proto);
if (proto) {
const uint8_t i = (proto) ? (proto - 1) : 0;
//Биты
if (abs((float)(time0 / pro[i].b1.n0) - pro[i].pulse) < tolerance && abs((float)(time1 / pro[i].b1.n1) - pro[i].pulse) < tolerance) { //1
return proto;
}
else {
if (abs((float)(time0 / pro[i].b0.n0) - pro[i].pulse) < tolerance && abs((float)(time1 / pro[i].b0.n1) - pro[i].pulse) < tolerance) { //0
return -proto;
}
}
} else {
// Преамбула
for (uint8_t i = 0; i < PROTO_COUNT; i++) {
if ((abs((float)(time0 / pro[i].pre.n0) - pro[i].pulse) < tolerance && abs((float)(time1 / pro[i].pre.n1) - pro[i].pulse) < tolerance)) return (i + 1);
}
}
return 0;
}
// ######################################################
// ######################################################
uint32_t availableRC() { // IRAM_ATTR для ESP8266/32
static int8_t protocolFound = 0; // отрицательный для бита = 0 / положительный бит = 1 / 0 - ищим преамбулу по всем протаколам
static uint8_t index = 0; // догоняем перебор кольцевого общего массива
// Serial.println("index: " + (String)index + ":: LOOPINDEX: " + (String)index);
static uint32_t decodedData = 0; // Храним полученный код
static uint8_t decodedCount = 0; // Храним кол-во найденных бит
static uint32_t timeOld = 0;
const uint32_t time = micros();
if (decodedCount > 23 && !protocolFound) {
// Serial.println(pro[protocolFound - 1].name);
// protocolFound = 0;
decodedCount = 0;
uint32_t decodedDataR = decodedData;
decodedData = 0;
// index = (index != LOOPINDEX) ? (index + 1) % LOOP_SIZE : index ;
return decodedDataR;
}
// ПОИСК БИТ 0/1 ######################################################
if (protocolFound) {
while (protocolFound && (index != LOOPINDEX)) {
if (!TIMINGS[index].pinStatus && (protocolFound = (isMatch(TIMINGS[((index + LOOP_SIZE - 1) % LOOP_SIZE)].timing, TIMINGS[index].timing, protocolFound)))) {
// тут protocolFound только != 0
if (protocolFound > 0) { // Добавляем бит 1
decodedData = (decodedData << 1) | 1;
decodedCount++;
} else { // Или добавляем бит 0 короткая запись decodedData <<= 1
decodedData = (decodedData << 1);
decodedCount++;
}
}
// Serial.print("index: " + (String)index + " :: " + (String)LOOPINDEX + " // decodedData: ");
// Serial.print(decodedData, HEX);
// Serial.println(" // TIMINGS: " + (String)TIMINGS[((index + LOOP_SIZE - 1) % LOOP_SIZE)].timing + ", " + TIMINGS[index].timing + " // PIN: " + (String)TIMINGS[index].pinStatus);
// Serial.println("TIMINGS[index].timing: " + (String)TIMINGS[index].timing);
index = (index + 1) % LOOP_SIZE;
if (decodedCount >= 32) {
protocolFound = false;
return availableRC();
}
}
}
// ПОИСК ПРЕАМБУЛЫ ######################################################
while (!protocolFound && (index != LOOPINDEX) && decodedCount < 1 ) {
if (!TIMINGS[index].pinStatus && (protocolFound = (isMatch(TIMINGS[((index + LOOP_SIZE - 1) % LOOP_SIZE)].timing, TIMINGS[index].timing, protocolFound)))) {
}
// Serial.print("index: " + (String)index + " :: " + (String)LOOPINDEX + " // decodedData: ");
// Serial.print(decodedData, HEX);
// Serial.println(" // TIMINGS: " + (String)TIMINGS[((index + LOOP_SIZE - 1) % LOOP_SIZE)].timing + ", " + TIMINGS[index].timing + " // PIN: " + (String)TIMINGS[index].pinStatus);
// Serial.println("TIMINGS[index].timing: " + (String)TIMINGS[index].timing);
Serial.println(pro[protocolFound - 1].name);
index = (index + 1) % LOOP_SIZE;
}
return 0;
}
// ######################################################
// ######################################################
void handleInterrupt() { // IRAM_ATTR для ESP8266/32
const uint32_t nowTime = micros();
static uint32_t lastTime = 0;
uint16_t delta = (uint16_t)((nowTime >= lastTime) ? (nowTime - lastTime) : (UINT32_MAX - lastTime + nowTime + 1)); // код проверки переполнениявремени (~71,6 мин), накапливаем только UINT16_MAX
lastTime = nowTime;
if (delta < 200 || delta > 12e3) return;
TIMINGS[LOOPINDEX].pinStatus = digitalRead(PIN_RECEIVER);
TIMINGS[LOOPINDEX].timing = delta;
LOOPINDEX = (LOOPINDEX + 1) % LOOP_SIZE;
// Serial.println("LOOPINDEX = " + String(LOOPINDEX));
// TIMINGS[LOOPINDEX].timing = 0; // всегда затераем следующий за текущим
}
// ######################################################
// ######################################################