Как сделать многозадачность?

Ты чего ожидал-то? Готового кода?

хотя бы объяснения более понятного.

1 лайк

Спроси у ChatGPT и отстань уже от людей

1 лайк

ок, понял

Форум не является обучающей площадкой. Или тебе тут курс лекций написать по программированию?

Злые вы все!
Но спасение идет со Св. Земли!!! Покайтесь, грешники! (можно не публично :wink: )

ТС! Изучай значение словосочетания: “неблокирующий код”.
Смысл его в том, что при выполнении кода блокирущий вызов delay() не используется. Вместо этого код переписывается исходя из модели “бесконечного цикла” в котором мы проверяем те или иные события.

ПРИМЕР;
Варим бейца рака (в смятку) (блокирующий):

включитьПлиту(конфорка);
налитьВоду (ковшик);
поставитьНагревать(ковшик, конфорка);

ПОКА (НЕ кипит (ковшик)  НИЧЕГО_НЕ+ДЕЛАТЬ;
положить(ковшик, яйцо);
нАчало = текущееВремя();
ПОКА (текущееВремя() - нАчало < ВРЕМЯ ВАРКИ_ВСМЯТКУ) НИЧЕГО_НЕ_ДЕЛАТЬ;
достать(ковшик.яйцо);

всякие моменты про окатить холодной водой и варить в соленой воде - всё это чтобы чистилось легко - опустим.
Где блокировки: в двух местах - ожидание кипения и сама варка. Первая неизвестное время, вторая известное.
Код называется БЛОКИРУЮЩИМ, если при его выполнении есть такие явления.

Перепишем как НЕБЛОКИРУЩИЙ:

//описание состояний
флаг водаЗакипела = ложь;
флаг яйцоCвfрилось = ложь;

включитьПлиту(конфорка);
налитьВоду (ковшик);
поставитьНагревать(ковшик, конфорка);

//бесконечный цикл
ПОКА (2*2 == 4) 
   {
    ЕСЛИ (кипит (ковшик) 
      {
      водаЗакипела = истина;
      положить(ковшик, яйцо);
      нАчало = текущееВремя();
      }
    ЕСЛИ (водаЗакипела)
     {
     
     ЕСЛИ (текущееВремя() - нАчало > ВРЕМЯ ВАРКИ_ВСМЯТКУ И (НЕ яйцоСварилось))   
       {
        достать(ковшик.яйцо);
        яйцоСварилось = Истина:
       }
     }
   }

Смотри, как это работает:
Перед бесконечным циклом мы сделали все подготовления.
В бесконечном цикле мы проверяем на закипание и продолжаем ТОЛЬКО после закипания. Если не кипит, то мы просто продолжаем цикл сначала. Нам НИЧЕГО не мешает в начале цикла сделать еще любые НЕ БЛОКИРУЮЩИЕ действия из других задач.

Далее короткое действие положить яйцо в воду и снова неблокирующее ожидание.
Пока ждем 2-3 минуты, чтобы яйцо сварилось мы снова-и-снова-и-снова будем начинать бесконечный цикл с начала и можем там выполнять ЛЮБЫЕ задачи. Потом окажемся в цикле, проверим флаг “водаЗакипела” попадем второй блок и станем проверять флаг “яйцоСварилось” и время варки. Когда сварится поднимем флаг, который позволит нам переходить к следующему блоку.

Эти называется “Машина состояний” и обычно программируют не отдельными флагами, а заводят переменную в которой хранится текущее состояние и проверяют ее при входе в бесконечный цикл. В зависимости от состояния делают нужные действия.
Понятно, что в бесконечном цикле можно вызвать хоть две, хоть три таких машины?
Каждая из них выполняется 1-2 миллисекунды или даже меньше. Это самое важное. Внутри машины не может быть блокирующих вызовов.

лисапеда нету, то и злые…
у меня лисапед есть если что

если допустим кто-то тупой то это блокирующий код полюбому.
И наоборот.

А позавчера Вы были погружены во что?
Имело ли это что то общее с программированием хоть на чем?

на кону вопрос, а нужен ли неблокирующий код, зачем? чтобы висеть не в delay(), а в loop() где она - разумная достаточность

Я так и не нашел, написал ли он хоть чтонить сам?

у меня было так что всё срочное делалось в прерываниях (в основном в таймерном), опрос клавиш то-сё неспешное по входам, а несрочное в фоновой программе: типа там УАРТ и тп, причем с дилеями! ибо они никого не парили тут.

видимо это

я c++ не проходил, а проходил python

Мимо? ))

