Реализация задержки через millis в разовой функции.
- Войдите на сайт для отправки комментариев
Ср, 11/03/2020 - 09:46
В голове появилась идея реализации управления контактом посредством aREST и библиотеки EtherCard.
Идея такова: Установлена камера, на python написан скрипт-обработчик аналитики, если получено значение 1 (доступ разрешен), то на arduino отправляется строка с GET запроса, которая должна на указанное количество (n) отключить реле или светодиод. Т.к. реле нет, балуюсь со светодиодом. Сразу скажу - скетч нагло скомуниздил и переписал чуток под себя, все работает отлично, НО не знаю как правильно реализовать задержку на указанный период, чтоб не положить контроллер. можно ли попросить совета у форума? Скетч прилагаю.
// Подключение библиотек. #include <EtherCard.h> #include <aREST.h> aREST rest = aREST(); // Статический IP адрес модуля. //static byte myip[] = { 192, 168, 0, 245 }; // IP адрес шлюза по умолчанию. //static byte gwip[] = { 192, 168, 0, 1 }; // Mac-адрес модуля. Должен быть уникальным внутри сети. static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 }; // Буфер приема/передачи TCP/IP. // Значение 350 выбрано и для экономии памяти, и из-за того, что размер выходного буфера aREST одинаков. byte Ethernet::buffer[350]; // Размер буфера приема/передачи TCP/IP. BufferFiller bfill; // Переменные. int pinLed = 3; volatile int n = 0; uint32_t timer = 0; // Функция настройки микросхемы. void setup() { Serial.begin(9600); Serial.println(F("\n[Проверка DHCP]")); Serial.print("MAC: "); for (byte i = 0; i < 6; ++i) { Serial.print(mymac[i], HEX); if (i < 5) Serial.print(':'); } Serial.println(); // По умолчанию Slave Select пин - 10. if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) { Serial.println(F("Failed to acCacess Ethernet controller")); } // Включение статического IP. // Serial.println(F("Setting up DHCP")); // if (!ether.staticSetup()) { // Serial.println(F("Static IP failed")); // } // Включение DHCP. Serial.println(F("Setting up DHCP")); if (!ether.dhcpSetup()) { Serial.println(F("DHCP failed")); } ether.printIp("My IP: ", ether.myip); ether.printIp("Netmask: ", ether.netmask); ether.printIp("GW IP: ", ether.gwip); ether.printIp("DNS IP: ", ether.dnsip); // Назначение функций URL: rest.function("led", led); rest.function("pindelay", pindelay); // Преднастройка GPIO (3): pinMode(pinLed, OUTPUT); // Пин по умолчанию включен: digitalWrite(pinLed, 1); } // Функция, организующая установку задержки по запросу. // В терминале linux: // $ curl http://"IP адрес модуля"/pindelay?mseconds=0 // где 0 - количество миллисекунд. int pindelay(String mseconds) { Serial.print("pindelay: "); if (mseconds.length() != 0) { n = mseconds.toInt(); Serial.println(n); } } // Функция управления пином. // В терминале linux: // $ curl http://"IP адрес модуля"/led?params=1 // где 1 - выполнение условия в функции. int led (String params) { if (params.length() != 0) { digitalWrite(pinLed, 0); //тут нужна задержка на n миллисекунд. digitalWrite(pinLed, 1); } } void loop() { word len = ether.packetReceive(); word pos = ether.packetLoop(len); if (pos) { bfill = ether.tcpOffset(); char *data = (char *) Ethernet::buffer + pos; if (strncmp("GET /", data, 5) != 0) { // Неподдерживаемый метод запроса (POST или другие). bfill.emit_p(PSTR("Unsupported HTTP request.")); } else { // vvvvvv------ REST вручную ------vvvvvv rest.handle_proto(data); char *res = rest.getBuffer(); // Отправка HTTP-заголовка: bfill.emit_p( PSTR("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nPragma: no-cache\r\n\r\n") ); // Отправка результата и обнуление буфера REST: rest.resetBuffer(); rest.reset_status(); // vvvvvv------ REST вручную ------vvvvvv\ } ether.httpServerReply(bfill.position()); // Отправка HTTP ответа. } ether.packetLoop(ether.packetReceive()); }
https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
Увы, у меня не получается вывести задержку разово при вызове функции, потому что я видимо что-то делаю не так, ибо я очень глуп. Не понимаю как поместить задержку в loop, чтоб не было разрывов по времени и чтоб все работало, при этом задержка через millis внутри функции не работает....
В хендлере поднять флаг типа ledActive, ledActivationStartTime = millis(), включить led.
В лупе проверять - если ledActive и заданный интервал прошёл (см. пример про blink w/o delay). то сбросить флаг ledActive и выключить led.
За такую подсказку невероятно огромное спасибо. В программировании я глуп, но вроде понял и почти добился чего хотел. Только вот добился я того, что у меня каждый раз отключает пин заданным значением. Я так понимаю, мне надо что-то добавить? Еще одно условие? Прилагаю скетч того, что вышло.
Засекать время старта нужно в момент активации светодиода, там же где устанавливается flag
В приведённом коде этого нет, зато есть лишняя строка #128
Светодиод активен всегда с момента включения ардуинки и выключается в момент вызова функции.
Если уберу строку #128, то не срабатывает включение светодиода. Если перенести currentMillis = millis(); в функцию, то светодиод при каждом запросе меняет состояние. Хоть вы и говорите так, однако, если я правильно вас понимаю и делаю по вашим словам, то результат отличается.
Если уберу строку #128, то не срабатывает включение светодиода. Если перенести currentMillis = millis(); в функцию, то светодиод при каждом запросе меняет состояние. Хоть вы и говорите так, однако, если я правильно вас понимаю и делаю по вашим словам, то результат отличается.
ОК. Не трогаем REST, начинаем с простого: как определить факт истечения временного промежутка, какие три параметра для этого нужны?
Текущее время, предыдущее значение и интервал?
Текущее время, предыдущее значение и интервал?
Который из этих трех параметров определяет начало течения временного промежутка?
Какой переменной он соответствует в примере "blink w/o delay"?
currentMillis - начало отсчета с момента включения.
interval - интервал, как бы очевидно это ни было
previousMillis - предыдущее значение currentMillis
Ну, то что переменные означают - понятно. Вопрос в том, которая из них определяет начало течения временного промежутка.
ну я так понимаю это должна быть currentMillis?
Вот поэтому у вас всё и включается само по себе.
Чтобы понять, сколько времени прошло, нужно из текущего времени вычесть начальное - так?
В формуле "currentMillis - previousMillis >= interval" где начальное время?
Извиняюсь, но если я правильно понял, вы намекаете что нужна еще 1 переменная?
Нет, я не намекаю. Дело там в одной строке кода, но я хочу, чтобы вы сами поняли, что делаете неправильно.
Ещё один пример: на работу вы пришли в 8, до обеда надо отработать 4 часа. Сейчас 13:00 - уже можно уходить на обед? Как вы это поняли? Прямо вот напишите цифирями условие для if()
if(13 - 8 >= 4)
{
можно на обед
}
Правильно?
Пока правильно.
Теперь сравниваем "if(13 - 8 > 4)" с "currentMillis - previousMillis >= interval" и ещё раз отвечаем на вопрос - какая переменная отражает начальное время работы?
А, это значит что нужно указать previousMillis в момент выполнения функции, так?
bingo.
Только previousMillis назвать понятней - как ledActivationStartTime, например.
Все работает отлично. Спасибо огромное)
И все же появился еще 1 вопрос, не по теме, но мало ли имеется знающий человек. Попробовал порыскать в сети информацию - найти почему-то не смог, хотя наверняка примеры где-то есть. Но не суть. Вопрос такой: можно ли отправлять запрос 1 строкой сразу? Чтоб в одной строке сразу и параметр для пина и задержку отправлять. А то я не сильно сведущий человек в этом, хотелось бы хоть пример кода для наглядности и куда копать. Или лучше новую тему с таким вопросом открыть?
index.php?led=1&time=1230&color=black
Т.е. нужен обработчик в php? Или я опять не понимаю вас?))
Нужно передавать запрос такого вида. Как вы там к ардуине обращаетесь (URI) ? Вот приделайте к данному запросу "переменные" в таком формате.