• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос Подружить ESP8266 и приемник 433МГц

Sr.FatCat

Member
Ясновидящие редкость это понятно, как и внимательно читающие. От D1 Wi-Fi Uno до обычной esp.
Так может рискнете уже написать правильный код для какого-нибудь пина, а такой нуб как я уже просто изменит одну циферку или буковку, или ручками воткнет датчик в нужный пин
Я уже расписал все выше - подробнее некуда, @tretyakov_sa, с завидным терпением, все повторил и разжевал. Где какие GPIO на незнакомой D1 Wi-Fi Uno мне не понятно, поэтому насчет какую циферку вписать вам в mySwitch.enableReceive(0) не скажет никто, кроме Вас.
Кстати, думаю, особых проблем ни с 0, ни с 2 не будет, при старте ESP-шка отрабатывает прижатие их к земле, а шум приемника он к питанию. Но неожиданности могут быть.

Абсолютно согласен, но с одной оговоркой. Если есть 100% уверенность в работоспособности данной библиотеки на esp8266.
В противном случае, лезть придется.
Это одна из лучших в плане мультиплатформенности библиотек. В коде препроцессора ESP поддерживается явнее некуда. Мне в код библиотеки пришлось лезть только по одной причине - для совместного использования обработчика прерывания, ибо интерфейса для наследников там не предусмотрено, к сожалению.

По теме вопроса. Дальнейшие исследования показали, что при совместном подключении UNO и ESP к приемнику - есть очень любопытные нюансы. А именно, если на UNO не подавать питания, то никаких сигналов к ESP не проходит. Похоже вход выключенной UNO шунтирует выход приемника. А при включенной UNO - ESPшка ловит манчестер в 3-5 раз лучше, чем если просто подключена одна, но все равно хуже в 2-3 раза, чем UNO. Даже предположить не могу, что там такого может быть на входе уны, что так благотворно влияет на прием есп-шкой. Пробывал подтягивать вход есп-шки (при отключеной уно) разными номиналами к земле и снимать с приемника через делитель, но эффекта 0 - ESPшка очень печально раскодирует манчестер и очень уверено RC_Switch. Хотя все это больше склоняет меня к борьбе аппаратной проблемой.
Вчера под вечер ситуация усугубилась. Похоже сильно прибавилось шумов в эфире, есп-шка стала хреновее работать как UDP-сервер и переодически вылетать с Exception(9). Закоментировал в обработчике прерывания мой декодер манчестера - вылетать перестала. Подозреваю, что идут слишком частые обращения к прерыванию и сравнительно тяжелый код манчестера вместе с лагающим UDP провоцируют злобную сторожевую собаку на soft reset...
 

kab

New member
@Sr.FatCat
Может в процедуре прерывания ввести принудительный интервал между "рабочими" приемами информации - пропуская без обработки пришедшие слишком "рано"? И вопрос к специалистам - а что вообще происходит, если процедура прерывания еще не завершена, а наступает новое условие прерывания?
 

roiksv

Member
Т.е в mySwitch.enableReceive(N) для Uno N=0 >pin2, N=1 >pin3, для Mega N=2 > pin21, N=3 > pin20, N=4 > pin19, N=5 > pin18, а для esp N=0 >gpio0, N=1 >gpio1 и так далее?
 

Sr.FatCat

Member
@roiksv именно так

@Sr.FatCat
Может в процедуре прерывания ввести принудительный интервал между "рабочими" приемами информации - пропуская без обработки пришедшие слишком "рано"? И вопрос к специалистам - а что вообще происходит, если процедура прерывания еще не завершена, а наступает новое условие прерывания?
Ну там и так отбрасывается, все, что меньше 200мкс, в эту сторону не отптимизируешь. Буду медитировать над кодом, чтобы придумать условия чтобы как можно раньше обрывать обработку.

Что касается именно этих прерываний у ESP - не знаю, а обычно вложенные прерывания могут быть разрешены и обработчик должен это учитывать, либо запрещать вложенность, либо запрещать вообще все прерывания на время обработки.
 

kab

New member
вложенные прерывания могут быть разрешены
может здесь собака и порылась? Т. е. во время выполнения "тяжелого" кода наступает новое прерывание и новый процесс сбивает какие-то значения глобальных переменных от старого процесса? И из-за этого всё путается?
 

Sr.FatCat

