#define LED_PIN LED_BUILTIN // пин встроенного светодиода
#define BLINK_INTERVAL 1000 // чачтота мигания
void setup() { // начальное состояние встроенного светодиода
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
}
void loop()
{
uint8_t delay_break_flag = 0; // внутренний флаг для delay с выходом, нужно вынести в глобальные переменные, если используется не только в loop()
// 76543210
// ||||||||
// |||||||+--- 0: произошел выход из delay() не дождавшись окончания интервала
// ||||||+---- 1: Flag 1
// |||||+----- 2: Flag 2
// ||||+------ 3: Flag 3
// |||+------- 4: Flag 4
// ||+-------- 5: Flag 5
// |+--------- 6: Flag 6
// +---------- 7: внутренний флаг для передачи в my_yield, что delay стартовала, можно проинициализировать какие то переменные
Serial.println("loop_begin------");
Serial.print("delay(30 000) start: ");
Serial.println(millis());
delay(30000); // обычный delay() на 30сек но блокировки не происходит, светодиод моргает
Serial.print("delay(30 000) end: ");
Serial.println(millis());
Serial.print("delay(60 000) start: ");
Serial.println(millis());
delay(600000, &delay_break_flag); // delay() с возможностью выти из него недожидаясь окончания интервала по какому то событию
Serial.print("delay(60 000) end: ");
Serial.println(millis());
if (delay_break_flag & 1) // если вышли из delay() раньше времени
Serial.println("Delay break");
if (delay_break_flag & 2) // обработчиком событий был взведен какой то флаг например смены стсояния. состояние смотрим в глобальной переменной, ее в примере нет
Serial.println("Flag detected");
Serial.println("loop_end--------\n");
}
void delay(uint32_t ms, uint8_t *ptr) // собственно чуть подправленный delay с возможностью прерывания
{
uint32_t start = micros();
if (ptr) // усли тлько зашли в new delay()
*ptr = 0x80; // взведем флаг начала delay()
while (ms > 0) {
my_yield(ptr);
if (ptr && *ptr & 1) // взведен флаг выхода из delay в my_yield()
break;
while ( ms > 0 && (micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
void yield() // если кто то вызвал yeld (не новый delay) вызываем my_yield() с нулевым указателем в параметре
{
my_yield(NULL); // вызовем my_yield() с нулевым указателем
}
void my_yield(uint8_t *ptr)
{
uint16_t currentMillis = (uint16_t) (millis() & 0xFFFFL); // у меня короткие интервалы
static uint16_t previousMillis = 0; // время последнего обновления состояния сетодиода - мигания
static int counter = 0;
static uint8_t ledState = LOW; // состояние светодиода
if (ptr && *ptr & 0x80) // это первый вход в my_yield() из delay(ххх,с указателем на флаг)(можно проинициализировать какие то внутренние переменные - например счетчик counter=0;
{
*ptr = 0; // сбросим флаг первого входа
counter=0; // проинициализируем переменные
}
if (currentMillis - previousMillis >= BLINK_INTERVAL) // --------------------------обработка каких то событий
{
previousMillis = currentMillis;
// мигаем светодиодом, счтаем мигания для примера
ledState =! ledState;
if (ledState == HIGH) {
Serial.print("Tic");
} else {
Serial.println("-tac");
counter++;
}
digitalWrite(LED_PIN, ledState);
if (counter == 10) // на 10 мигании
{
counter=0; // сбросим счетчик
if (ptr) // если указатель не нулевой, попали из delay с выходом
*ptr |= (uint8_t) 1; // взведем флаг выхода
*ptr |= (uint8_t) 2; // для примера взведем флаг изменения состояния, состояние передаем через глобальную переменную
}
} // --------------------------обработка каких то событий
}