3 лайка

что мимо?

Шел бы ты, Кирилка, книжки читать. А то так в темноте всю жизнь и проживешь…

1 лайк

На однозалачных системах такое реализуется “тиками”: у тебя есть главный цикл, в котором вызываются функции, по чуть-чуть :slight_smile:

while(!Exit) {
  if (!button1_pressed) {
    led_stripe_tick();
    audio_tick();
 }
...
}

Функции led_stripe_tick() и audio_tick() отвечают за светодиоды и звук, но они отработав, быстро возвращают управление.

Например, так сделана “многозадачность” в Quake1 (в однозадачной DOS)

FreeRTOS поможет). Мигание светодиодом с помощью FreeRTOS и Arduino: схема и программа

Спойлер
#define BUZZER_PIN 12       // Пин для пищалки
#define BUTTON_LED_PIN 2    // Пин кнопки для управления светодиодом
#define BUTTON_BUZZER_PIN 3 // Пин кнопки для управления пищалкой

// Таймеры для задач
unsigned long ledTimer = 0;
unsigned long buzzerTimer = 0;

// Интервалы для светодиода и пищалки
const unsigned long LED_INTERVAL = 500;    // Интервал мигания светодиода (мс)
const unsigned long BUZZER_INTERVAL = 300; // Интервал для звука пищалки (мс)

// Состояния
bool ledEnabled = false;    // Состояние управления светодиодом
bool buzzerEnabled = false; // Состояние управления пищалкой
bool ledState = false;      // Состояние светодиода
bool buzzerState = false;   // Состояние пищалки

void setup() {
    pinMode(LED_PIN, OUTPUT);
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode(BUTTON_LED_PIN, INPUT_PULLUP);    // Кнопка с подтяжкой
    pinMode(BUTTON_BUZZER_PIN, INPUT_PULLUP); // Кнопка с подтяжкой

    digitalWrite(LED_PIN, LOW);
    digitalWrite(BUZZER_PIN, LOW);

    Serial.begin(115200);
}

void loop() {
    handleButton(BUTTON_LED_PIN, ledEnabled);    // Обработка кнопки для светодиода
    handleButton(BUTTON_BUZZER_PIN, buzzerEnabled); // Обработка кнопки для пищалки

    if (ledEnabled) handleLed();      // Управление светодиодом
    if (buzzerEnabled) handleBuzzer(); // Управление пищалкой
}

// Обработка кнопки для управления потоком
void handleButton(int buttonPin, bool &taskEnabled) {
    static unsigned long lastDebounceTime = 0; // Таймер для антидребезга
    const unsigned long DEBOUNCE_DELAY = 50;   // Задержка для антидребезга
    static bool lastButtonState = HIGH;        // Предыдущее состояние кнопки

    bool currentState = digitalRead(buttonPin);

    if (currentState != lastButtonState) {
        lastDebounceTime = millis(); // Обновляем время изменения состояния
    }

    if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
        // Если состояние кнопки изменилось после антидребезга
        if (currentState == LOW && lastButtonState == HIGH) {
            taskEnabled = !taskEnabled; // Переключаем состояние задачи
            Serial.print("Поток ");
            Serial.print(buttonPin == BUTTON_LED_PIN ? "LED" : "BUZZER");
            Serial.println(taskEnabled ? " включен" : " выключен");
            if (!taskEnabled) { // Если поток выключен, выключаем устройство
                if (buttonPin == BUTTON_LED_PIN) digitalWrite(LED_PIN, LOW);
                if (buttonPin == BUTTON_BUZZER_PIN) digitalWrite(BUZZER_PIN, LOW);
            }
        }
    }

    lastButtonState = currentState;
}

// Управление светодиодом
void handleLed() {
    if (millis() - ledTimer >= LED_INTERVAL) {
        ledTimer = millis();
        ledState = !ledState;
        digitalWrite(LED_PIN, ledState);
    }
}

// Управление пищалкой
void handleBuzzer() {
    if (millis() - buzzerTimer >= BUZZER_INTERVAL) {
        buzzerTimer = millis();
        buzzerState = !buzzerState;
        digitalWrite(BUZZER_PIN, buzzerState);
    }
}
Спойлер

Интересно, как скоро мой ЧатГПТ начнет тупеть от подобных заданий?))) И поговорить тогда не с кем будет на философские темы

1 лайк