Как сделать очень долгую функцию delay(), несколько часов
Я пытаюсь сделать открывающуюся и закрывающуюся дверцу, которая должна открываться и закрываться каждые 12 часов. Мне было интересно, могу ли я просто сделать небольшой зацикленный скрипт с задержкой delay() на 12 часов, delay(43 200 000 000); Наверное? Однако я понятия не имею, возможно ли это и/или рекомендуется. Неплохие отзывы/альтернативы (при необходимости) :)
@Fred Pannekoek, 👍9
Обсуждение6 ответов
Лучший ответ:
Метод часов реального времени является наиболее точным, но в остальном используется миллис
unsigned long startMillis = millis();
while (millis() - startMillis < LONG_DELAY_MS);
Это задержит прибл. 4294967295 мс (2^32-1) или 49 дней, после чего таймер догонит значение startMillis
Что плохого в простом использовании delay(LONG_DELAY_MS)
? [Реализация Arduino](https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/wiring.c#L109-119) принимает длинные значения без знака. Я также не совсем уверен, что ваш код работает правильно, когда millis()
зацикливается и меньше, чем startMillis
, @Gerben
Если я прав, задержка делает ваш Arduino полностью неактивным во время ожидания. Я не знаю, как это будет действовать, когда миллис вернется к 0., @Fred Pannekoek
@Gerben, хорошие вещи, поставь это как ответ!, @geometrikal
Переполнение @FredPannekoek будет работать нормально, если используется *unsigned* long., @geometrikal
Итак, вы хотите, чтобы прерывания происходили каждую мс в течение 12 часов? Почему бы просто не перевести контроллер в спящий режим на 12 часов?, @23ars
@23ars Как ты собираешься будить контроллер ровно через 12 часов? Самым элегантным решением является внешний RTC с будильником на 12 часов., @geometrikal
взгляните на ответ Рикардо. Или, если вам не нужен сторожевой таймер и спящий режим, решением может быть установка таймеров на генерацию прерывания каждую секунду (TIMERX_COMPA) и отсчет секунд, а не миллис. с миллисом вы генерируете прерывание каждую мс, и это не совсем нормально. Даже если это Arduino, я как-то против использования функций из библиотек, типа millis и других., @23ars
@23ars Основная причина успеха Arduino — это простая в использовании библиотека аппаратных абстракций. Если вы против функций из библиотек, вы несколько ограничиваете себя. В любом случае, функция комментариев — улучшить ответ. Если у вас есть лучшее решение, напишите свой ответ. ;), @geometrikal
@Gerben: Почему вы говорите, что реализация Arduino принимает беззнаковые длинные значения? В справочнике Arduino указано, что аргумент для задержки() должен быть беззнаковым целым числом. (Ваша ссылка на «реализацию Arduino» больше не работает)., @PimV
Обновленная ссылка @PimV: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring.c#L106. [Справочный веб-сайт Arduino](https://www.arduino.cc/reference/en/language/functions/time/delay/) также сообщает, что delay
принимает unsigned long
. Поэтому я не уверен, о какой ссылке вы говорите, где говорится, что это должно быть беззнаковое целое число., @Gerben
@Гербен: Спасибо. Прошу прощения, вы правы. Не могу найти обратно, наверное носом смотрел., @PimV
Есть ли у вас спящий режим (целые числа без знака в секундах)?
В противном случае это позволит вам задерживать() очень долго:
for (unsigned int bigloop=0; bigloop<65535; bigloop++)
{
for (unsigned int smallloop=0; smallloop<65535; smallloop++)
{
for (unsigned int tinyloop=0; tinyloop<65535; tinyloop++)
{
delay(65535);
}
}
}
Я мог бы попробовать это, если мне не удастся получить rtc, как сказал Том. Спасибо за помощь!, @Fred Pannekoek
delay()
есть свое применение, но для длительных задержек это бесполезно. Он просто говорит микроконтроллеру ничего не делать в течение x
тактов. В это время ваш Arduino больше ничего не может делать.
Лучше всего использовать часы реального времени (RTC). Эти чипы специально созданы для отслеживания времени, и вы можете легко подключить их к Arduino. Вот пример того, как это можно сделать.
+1 — Решение RTC особенно хорошо, если вам нужна большая точность, чем может дать MCU., @Ricardo
@Ricardo - RTC вряд ли будет более точным, чем MCU с тактовым кристаллом, использующим один из своих аппаратных таймеров для запуска периодического прерывания; обычно он дает вам отслеживание потери мощности и, возможно, некоторое знание календарных схем., @Chris Stratton
Afaik Uno не использует кварцевый бит и керамический резонатор для своих часов, поэтому точность гораздо меньшая, чем у RTC., @jfpoilpret
@ChrisStratton - Верно. Дело принято. RTC будет гораздо лучшим вариантом, если ОП придется открывать или закрывать дверь в определенное время суток., @Ricardo
Вы можете использовать прерывание сторожевого таймера, чтобы MCU засыпал во время ожидания и экономил энергию.
Но учтите, что вы сэкономите электроэнергию только в том случае, если ваша плата также будет ее экономить. Это означает, что у вас должен быть регулятор низкого напряжения покоя вместо обычных регуляторов, которыми оснащены наиболее распространенные платы Arduino, такие как Uno. В противном случае не имеет значения, экономит ли ваш MCU энергию, если ваша плата этого не делает.
Вот код (непроверенный):
#include <avr/sleep.h>
// Эта переменная делается изменчивой, потому что она изменяется внутри функции прерывания
volatile int sleep_count = 0; // Следите за тем, сколько циклов сна было завершено.
const int interval = 720; // Интервал в минутах между пробуждением и выполнением задач.
const int sleep_total = (interval*60)/8; // Приблизительное количество циклов сна
// необходимо до истечения указанного выше интервала. Не то, чтобы это делало целочисленную математику.
void setup(void) {
watchdogOn(); // Включаем сторожевой таймер.
// Отключите АЦП, установив бит ADEN (бит 7) в ноль.
ADCSRA = ADCSRA & B01111111;
// Отключите аналоговый компаратор, установив бит ACD (бит 7) в единицу.
ACSR = B10000000;
// Отключите буферы цифровых входов на всех аналоговых входных контактах, установив биты 0-5 в единицу.
DIDR0 = DIDR0 | B00111111;
}
void loop(void) {
goToSleep(); // ATmega328 засыпает примерно на 8 секунд
// и продолжает выполнение кода после пробуждения
if (sleep_count == sleep_total) {
// КОД, ВЫПОЛНЯЕМЫЙ ПЕРИОДИЧЕСКИ
}
}
void goToSleep() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Установить спящий режим.
sleep_enable(); // Включить спящий режим.
sleep_mode(); // Входим в спящий режим.
// После пробуждения от сторожевого прерывания выполнение кода продолжается
// для выполнения с этой точки.
sleep_disable(); // Отключаем спящий режим после пробуждения.
}
void watchdogOn() {
// Очистить флаг сброса, бит WDRF (бит 3) MCUSR.
MCUSR = MCUSR & B11110111;
// Установите бит WDCE (бит 4) и бит WDE (бит 3) WDTCSR.
WDTCSR = WDTCSR | B00011000;
// Установите значение предделителя тайм-аута сторожевого таймера на 1024 K
// что даст интервал времени ожидания около 8,0 с.
WDTCSR = B00100001;
// Разрешить прерывание сторожевого таймера.
WDTCSR = WDTCSR | B01000000;
MCUSR = MCUSR & B11110111;
}
ISR(WDT_vect)
{
sleep_count ++; // отслеживать, сколько циклов сна было завершено.
}
Код, который я скопировал, взят с этой страницы: Низкий - Питание Arduino с помощью сторожевого таймера.
Это сработает:
longDelayInSeconds = 120; //пара минут;
while (p < longDelayInSeconds) {
delay(1000);
p++;
}
не лучшее решение, и ОП запросил 12 часов, а не 2 минуты., @Madivad
Я просто использую циклы for, когда не хочу делать промежуточные действия:
for (int Hours = 0; Hours < 12; Hours++) { // Создает 12 часов
for (int Minutes = 0; Minutes < 60; Minutes++) { // Создает 1 час
for (int Seconds = 0; Seconds < 60; Seconds++) { // Создает 1 минуту
delay(1000); // Создает 1 секунду
}
}
}
Ну, для начала было бы проще изменить продолжительность ожидания. Просто измените число для каждого часа, минуты и секунды без необходимости конвертировать в миллисекунды., @GeneCode
- Разница между «time_t» и «DateTime»
- Получение BPM из данного кода
- Создание таймера с использованием часов реального времени с указанием времени начала и остановки
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Генерация стабильной частоты
- Как исправить ошибку компиляции для tone (), используя тот же таймер, что и другая функция
- Использовать timer0, не влияя на millis() и micros().
- Использование timer0 на Arduino Uno
хорошо, я думаю, что задержка имеет максимум 65535 мкс, но теперь мне нужна альтернатива..., @Fred Pannekoek
Синхронизация в более зрелых системах, состоящих только из MCU, обычно выполняется путем программирования канала аппаратного таймера MCU для периодического срабатывания прерывания, а затем их подсчета, что позволяет процессору тем временем заниматься другими делами и в совокупности является таким же точным, как и часовой хрусталь., @Chris Stratton
Использование задержки увеличит очень маленькую служебную ошибку. Лучше использовать прерывание для определения времени заведомо удачного периода, а затем считать оттуда. Вот доказательство концепции на моем личном сайте: http://blog.linformatronics.nl/213/electronics/timed-1-millisecond-interrupt-routine-for-arduino., @jippie
Если это не обязательно должно быть идеально рассчитано по времени, вы можете использовать нетрадиционные вещи, такие как датчик освещенности, чтобы чувствовать утро и вечер., @The Guy with The Hat
да, я думал об этом, однако у меня есть только небольшая часть детектора света, и я не знаю, как защитить ее от непогоды (маленькая дверца снаружи), @Fred Pannekoek
Я хочу 20 минут низкой и 3 минуты высокой структуры программы. у меня есть плата ардуино уно, @Janaka rathnasiri