FAQ ESP8266
Модератор: immortal
- nick7zmail
- Сообщения: 7573
- Зарегистрирован: Пн окт 28, 2013 8:14 am
- Откуда: Екатеринбург
- Благодарил (а): 121 раз
- Поблагодарили: 2010 раз
Re: FAQ ESP8266
Ну для начала я бы избавился от delay...иначе получать сигнал с датчика по прошествии 3 сек с его сработки (а тем более, к примеру, включать свет по таким показаниям) - как минимум не комфортно...во вторых увеличил бы интервал отправки температуры/влажности....зачем так часто спамить (для отладки хорошо, но на постоянку я бы засылал раз в 5-10 минут, а движение, естесственно, при сработке по факту).
Вот тут очитайте про базовые таймеры https://arduinomaster.ru/program/arduino-delay-millis/
Вот тут очитайте про базовые таймеры https://arduinomaster.ru/program/arduino-delay-millis/
- За это сообщение автора nick7zmail поблагодарил:
- ZyaK (Пт май 29, 2020 12:52 pm)
- Рейтинг: 1.16%
Raspberry Pi3+Broadlink+esp8266 (blynk)+AMS
Если вам помогло какое-либо сообщение - не забывайте пользоваться кнопкой "СПАСИБО".
Услуги в профиле коннект
>>>>>Мой новый канал на ютутбе, подписывайтесь!<<<<<
Если вам помогло какое-либо сообщение - не забывайте пользоваться кнопкой "СПАСИБО".
Услуги в профиле коннект
>>>>>Мой новый канал на ютутбе, подписывайтесь!<<<<<
-
- Сообщения: 407
- Зарегистрирован: Вт окт 24, 2017 2:01 pm
- Откуда: Ижевск
- Благодарил (а): 45 раз
- Поблагодарили: 69 раз
Re: FAQ ESP8266
улучшать необходимо.
в лупе у вас постоянный спам от датчиков температуры да еще и задержки по 1 секунде...
задержки убирать однозначно, спам в сериал порт и преобразования датчиком температуры убирать в отдельную функцию.
в лупе завести таймер и при определенном значении вызывать функцию опроса датчиков и спама в порт.
датчик движения я так понимаю работает по прерыванию? обработчика прерывания не увидел.
Как то так примерно должно выглядеть
- Вложения
-
- IMG_20200529_135953.jpg (1.41 МБ) 3326 просмотров
- Рейтинг: 1.16%
PI2 + MQTT + 5 ESP8266 + Atmega16
- nick7zmail
- Сообщения: 7573
- Зарегистрирован: Пн окт 28, 2013 8:14 am
- Откуда: Екатеринбург
- Благодарил (а): 121 раз
- Поблагодарили: 2010 раз
Re: FAQ ESP8266
А ещё советую глянуть код AMS (Arduino Mega Server), тут на форуме есть проект...там очень много мусора в коде, но конкретно с таймерами там максимально понятно сделано. Я даже конкретно вырезку с таймерами использовал в отдельных проектах.
Raspberry Pi3+Broadlink+esp8266 (blynk)+AMS
Если вам помогло какое-либо сообщение - не забывайте пользоваться кнопкой "СПАСИБО".
Услуги в профиле коннект
>>>>>Мой новый канал на ютутбе, подписывайтесь!<<<<<
Если вам помогло какое-либо сообщение - не забывайте пользоваться кнопкой "СПАСИБО".
Услуги в профиле коннект
>>>>>Мой новый канал на ютутбе, подписывайтесь!<<<<<
-
- Сообщения: 68
- Зарегистрирован: Чт сен 26, 2019 4:14 pm
- Откуда: Ярославль
- Благодарил (а): 19 раз
- Поблагодарили: 6 раз
Re: FAQ ESP8266
Прошу прощения, вот это не функция обработки прерыванияZyaK писал(а): ↑Пт май 29, 2020 12:51 pmулучшать необходимо.
в лупе у вас постоянный спам от датчиков температуры да еще и задержки по 1 секунде...
задержки убирать однозначно, спам в сериал порт и преобразования датчиком температуры убирать в отдельную функцию.
в лупе завести таймер и при определенном значении вызывать функцию опроса датчиков и спама в порт.
датчик движения я так понимаю работает по прерыванию? обработчика прерывания не увидел.
Как то так примерно должно выглядеть
void IRAM_ATTR detectsMovementD6() { // Функция при обнаружении движения на D6
Serial.println("Движение на D6!!!");
}
-
- Сообщения: 407
- Зарегистрирован: Вт окт 24, 2017 2:01 pm
- Откуда: Ижевск
- Благодарил (а): 45 раз
- Поблагодарили: 69 раз
Re: FAQ ESP8266
А где вы её вызываете то? она у вас обозначена в начале программы и всё, где она вызывается? в лупе о ней нет ни строчки, что происходит внутри функции тоже нигде не написано.
это должно быть организовано на подобии кнопки, в лупе вызываем таймер, если таймер наступил - делаем действия по таймеру, после таймера опрос функций обработчиков входных пинов, в функции опрашивается состояние пина если высокий - ничего не делаем, выходим из функции, если упал на 0, проверяем еще раз через 10 миллисекунд (защита от дребезга) если высокий - ничего не делаем и выходим из функции, если 0 -> обрабатываем срабатывание датчика движения кричим, орем, мигаем светодиодом или там данные на сервер передаём - выходим из обработчика функции -> дальше крутимся по бесконечному циклу, проверяем таймер, опять опрашиваем состояния входных пинов
так же можно добавить таймер и еще одну переменную что бы не опрашивать несколько сотен раз в секунду уже включенный датчик движения, а то при каждом заходе в функцию пока датчик включен будут на сервер лететь пакеты которые и так уже нафиг не нужны. называется "Флаг срабатывания" когда датчик отключился, соответственно пин стал опять в высокий уровень, флаг сбрасывается в 0. при следующем срабатывании датчика флаг выставляется в 1 после отправки данных и больше в функцию отправки программа попадать не должна.
это должно быть организовано на подобии кнопки, в лупе вызываем таймер, если таймер наступил - делаем действия по таймеру, после таймера опрос функций обработчиков входных пинов, в функции опрашивается состояние пина если высокий - ничего не делаем, выходим из функции, если упал на 0, проверяем еще раз через 10 миллисекунд (защита от дребезга) если высокий - ничего не делаем и выходим из функции, если 0 -> обрабатываем срабатывание датчика движения кричим, орем, мигаем светодиодом или там данные на сервер передаём - выходим из обработчика функции -> дальше крутимся по бесконечному циклу, проверяем таймер, опять опрашиваем состояния входных пинов
так же можно добавить таймер и еще одну переменную что бы не опрашивать несколько сотен раз в секунду уже включенный датчик движения, а то при каждом заходе в функцию пока датчик включен будут на сервер лететь пакеты которые и так уже нафиг не нужны. называется "Флаг срабатывания" когда датчик отключился, соответственно пин стал опять в высокий уровень, флаг сбрасывается в 0. при следующем срабатывании датчика флаг выставляется в 1 после отправки данных и больше в функцию отправки программа попадать не должна.
PI2 + MQTT + 5 ESP8266 + Atmega16
-
- Сообщения: 68
- Зарегистрирован: Чт сен 26, 2019 4:14 pm
- Откуда: Ярославль
- Благодарил (а): 19 раз
- Поблагодарили: 6 раз
Re: FAQ ESP8266
Спасибо Вам за ликбез, очень поучительно.ZyaK писал(а): ↑Пт май 29, 2020 3:01 pmА где вы её вызываете то? она у вас обозначена в начале программы и всё, где она вызывается? в лупе о ней нет ни строчки, что происходит внутри функции тоже нигде не написано.
это должно быть организовано на подобии кнопки, в лупе вызываем таймер, если таймер наступил - делаем действия по таймеру, после таймера опрос функций обработчиков входных пинов, в функции опрашивается состояние пина если высокий - ничего не делаем, выходим из функции, если упал на 0, проверяем еще раз через 10 миллисекунд (защита от дребезга) если высокий - ничего не делаем и выходим из функции, если 0 -> обрабатываем срабатывание датчика движения кричим, орем, мигаем светодиодом или там данные на сервер передаём - выходим из обработчика функции -> дальше крутимся по бесконечному циклу, проверяем таймер, опять опрашиваем состояния входных пинов
так же можно добавить таймер и еще одну переменную что бы не опрашивать несколько сотен раз в секунду уже включенный датчик движения, а то при каждом заходе в функцию пока датчик включен будут на сервер лететь пакеты которые и так уже нафиг не нужны. называется "Флаг срабатывания" когда датчик отключился, соответственно пин стал опять в высокий уровень, флаг сбрасывается в 0. при следующем срабатывании датчика флаг выставляется в 1 после отправки данных и больше в функцию отправки программа попадать не должна.
Я далеко не специалист конечно, но подскажите пожалуйста, да действительно данная функция пока ничего не делает кроме как пишет в монитор сообщение, но если я правильно разобрался то она вызывается сам когда происходит прерывание на контакте, так как флаг стоит RISING то прерывание вызывается (а значит и функция) только когда на пине происходит смена с LOW на HIGH, а значит есть сработка датчика.
Или я не прав в своих рассуждениях и не верно понял смысл прерывания?
-
- Сообщения: 407
- Зарегистрирован: Вт окт 24, 2017 2:01 pm
- Откуда: Ижевск
- Благодарил (а): 45 раз
- Поблагодарили: 69 раз
Re: FAQ ESP8266
прерывания это очень хорошо, но в данном случае его использовать нет смысла, лучше завести функцию опроса. Если по каким то причинам будет на пине дребезг или помехи, встанет вся программа и заспамит сообщениями.
PI2 + MQTT + 5 ESP8266 + Atmega16
-
- Сообщения: 68
- Зарегистрирован: Чт сен 26, 2019 4:14 pm
- Откуда: Ярославль
- Благодарил (а): 19 раз
- Поблагодарили: 6 раз
Re: FAQ ESP8266
У прерывания как я понял есть и недостатки, а именно не возможность использования функций задержки которые в основном применяются для программного устранения дребезка контактов, поэтому в этом случае я с вами согласен, но без ответа на вопрос: Верно или нет Я понял принцип работы прерывания ? - я не могу двигаться дальше.
Например для датчиков окна - простых герконов, я хочу применить именно прерывание, а дребезг подавить RC - фильтрами на уровне железа.
-
- Сообщения: 407
- Зарегистрирован: Вт окт 24, 2017 2:01 pm
- Откуда: Ижевск
- Благодарил (а): 45 раз
- Поблагодарили: 69 раз
Re: FAQ ESP8266
Сам смысл прерывания это экстренно при возникновении события забить хрен на всю программу в плоть до прекращения принятий сообщений по интерфейсам (uart, i2c, spi) с целью обработки прерывания, именно по этому код в прерывании должен быть очень коротким(ставим флаг и быстро сваливаем, что бы не мешать основной программе, а потом уже где то в программе проверяется флаг и выполняются какие то действия) естественно никакие делеи там не допустимы (да и в целом по программе делеи не желательно ставить, т.к. Делей это та же функция с бесконечным циклом внутри и пока он идёт - программа стоит на месте и ждет пока кончится делей) то есть это необходимо для моментального реагирования, в случае с датчиками движения или герконами такой необходимости нет. Это как использовать мощный микропроцессор АРМовский с целью моргать светодиодом.
Но смысл поняли правильно.
Дальше двигаться необходимо в сторону создания функций обработки датчиков и обработки входов и вызывать эти функции в лупе.
так же необходимо глянуть в даташит, возможность вызова прерываний есть далеко не у каждой ноги контроллера, например у Атмеги 8 если память не изменяет этих ног всего 3
Но смысл поняли правильно.
Дальше двигаться необходимо в сторону создания функций обработки датчиков и обработки входов и вызывать эти функции в лупе.
так же необходимо глянуть в даташит, возможность вызова прерываний есть далеко не у каждой ноги контроллера, например у Атмеги 8 если память не изменяет этих ног всего 3
PI2 + MQTT + 5 ESP8266 + Atmega16
-
- Сообщения: 68
- Зарегистрирован: Чт сен 26, 2019 4:14 pm
- Откуда: Ярославль
- Благодарил (а): 19 раз
- Поблагодарили: 6 раз
Re: FAQ ESP8266
ZyaK писал(а): ↑Пт май 29, 2020 4:55 pmСам смысл прерывания это экстренно при возникновении забить хрен на всю программу в плоть до прекращения принятий сообщений по интерфейсам с целью обработки прерывания именно по этому код в прерывании должен быть очень коротким(ставим флаг и быстро сваливаем, что бы не мешать основной программе, а потом уже где то в программе проверяется флаг и выполняются какие то действия), то есть это необходимо для моментального реагирования, в случае с датчиками движения или герконами такой необходимости нет. Это как использовать мощный микропроцессор АРМовский с целью моргать светодиодом.
Но смысл поняли правильно.
Дальше двигаться необходимо в сторону создания функций обработки датчиков и обработки входов и вызывать эти функции в лупе.
так же необходимо глянуть в даташит, возможность вызова прерываний есть далеко не у каждой ноги контроллера, например у Атмеги 8 если память не изменяет этих ног всего 3
Спасибо.
Я буду использовать nodemcu V3, как понимаю у нее все GRIO, кроме 16-го поддерживают прерывание.
Конечно железка для таких целей как у меня наверное мощновата, но да ладно.
Цель у меня простая, получить с датчиков данные и отправить их в сервер.
Ниже в коде я постарался (на сколько хватает понимания) учесть ваши замечания.
Не могли бы взглянуть и высказать новые замечания
Код: Выделить всё
// Блок [Подключение библиотек] ************************************************
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <BME280I2C.h>
#include <Wire.h>
// END Блок [Подключение библиотек] ********************************************
// Блок [Подключение к сети WI-FI] *********************************************
const char* ssid = "ХХХХХХХХ"; // Имя WI-FI сети
const char* password = "ХХХХХХХХХХХХ"; // Пароль WI-FI сети
const char* mqtt_server = "192.168.2.3"; // IP адрес MQTT сервер
// END Блок [Подключение к сети WI-FI] *****************************************
#define motionSensorD6 D6 // пин, к которому подключен датчик Движения
#define openSensorD3 D3 // пин, к которому подключен датчик Окна 1
#define openSensorD4 D4 // пин, к которому подключен датчик Окна 2
#define smokeSensorD5 D5 // пин, к которому подключен датчик Дыма
#define Temp_topic "ESP/Temp" // Топик Температуры
#define Humidity_topic "ESP/Humidity" // Топик Влажности
#define Pressure_topic "ESP/Pressure" // Топик Давления
#define motionSensor_topic "ESP/Motion" // Топик датчика движения
#define openSensor_topic1 "ESP/WINDOWS_1" // Топик датчика окна 1
#define openSensor_topic2 "ESP/WINDOWS_2" // Топик датчика окна 2
#define smokeSensor_topic "ESP/SMOKE" // Топик датчика Дыма
WiFiClient espClient;
PubSubClient client(espClient);
BME280I2C bme280;
long last_mls = millis();
long last_mls_temp = millis();
long last_mls_move = millis();
long last_mls_moveOff = millis();
boolean moveOn = false;
boolean Win1On = false;
boolean Win2On = false;
boolean SmokeOn = false;
int Win1Old;
int Win2Old;
int SmokeOld;
char msg[50];
void IRAM_ATTR detectsMovementD6() { // Функция при обнаружении движения на D6
if(int val = digitalRead(motionSensorD6)){
delay(10);
if(int val = digitalRead(motionSensorD6)){
client.publish(motionSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика движения
Serial.println("Движение D6!!!");
moveOn = true;
}
}
}
void IRAM_ATTR detectsOpenD3() { // Функция при обнаружении Открытия окна D3
Win1On = true;
Win1Old = digitalRead(openSensorD3);
}
void IRAM_ATTR detectsOpenD4() { // Функция при обнаружении Открытия окна D4
Win2On = true;
Win2Old = digitalRead(openSensorD4);
}
void IRAM_ATTR detectsSmokeD5() { // Функция при обнаружении движения на D6
SmokeOn = true;
SmokeOld = digitalRead(smokeSensorD5);
}
void setup() {
Serial.begin(115200);
client.setServer(mqtt_server, 1883);
delay(100);
WiFi.begin(ssid, password);
delay(6000);
client.connect("ESP8266Client");
pinMode(motionSensorD6, INPUT_PULLUP); // уставливаем пин D6 на прием и включаем внутренний подтягивающий резистор
// Первоначальные данные по датчику движения
if(int val = digitalRead(motionSensorD6)){
client.publish(motionSensor_topic, String(val).c_str(), true); // Публикуем состояние датчика движения
Serial.println("Движение D6!!!");
}else{
client.publish(motionSensor_topic, String(val).c_str(), true); // Публикуем состояние датчика движения
Serial.println("Все тихо D6!!!");
}
pinMode(openSensorD3, INPUT_PULLUP); // уставливаем пин D3 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(openSensorD3, detectsOpenD3, CHANGE); // Прерывание для датчика окна запуск функции detectsOpenD3
// Первоначальные данные по датчику окна 1
if(int val = digitalRead(openSensorD3)){
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Открыто окно D3!!!");
}else{
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Закрыто окно D3!!!");
}
pinMode(openSensorD4, INPUT_PULLUP); // уставливаем пин D4 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(openSensorD4, detectsOpenD4, CHANGE); // Прерывание для датчика окна запуск функции detectsOpenD4
// Первоначальные данные по датчику окна 2
if(int val = digitalRead(openSensorD4)){
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Открыто окно D4!!!");
}else{
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Закрыто окно D4!!!");
}
pinMode(smokeSensorD5, INPUT_PULLUP); // уставливаем пин D6 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(smokeSensorD5, detectsSmokeD5, CHANGE); // Прерывание для датчика движения запуск функции detectsMovementD6
// Первоначальные данные по датчика дыма
if(int val = digitalRead(smokeSensorD5)){
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Пожар D5!!!");
}else{
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Дыма нет D5!!!");
}
Wire.begin();
while(!bme280.begin())
{
Serial.println("Could not find BME280 sensor 76!");
delay(1000);
}
}
void reconnect_server() {
if (WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("WiFi connect...");
} else {
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("");
}
if(!client.connected() && WiFi.status() == WL_CONNECTED){
if (client.connect("ESP8266Client")) {
Serial.println("Mosquitto connect...");
client.subscribe(motionSensor_topic);
client.subscribe(openSensor_topic1);
client.subscribe(openSensor_topic2);
} else {
Serial.print("failed connect Mosquitto, rc=");
Serial.print(client.state());
Serial.println("");
}
}
}
void IRAM_ATTR ChangeTemp() { // Функция считывания и публикации данных о температуре
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
// Датчик температуры на адресе 0х76
float temp76(NAN), hum76(NAN), pres76(NAN);
bme280.read(pres76,temp76,hum76,tempUnit,presUnit);
Serial.print("Temp76: ");
Serial.print(temp76);
Serial.println("°C");
Serial.print("Humidity76: ");
Serial.print(hum76);
Serial.println("% RH");
Serial.print("Pressure76: ");
Serial.print(pres76*0.00750062,2);
Serial.println(" mmHg");
client.publish(Temp_topic, String(temp76).c_str(), false); // Публикуем температуру
client.publish(Humidity_topic, String(hum76).c_str(), false); // Публикуем влажность
client.publish(Pressure_topic, String(pres76*0.00750062,2).c_str(), false); // Публикуем давление
}
void loop(){
client.loop();
// Блок [Проверка подключения] **********************************************
if (millis() - last_mls > 60000) { // Проверка подключения к сети (раз в 60 сек.)
last_mls = millis();
reconnect_server();
}
// END Блок [Проверка подключения] ******************************************
// Блок [Проверка температуры ] **********************************************
if (millis() - last_mls_temp > 60000) { // Проверка температуры (раз в 60 сек.)
last_mls_temp = millis();
ChangeTemp();
}
// END Блок [Проверка температуры] ******************************************
// Блок [Проверка движения ] **********************************************
if (moveOn = false) { // будем проверять если не зафиксировано сработки датчика
if (millis() - last_mls_move > 3000) { // Проверка датчика движения (раз в 3 сек.)
last_mls_move = millis();
detectsMovementD6();
}
}
if (moveOn = true) { // будем проверять если Зафиксировано сработка датчика
if (millis() - last_mls_moveOff > 15000) { // Проверка (раз в 15 сек.)
last_mls_moveOff = millis();
moveOn=false; // Обнуляем сработку датчика
}
}
// END Блок [Проверка движения] ******************************************
if (Win1On = true) {
delay(10);
if (Win1Old = digitalRead(openSensorD3)){
if(int val = digitalRead(openSensorD3)){
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Открыто окно D3!!!");
}else{
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Закрыто окно D3!!!");
}
Win1Old = digitalRead(openSensorD3);
}
Win1On = false;
}
if (Win2On = true) {
delay(10);
if (Win2Old = digitalRead(openSensorD4)){
if(int val = digitalRead(openSensorD4)){
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Открыто окно D4!!!");
}else{
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Закрыто окно D4!!!");
}
Win2Old = digitalRead(openSensorD4);
}
Win2On = false;
}
if (SmokeOn = true) {
delay(10);
if (SmokeOld = digitalRead(smokeSensorD5)){
if(int val = digitalRead(smokeSensorD5)){
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Пожар D5!!!");
}else{
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Дыма нет D5!!!");
}
SmokeOld = digitalRead(smokeSensorD5);
}
SmokeOn = false;
}