Реализовать два процесса одновременно

Я новичок в arduino, и из-за блокировки я изучаю его, реализуя его на tinkercad. Я сделал симуляцию, к которой прикрепил:

  1. Серводвигатель

  2. Ультразвуковой датчик

  3. Светодиодная лампа

  4. ЖК-дисплей

к Arduino Uno 3

Моя цель: когда что-то падает на расстояние менее 30 см от ультразвукового датчика, серводвигатель запускается из нулевого положения и достигает 180 градусов за 20 секунд, а затем возвращается в исходное положение. При этом и светодиод загорается на 20 с и гаснет, когда двигатель возвращается в исходное положение. Мне удалось это успешно реализовать. Но затем я добавил ЖК-дисплей, чтобы показать время, т.е. время инициализируется с 0 секунд, а затем переходит к 20 секундам и когда двигатель сбрасывается. Время также сбрасывается.

Мне удалось создать таймер в другой симуляции, и я попытался запустить его в этой, правильно разместив код, но не могу понять, как это сделать?

Настоящий код, который я написал, продолжает мигать светодиодом с интервалом в одну секунду, а сервопривод движется очень-очень медленно.

Любая помощь будет замечательной.

Это моя симуляция, я сделал ее общедоступной, вы можете скопировать и смоделировать ее, если у вас есть учетная запись tinkercad. . Даже без учетной записи вы можете увидеть, как это выглядит.

Вот код: (Пожалуйста, спросите, хотите ли вы, чтобы я добавил комментарии к некоторым областям)

//код библиотеки для LCD
#include <LiquidCrystal.h>
//установка пинов
const int rs = 9, en = 8, d4 = 5, d5 = 4, d6 = 3, d7 = 2;

// инициализируем библиотеку номерами выводов интерфейса
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);


unsigned long readTime=20; 



//серводвигатель
#include <Servo.h>
Servo servo_9;
int pos = 0;
//конец серводвигателя

//контакт ультразвукового датчика
const int pingPin = 12;

// ЖК
signed short seconds;
char timeline[16];

void setup()
{
  
  servo_9.attach(13); // сервопривод
  Serial.begin(9600);
  
  pinMode(11,OUTPUT);// светодиод
  
  // инициализация ЖК-дисплея
  lcd.begin(16, 2);
  lcd.print("Time : ");

}

