Функция запуска при срабатывании
Я пытаюсь создать устройство, реагирующее на движение/падение. У меня есть датчик, который постоянно проверяет, обнаружено ли движение и падение в voidloop()
. Если обнаружено и движение, и падение, я хотел бы отправить изображение на свой компьютер. Моя функция захвата изображений — camCapture()
. Проблема в том, что после обнаружения движения и падения он постоянно вызывает camCapture()
и неоднократно отправляет изображения на компьютер, учитывая, что camCapture()
вызывается в void цикл()
. Я хотел бы отправлять только одно изображение при его запуске и одно изображение каждый раз, когда оно срабатывает в дальнейшем.
Например, если срабатывает движение и падение, то отправьте изображение один раз. Если он обнаружит движение и снова упадет после того, как уже вернулся в НИЗКИЙ режим, отправьте изображение еще раз.
Я не могу использовать setup()
, поскольку я могу запустить функцию только один раз, и это противоречит цели того, что я пытаюсь сделать. Мой код voidloop ()
приведен ниже.
void loop()
{
// Читаем данные с акселерометра
mma.read();
sensors_event_t event;
mma.getEvent(&event);
// Сохраняем величину всех осей
magnitude = calculateMagnitude(event.acceleration.x, event.acceleration.y, event.acceleration.z);
// Обнаружено движение! На обнаружение падения с акселерометра будет дано 20 секунд.
if(digitalRead(pirSensor) == HIGH)
{
num_timeAtPIR = millis(); // Время активации PIR-датчика относительно системного времени
bool_waitForAccel = 1; // Установите флаг в значение true, чтобы дождаться сигнала акселерометра
Serial.println("Motion detected!");
digitalWrite(buzzer, LOW);
//задержка(1000);
}
else if(magnitude > sensitivity)
{
num_timeAtAccel = millis();
Serial.println("Fall detected!");
Serial.print("Magnitude is: ");
Serial.println(magnitude);
bool_waitForPIR = 1; // Ожидание PIR
Serial.println();
digitalWrite(buzzer, HIGH);
delay(4000);
}
else // Движение не обнаружено
{
Serial.println("No motion detected! :(");
bool_waitForPIR = 0;
bool_waitForAccel = 0;
Firebase.setInt(firebaseData, pirPath, 0);
Firebase.setInt(firebaseData, accelPath, 0);
digitalWrite(buzzer, LOW);
}
// Обнаружено движение, затем падение. Сигнализация активируется, изображение захватывается и сохраняется на сервере.
if(bool_waitForAccel == 1 && (magnitude > sensitivity))
{
Serial.println("Motion and Fall detected!");
Serial.print("Magnitude is: ");
Serial.println(magnitude);
bool_waitForAccel = 0; // Больше не ждем акселерометра
Serial.println();
digitalWrite(buzzer, HIGH);
delay(4000);
camCapture(); // Сделать фотографию!
}
// Падение, затем обнаружено движение. Сигнализация активируется, и изображение/видео захватывается для сохранения на веб-сайте.
else if(bool_waitForPIR == 1 && (magnitude > sensitivity))
{
Serial.println("Fall detected");
Serial.print("Magnitude is: ");
Serial.println(magnitude);
Serial.println();
bool_waitForPIR = 0; // Больше не ждем PIR
digitalWrite(buzzer, HIGH);
delay(4000);
camCapture(); // Сделать фотографию!
}
// 20-секундный таймер для проверки обнаружения падения после обнаружения движения.
if(millis() > (num_timeAtPIR + period))
{
bool_waitForAccel = 0; // Устанавливаем флаг в значение false
}
else if(millis() > (num_timeAtAccel + period)) // 20-секундный таймер для проверки обнаружения движения после обнаружения падения
{
bool_waitForPIR = 0;
}
}
ОБНОВЛЕНИЕ 1: Публикация остальной части кода.
// Заголовочные файлы программы
#include <Wire.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "FS.h"
#include "FirebaseESP32.h"
#include "memorysaver.h"
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>
//Заголовок NTP-сервера времени и даты
#include <NTPClient.h>
#include <WiFiUdp.h>
//Определяем NTP-клиент для получения времени
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
//Переменные для сохранения даты и времени
String formattedDate = "";
String dayStamp = "";
String timeStamp = "";
String logPath = "/Log";
String tempPath = "/Log/Temperature";
String pirPath = "/Log/PIR_Sensor";
String accelPath = "/Log/Accelerometer";
String pirDatePath = "/Log/pir_Date";
String pirTimePath = "/Log/pir_Time";
String accelDatePath = "/Log/accel_Date";
String accelTimePath = "/Log/accel_Time";
// Конфигурация базы данных/Wi-Fi
#define FIREBASE_HOST "host"
#define FIREBASE_AUTH "auth"
#define AP_SSID "apssid"
#define AP_PASSWORD "password"
#define WIFI_SSID "ssid"
#define WIFI_PASSWORD "passsword"
// Переменные для отслеживания предыдущего и текущего времени для создания задержки
unsigned long currentTime = 0;
unsigned long prevTime = 0;
unsigned long bool_waitForAccel = 0; // Используется для обозначения акселерометра
unsigned long bool_waitForPIR = 0; // Используется для обозначения PIR
unsigned long num_timeAtPIR = 0; // Используется для отслеживания времени, когда PIR-датчик обнаружил движение
unsigned long num_timeAtAccel = 0; // Используется для отслеживания времени, когда акселерометр обнаружил падение
unsigned long period = 20000; // Количество времени, отведенное на проверку после обнаружения движения
int statusLED = 26; // Выбираем контакт для светодиода состояния
int buzzer = 12; // Выберите пин для Пьеццо Зуммера. Подключен от затвора MOSFET.
int tempSensor = 2; // Выбор контакта для датчика температуры
int pirSensor = 27; // Выбор контакта для PIR-датчика контроллера
int PIR_Power = 25; // Управляет силовым входом для PIR-датчика
int ArduCAM_Power = 32; // Управляет силовым вентилем для ArduCAM
const int CS = 5; // GPIO5 как выбор ведомого устройства для ArduCAM
int wifiType = 0; // 0: Станция 1: AP (точка доступа)
// Настраиваем запросы на отправку захваченного изображения на внешний сервер
bool onlineMode = true;
String start_request = "";
String boundary = "_cam_";
String end_request = "\n--" + boundary + "--\n";
// Устанавливаем размер буфера для данных камеры
static const size_t bufferSize = 2048;
static uint8_t buffer[bufferSize] = {0xFF};
byte buf[256];
static int iPic = 0;
static int kPic = 0;
uint8_t temp = 0, temp_last = 0;
uint32_t len = 0;
bool is_header = false;
// Порог объявления падения по акселерометру
float sensitivity = 11.0;
float magnitude = 0.0; // Сохраняет рассчитанную величину
// Экземпляры акселерометра, семафора и Firebase
Adafruit_MMA8451 mma = Adafruit_MMA8451();
FirebaseData firebaseData;
#if defined (OV2640_MINI_2MP) || defined (OV2640_CAM)
ArduCAM myCAM(OV2640, CS);
#endif
WiFiClient client;
void start_capture()
{
myCAM.clear_fifo_flag();
myCAM.start_capture();
}
void camCapture()
{
digitalWrite(ArduCAM_Power, HIGH);
// Очищаем FIFO
myCAM.flush_fifo();
// Очистить флаг завершения захвата
myCAM.clear_fifo_flag();
// Начинаем захват
myCAM.start_capture();
Serial.println("Start capture!");
while(!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
len = myCAM.read_fifo_length();
Serial.print("The FIFO length is: ");
Serial.println(len);
if(len >= MAX_FIFO_SIZE) // 8M
{
Serial.println("Over size!");
}
if(len == 0) // 0 КБ
{
Serial.println("Size is 0KB");
return;
}
long full_length;
if(client.connect("xx.xx.xx.xx", 80) || onlineMode)
{
if(onlineMode)
{
while(client.available())
{
String line = client.readStringUntil('\r');
}
}
start_request = start_request +
"\n--" + boundary + "\n" +
"Content-Disposition: form-data; name=\"data\"; filename=\"CAM.jpg\"\n" +
"Content-Transfer-Encoding: binary\n\n";
full_length = start_request.length() + len + end_request.length();
client.println("POST /uploads.php HTTP/1.1");
client.println("Host: xx.xx.xx.x");
client.println("Content-Type: multipart/form-data; boundary =" + boundary);
client.print("Content-Length: "); client.println(full_length);
client.println();
client.print(start_request);
iPic = 0;
static uint8_t buffer[bufferSize] = {0xFF};
while (len--)
{
temp_last = temp;
temp = SPI.transfer(0x00);
//Читаем данные JPEG из FIFO
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //Если найден конец, прервать while,
{
buf[iPic++] = temp; //сохраняем последний 0XD9
//Записываем оставшиеся байты в буфер
myCAM.CS_HIGH();
client.write(buf, iPic);
//Закрываем файл
//файл.закрыть();
Serial.println(F("Image save OK."));
is_header = false;
iPic = 0;
}
if (is_header == true)
{
//Записываем данные изображения в буфер, если он не заполнен
if (iPic < 256)
buf[iPic++] = temp;
else
{
//Запись 256-байтовых данных изображения в файл
myCAM.CS_HIGH();
client.write(buf, 256);
iPic = 0;
buf[iPic++] = temp;
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
}
else if ((temp == 0xD8) & (temp_last == 0xFF))
{
is_header = true;
buf[iPic++] = temp_last;
buf[iPic++] = temp;
}
}
// Завершаем POST-запрос к серверу
client.println(end_request);
myCAM.CS_HIGH();
// Остановим клиент
client.stop();
digitalWrite(ArduCAM_Power, LOW);
}
else // Нет соединения с сервером.
{
Serial.println("Could not connect to external server!");
Serial.println("Please check the IP address or Port");
return;
}
}
// Вычисляем величину по осям x, y и z акселерометра.
// Дает общее значение, которое лучше, чем просто использование оси Z
float calculateMagnitude(float x, float y, float z)
{
float magnitude = sqrt(sq(x) + sq(y) + sq(z));
return magnitude;
}
void setup()
{
Wire.begin();
Serial.begin(115200);
SPI.begin();
SPI.setFrequency(4000000);
pinMode(CS, OUTPUT);
pinMode(PIR_Power, OUTPUT); // Устанавливаем затвор МОП-транзистора на выход для PIR-датчика
pinMode(ArduCAM_Power, OUTPUT); // Устанавливаем затвор МОП-транзистора на выход для ArduCAM
pinMode(statusLED, OUTPUT); // Объявляем светодиод как выход
pinMode(buzzer, OUTPUT); // Объявляем пьезо-зуммер как выход
pinMode(pirSensor, INPUT); // Объявляем PIR-датчик как входные данные
Serial.println();
// Проверяем, правильно ли подключен/найден акселерометр
if(!mma.begin())
{
Serial.println("Couldn't start MMA8451 Accelerometer.");
Serial.println("Check your connections.");
while(1);
}
Serial.println("MMA8451 Accelerometer found!");
// Установите диапазон g для акселерометра. Можно настроить на 2 г, 4 г или 8 г.
mma.setRange(MMA8451_RANGE_2_G);
// Проверяем, найдена ли камера
digitalWrite(ArduCAM_Power, HIGH);
uint8_t vid, pid;
uint8_t temp;
while(1)
{
//Проверяем, в порядке ли шина ArduCAM SPI
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
temp = myCAM.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55) {
Serial.println(F("SPI interface Error!"));
delay(2);
continue;
}
else
break;
}
#if defined (OV2640_MINI_2MP) || defined (OV2640_CAM)
//Проверяем, является ли тип модуля камеры OV2640
myCAM.wrSensorReg8_8(0xff, 0x01);
myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 )))
Serial.println(F("Can't find OV2640 module!"));
else
Serial.println(F("OV2640 detected."));
#endif
//Переходим в режим захвата JPEG и инициализируем модуль OV2640
myCAM.set_format(JPEG);
myCAM.InitCAM();
myCAM.OV2640_set_JPEG_size(OV2640_640x480);
myCAM.clear_fifo_flag();
// Выключаем камеру
digitalWrite(ArduCAM_Power, LOW);
// Подключаемся к Wi-Fi
if (wifiType == 0)
{
if(!strcmp(WIFI_SSID,"SSID"))
{
Serial.println(F("Please set your SSID"));
while(1);
}
if(!strcmp(WIFI_PASSWORD,"PASSWORD"))
{
Serial.println(F("Please set your PASSWORD"));
while(1);
}
// Подключаемся к сети Wi-Fi
Serial.println();
Serial.print(F("Connecting to: "));
Serial.println(WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected"));
Serial.println();
Serial.println(WiFi.localIP());
}
else if (wifiType == 1)
{
Serial.println();
Serial.println();
Serial.print(F("Shared AP: "));
Serial.println(AP_SSID);
Serial.print(F("The password is: "));
Serial.println(AP_PASSWORD);
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
Serial.println();
Serial.print("AP IP Address is: ");
Serial.println(WiFi.softAPIP());
}
// Инициализируем NTPClient, чтобы получить время
timeClient.begin();
timeClient.setTimeOffset(-14400);
//Если Firebase подключен, включаем светодиод
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
digitalWrite(statusLED,HIGH);
Serial.println("------------------------------------");
Serial.println("Path exist test...");
if (Firebase.pathExist(firebaseData, logPath))
{
Serial.println("Path " + logPath + " exists");
}
else
{
Serial.println("Path " + logPath + " does not exist");
Serial.println("Adding all necessary paths to /Log");
Serial.println("Will have to reinitialize later once everything is set up.");
// Инициализируем все переменные значением 0;
Firebase.setFloat(firebaseData, tempPath, 0.0);
Firebase.setInt(firebaseData, pirPath, 0);
Firebase.setInt(firebaseData, accelPath, 0);
//Firebase.setString(firebaseData, pirDatePath, ???);
//Firebase.setString(firebaseData, pirTimePath, ???);
//Firebase.setString(firebaseData, accelDatePath, ???);
//Firebase.setString(firebaseData, accelTimePath, ???);
}
Serial.println("------------------------------------");
Serial.println();
digitalWrite(PIR_Power, HIGH);
digitalWrite(pirSensor, LOW);
digitalWrite(statusLED, LOW);
Serial.println("Sensors booting up...");
delay(10000); // Даем сенсорам загрузиться, 10 с
Serial.println("Sensors ready!");
}
@fern132, 👍0
Обсуждение1 ответ
Лучший ответ:
Вам необходимо добавить переменную состояния в функцию loop()
.
В начале loop()
добавьте объявление переменной, например:
void loop()
{
static bool capture_sent = false;
Тогда измените свою линию
if(bool_waitForAccel == 1 && (magnitude > sensitivity))
{
в
if(!capture_sent && bool_waitForAccel == 1 && (magnitude > sensitivity))
{
capture_sent = true;
или, если вы хотите выполнить часть логики в этом разделе и просто не вызывать camCapture()
, оставьте строку if
в покое и выполните вызов
code>camCapture() при условии !capture_sent
.
Затем в любом месте вашего кода, где вы видите условие, которое говорит о том, что вы хотите снова вызвать camCapture()
при срабатывании, сбросьте capture_sent
на `false . Я оставляю вам право решать, куда это пойдет, потому что вы понимаете, какие условия это определяют.
Потрясающий! Спасибо за ответ! Утром я внесу эти изменения и сообщу вам, как все пройдет., @fern132
- Esp8266 Vin контакт
- esp32 Stack canary watchpoint срабатывает
- ESP32 millis не работает должным образом
- esp32 http client response только 200 не получил данные после этого
- Может ли ESP 32 использовать библиотеку проводов точно так же, как это было в Arduino?
- Adafruit esp32 Feather не удалось скомпилировать
- Как отправить пакет данных UDP между двумя точками доступа?
- Сработал детектор отключения питания
Спасибо за очень хорошее форматирование. Так много людей публикуют вопросы в совершенно дерьмовом формате, из-за чего вопрос становится очень трудным для чтения и понимания., @romkey
@JohnRomkey Ха-ха! Спасибо, мне нужно как-то облегчить всем жизнь., @fern132