Member
@kab я сделал более кондово: я запрещал в обработчике прерывания :), гарантируя что мне ничего не помешает. Качество распознавания манчестера ни сколько не улучшилось :(
 

Sr.FatCat

Member
Выкинул из обработчика прерывания процедуру декодирования манчестера и сделал буфер на 256 таймингов. Буфер копирую с запретом прерывания и разбираю, по возможности, в основном цикле. Сторожевая собака довольна, хотя переполнение буфера происходит переодически и часть сигналов теряется.
Вставил это безобразие в основной проект, распознавание манчестера ухудшилось еще сильнее - теперь в среднем не более 4 распознаных посылок за час.

Тем не менее, у меня картинка сложилась, может не до конца правильная, но думаю дело в этом. Часть кода в ESP8266 отвечающая за обслуживание WiFi, естественно имеет более высокий приоритет, а потому прерывание от приемника 433 выполняется не всегда или с задержкой. Для RC_switch это не так критично, хотя более внимательное рассмотрение показывает, что оно тоже страдает, пропуск посылок на реальном проете все-таки и там происходит, но редко - в 5-7% случаев примерно, а вот для манчестера - да, беда, беда.

Программное решение тут почти не вижу. То, что могу придумать - довольно сложно, с массой ограничений и работать будет не идеально.
Аппаратных решений вижу 2: использовать в качестве приемника что-типа RFM69 или сделать свой бридж RF433->OneWire/I2C на какой-нибудь тиньке или мини про. Думаю тему можно закрывать.
 
  • Like
Реакции: kab

fm96

New member
Не очень надеюсь, что кто-то сможет чем-то помочь, поэтому скетч пока выкладывать не буду. Опишу словами:
Есть NodeMCU к выводу D1 (GPIO5) которого подключен примитивный приемник 433МГц (сейчас RXB6, как самый хваленый, но картина не сильно отличается и с SRX882 и даже с RF-5V) - задача принять и расшифровать сигналы от стандартного RC_Switch устройства и датчиков Oregon Scientific.
Реализация довольно примитивная: сигнал с приемника вызывает прерывание на D1 - там определяется его длинна (от предыдущего прерывания) и по известным алгоритмам переводится в байты RCSwitch или манчестерский код.
Велосипед не изобретался. была взята известная библиотека RCSwitch и в ее процедуру обработки прерывания вкостылена еще и функция обсчета манчестерского кода известным классом DecodeOOK.

Вся математика в прерывании. В теле loop проверяется только флаг прочитанного кода и если он выставлен - результат выводится в Serial.

Теперь интрига.
Сначала все это опробывал на Arduino UNO (с подключением к 2-му цифровому, прерывание 0) - работает как часы. Просто отлично.
Поменял в скетче только номер прерывания. Загрузил в ESP и облом. RCSwitch - все так же выдает как часы, данные от Oregon получаются расшифровать в среднем в 1 из 7-10 посылок. При этом еще и куча ложняков приходит (это при том, что 6/8 байт манчестерского кода проверяются по CRC !!!)
Погрешил на шумность ESP - смонтировал UNO и NodeMCU на одной макетке c одним приемником, выход которого подключил без всякой развязки к 2 и D1 выводов МК сответственно. Питание пробывал подавать и от уны и от ноды. Запускаю скетчи одновременно - смотрю в разных терминалах. Результат - тот же. Все прекрасно работает на уне, но на esp только RCSwitch работает отлично, по Орегону очень редко и ложняки.
Хотя бы понять с чем это связано может быть? Аппаратно или программно?
У меня работает н RC_Switch, но не работает на RemoteReceiver
 

fm96

New member
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RCSwitch.h>
LiquidCrystal_I2C _lcd1(0x27, 16, 2);
int _dispTempLength1=0;
boolean _isNeedClearDisp1;
extern "C" {
#include "user_interface.h";
}
float out1;
float out2;
RCSwitch mySwitch= RCSwitch();
float tempout=0,Hr=0;
#define key1 11000 // датчик температуры
#define key2 12000 // датчик влажность
extern "C" {
#include "user_interface.h"
}
os_timer_t watchDogTimer;
int _PWDC = 0;
int _disp1oldLength = 0;
int _disp2oldLength = 0;
void setup()
{
Wire.pins(4, 5);
Wire.begin();
delay(10);
satrtWachDogTimer();
_lcd1.init();
_lcd1.backlight();
mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2 // иницилизация.Используется вывод м/к с прерыванием под номером 0.
Serial.begin(9600);
mySwitch.enableReceive(0);
}
void loop()
{if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;}
_PWDC = 0;


//Плата:1
{

if (mySwitch.available()) {

unsigned long receivedCode= mySwitch.getReceivedValue();
if (receivedCode == 0) {
// обработка:не верный формат данных
} else {
if (key1<=receivedCode && key1+999>receivedCode) tempout=(int)(receivedCode-key1-500);
else if (key2<=receivedCode && key2+999>receivedCode)Hr=(int)(receivedCode-key2);
else tempout = (float)(receivedCode); //пример для влажности
// нужно делить на 10,если отправляем через езернет на компьютер- разделить можно там.

}
mySwitch.resetAvailable(); // сброс данных.
} // end available
out1 = tempout;
out2 = Hr;
Serial.println(tempout);
delay(1000);
Serial.println(Hr);
delay(1000);
// тут могут выводится данные tempout и tempin на лсд экран или отправлятся через езернет.
}
if (1) {
_dispTempLength1 = ((( _floatToStringWitRaz((out2)/(10.00),2)))).length();
if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp2oldLength = _dispTempLength1;
_lcd1.setCursor(0, 1);
_lcd1.print((( _floatToStringWitRaz((out2)/(10.00),2))));
} else {
if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;}
}
if (1) {
_dispTempLength1 = ((( _floatToStringWitRaz((out1)/(10.00),2)))).length();
if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp1oldLength = _dispTempLength1;
_lcd1.setCursor(0, 0);
_lcd1.print((( _floatToStringWitRaz((out1)/(10.00),2))));
} else {
if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;}
}


}
String _floatToStringWitRaz(float value, int raz)
{

return String(value,raz);
}
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long currentTime;
currentTime = millis();
if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
}
void wachDogTimerTick(void *pArg) {
if (_PWDC >= 100){ ESP.reset(); }else{_PWDC = _PWDC+1;}
}
void satrtWachDogTimer(void ) {
os_timer_setfn(&watchDogTimer, wachDogTimerTick, NULL);
os_timer_arm(&watchDogTimer, 100, true);
}
 
Сверху Снизу