void loop()
{
  
  long duration, cm;
  //Ультразвуковой запуск
  // PING))) запускается ВЫСОКИМ импульсом продолжительностью 2 или более микросекунд.
  // Заранее подайте короткий НИЗКИЙ импульс, чтобы обеспечить чистый ВЫСОКИЙ импульс:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // Этот же пин используется для считывания сигнала от PING))): HIGH
  // импульс, длительность которого равна времени (в микросекундах) с момента отправки
  // от пинга до приема его эха от объекта.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // конвертируем время в расстояние
  cm = microsecondsToCentimeters(duration);

  // Печатаем расстояние
  Serial.print("Distance: ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  // ультразвуковой конец
  
  
  // серводвигатель должен активироваться, когда объект
  //менее 30 см рядом с датчиком
  
 if(cm < 30) {
   
  // поворачиваем сервопривод от 0 до 180 градусов пошагово
  // 1 градус
  for (pos = 0; pos <= 180; pos += 1) {
    
    // сообщаем сервоприводу перейти в позицию в переменной 'pos'
    servo_9.write(pos); 

     //ЗАПУСК ЖК-ТАЙМЕРА
    lcd.setCursor(0, 1);
    sprintf(timeline,"%0.2d secs", seconds);
    lcd.print(timeline);
    delay(1000);
    seconds++;


    //светодиод включается
    digitalWrite(11,HIGH);

    // ждем 20 мс, пока сервопривод не достигнет позиции
    delay(200);

    // выключатель лампочки
    digitalWrite(11,LOW);

     
  }
   
  
  //перемещение сервопривода обратно в ноль
  for (pos = 180; pos >= 0; pos -= 1) {
      // сообщаем сервоприводу перейти в позицию в переменной 'pos'
      servo_9.write(pos);
      // ждем 20 мс, пока сервопривод не достигнет позиции
      delay(20); // Ждем 15 миллисекунд(ы)
            }
  
    } //если конец
 
  
  delay(100);


}//конец цикла


//ФУНКЦИИ

long microsecondsToCentimeters(long microseconds) {
  // Скорость звука 340 м/с или 29 микросекунд на сантиметр.
  // Пинг проходит туда и обратно, поэтому, чтобы найти расстояние
  // объект берем половину пройденного пути.
  return microseconds / 29 / 2;
}


, 👍1

Обсуждение

Эта программа тратит большую часть своего времени на выполнение функции delay(), которая не выполняет никакой полезной работы. Изучите учебник [Blink Without Delay](https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay) Arduino и посмотрите, ответит ли он на ваш вопрос., @Edgar Bonet

Сервопривод движется с запрограммированной вами скоростью. (И между ходами есть задержки.) И не думайте о «множественных процессах». Это проще, и у вас нет операционной системы на uno., @DataFiddler

@ЭдгарБонет, спасибо. Я это проверю, @zibbyboo

@DataFiddler хорошо, конечно. Спасибо за руководство!!, @zibbyboo


1 ответ


Лучший ответ:

7

Думайте об Arduino как о цирковом клоуне, вращающем пластины. Ему приходится тратить очень мало времени на одну тарелку, а затем он может заставить вращаться множество тарелок, быстро перемещаясь от одной к другой.

Вот как "многозадачность" работает на устройстве реального времени, таком как Arduino. Вы пишете циклическую функцию, которая проходит через кучу подзадач, тратя на каждую несколько микросекунд, а затем повторяет процесс. Каждая тарелка (подзадача) получает немного времени при каждом проходе, но совсем немного.

Функция delay() — это смерть. Если вы находитесь в режиме delay(), все резко останавливается. Ваша программа перестает проверять нажатия кнопок, перестает переключать выходные контакты для управления вашими двигателями и т. д. Это похоже на клоуна, который делает перерыв на кофе. Плиты начинают падать на землю.

Вы можете обойтись одноразрядными задержками для таких вещей, как изменение времени в состоянии вывода (и delayMicroseconds() редко вызывает проблемы, поскольку эти задержки очень короткие), но delay (1000) означает, что все резко останавливается на целую секунду.

Вам необходимо реорганизовать код, чтобы избавиться от вызовов delay() со значениями задержки более нескольких миллисекунд. Выполните поиск по запросу «Arduino мигает без задержки». чтобы понять как.

Обратите внимание, что на одноядерном устройстве с вытесняющей многозадачностью аналогия с цирковым клоуном по-прежнему актуальна, но теперь ОС выступает в роли менеджера клоуна. ОС планирует время клоуна и сообщает ему, когда переключаться между тарелками. Если клоун отвлекается на особенно блестящую тарелку и пытается провести с ней слишком много времени, ОС заставляет клоуна поменять тарелку. ОС также сохраняет текущее состояние клоуна каждый раз, когда он переключается с задачи, и восстанавливает это состояние, когда возвращается к этой задаче.

На многоядерном устройстве с вытесняющей многозадачностью у менеджера (ОС) есть команда клоунов (ядер). Каждому клоуну (ядру) назначают разные пластины (задачи), и все клоуны работают одновременно (ядра работают одновременно). в ту же память или другие ресурсы.)

,

Большое спасибо за ответ. Это многое проясняет для меня, поскольку я здесь новичок, и позволяет лучше понять работу Arduino., @zibbyboo

проголосуйте за лучшую аналогию многозадачности, которую я когда-либо видел ... цирковое представление с вращающейся тарелкой может на самом деле быть чем-то, что видели почти все, @jsotola

Лучшая аналогия, которую я когда-либо слышал для циклов Arduino. Я создал учетную запись здесь, чтобы проголосовать за нее .., @Tim_Stewart

Еще раз спасибо. Я смог реорганизовать свой код, чтобы заставить его работать после реализации статьи Arduino «Работа без задержки»., @zibbyboo