Виснет ардуино

Тема в разделе "Arduino & Shields", создана пользователем SunMaster, 29 июл 2022.

  1. ИгорьК

    ИгорьК Гуру

    ESP8266 во время delay() обеспечивает работу wifi. В больших циклах рекомендуется вставлять delay(0) как раз для этого.
     
    DetSimen и SergeiL нравится это.
  2. parovoZZ

    parovoZZ Гуру

    там RTOS крутится.
     
  3. SunMaster

    SunMaster Нерд


    интересно, но ничего не понял
     
  4. Asper Daffy

    Asper Daffy Иксперд

    Блин, да с чего?

    Молоток иногда попадает по пальцу - значит он зло и гвозди забивать надо микроскопом, так что ли?

    delay - один из инструментов, который весьма полезен, если использовать его по назначению и правильно.

    А ЗЛО - это "Западное Либеральное Общество".
     
  5. Asper Daffy

    Asper Daffy Иксперд

    См. код delay в #60 и попробуйте объяснить, каким боком delay(0) может хоть на что-то повлиять, если там даже yield ни разу не вызовется?
     
    Feofan и DetSimen нравится это.
  6. ИгорьК

    ИгорьК Гуру

    Джентльмены верят на слово :)

    Речь про ESP8266. И поскольку я пасу этого коня на языке Lua, то про волшебную ардуино на оном камне читал очень давно. Про делай на ESP8266 осталось такое приятное воспоминание.

    Хотите оказаться правым - ковыряйте исходники сами. Сферические кони ждут.
     
  7. SergeiL

    SergeiL Оракул Модератор

    Да это понятно, как и с delay(0) тоже заметил, но руки не дошли написать.
    Если понимать как работает, то можно легко пользоваться. Приведенный пример - тому доказательство.
    Но для начинающих, как мне кажется, вариант сложноватый, проще наверное с millis(), как обычно.
    Пост:
    это подтверждает.
    Я пытался найти для себя сценарии использования, честно говоря только искусственные варианты.
    Хотя с глобальными флагами, чтобы ветвиться после delay(), в зависимости от обработки в yield(), можно придумать.
    Но, как мне кажется, не хватает принудительно окончания delay(), по решению из yield().
     
  8. ИгорьК

    ИгорьК Гуру

    Попробовать перегружать функцию с аргументами типа delay(1000, true, ...)?
     
    SergeiL нравится это.
  9. SergeiL

    SergeiL Оракул Модератор

    Думаю можно в yield() возвращать 0/1 в зависимости от необходимости вывалиться сразу или после окончания интервала.
     
  10. SergeiL

    SergeiL Оракул Модератор

    Подумал на досуге, мне кажется, что вариант с перегрузкой функции, delay(1000, &flag_variable); проще будет.
    Ну и my_yield(uint8_t *ptr) с передачей флага через указатель из основного кода через новый delay(1000, &flag_variable).
    А из yield() вызывается my_yield(NULL), для совместимости.
    Тогда с минимальными потерями можно управлять выходом из delay(xxxx,ptr) в любой момент, а через указатель на флаг передавать причину и необходимое действие.
    Еще можно добавить глобальный флаг состояния для анализа в my_yield(...), чтобы понимать откуда мы туда попали, и что нужно сделать...
    Пример кода:
    Код (C++):
    const int ledPin =  LED_BUILTIN;    // the number of the LED pin
    int ledState = LOW;                 // ledState used to set the LED
    uint32_t previousMillis = 0;        // will store last time LED was updated
    const long interval = 1000;         // interval at which to blink (milliseconds)

    void setup() {                      // set the digital pin as output:
      pinMode(ledPin, OUTPUT);
      Serial.begin(115200);
    }

    void loop()
    {
      uint8_t delay_break_flag = 0;
    //        76543210
    //        ||||||||
    //        |||||||+---  0: brake from delay
    //        ||||||+----  1: Flag 1
    //        |||||+-----  2: Flag 2
    //        ||||+------  3: Flag 3
    //        |||+-------  4: Flag 4
    //        ||+--------  5: Flag 5
    //        |+---------  6: Flag 6
    //        +----------  7: Internal flag "delay start"

      Serial.println("loop_begin------");

      Serial.print("delay(30 000) start: ");
      Serial.println(millis());

      delay(30000);

      Serial.print("delay(30 000) end: ");
      Serial.println(millis());

      Serial.print("delay(60 000) start: ");
      Serial.println(millis());

      delay(600000, &delay_break_flag);

      Serial.print("delay(60 000) end: ");
      Serial.println(millis());

      if (delay_break_flag & 1)
        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)
    {
        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()
    {
      my_yield(NULL);  // вызовем my_yield() с нулевым указателем
    }

    void my_yield(uint8_t *ptr)
    {
      unsigned long currentMillis = millis();
      static int counter = 0;

      if (ptr && *ptr & 0x80)  // это первый вход в my_yield() из delay(ххх,с указателем на флаг) ?
      {
        *ptr = 0;   // сбросим флаг  первого входа
        counter=0;  // проинициализируем переменные
      }
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;

        // if the LED is off turn it on and vice-versa:
        if (ledState == LOW) {
          ledState = HIGH;
          Serial.print("Tic");
        } else {
          ledState = LOW;
          Serial.println("-tac");
          counter++;
        }
        digitalWrite(ledPin, ledState);
      }
      if (counter == 10)
      {
        counter=0;
        if (ptr)                      // тут для примера, переписываем в зависимости от условий и статуса...
          *ptr |= (uint8_t) 1;
          *ptr |= (uint8_t) 2;
      }
    }
    В симуляторе
     
    ИгорьК нравится это.
  11. ИгорьК

    ИгорьК Гуру

    Ну я то думал не больше совы из анекдота про мышей/ежей :)
     
  12. Unixon

    Unixon Оракул Модератор

    Библиотеки для I2C/1wire тоже нужно проверить, там скорее всего есть бесконечные циклы ожидания событий и настраиваемые таймауты не предусмотрены, как и в библиотеках для периферии. Чтобы нормальный неблокирующий код получился придется почти все переписать в формате конечных автоматов.