Проблема с измерением времени в цикле for

Я знаком с определением времени с помощью функции millis(), но, похоже, столкнулся с проблемой цикла for. Дело в том, что я сравниваю показания энкодера со значением, введенным с клавиатуры 4x4. Поскольку мне нужно ввести более одного значения, я поместил все значения с клавиатуры в массив. Затем я создал цикл for, который будет проходить по этому массиву и сравнивать каждое значение с показаниями энкодера, когда энкодер достигает введенного значения с клавиатуры, светодиод должен загореться на 2 секунды. Вот где возникает проблема. Когда он достигает установленного значения, светодиод загорается на долю секунды. Я предполагаю, что петля создает здесь некоторые проблемы. Может быть, потому что петля работает так быстро, что светодиоду не хватает времени, чтобы гореть постоянно. Как вы думаете?

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

Пожалуйста, спросите, нужны ли вам какие-либо разъяснения кода, и заранее спасибо

#include <Encoder.h>
#include<Wire.h>
#include<LiquidCrystal_I2C.h>

int led1=14;
int led2=15;
unsigned long encoder;
unsigned long prev_value;
int array1[]={100, 200, 300, 400, 500, 600};
int array2[]={150, 250, 420};
int i,j,k,l;
int brV=6;
int brM=3;
int tolerance=10;
unsigned long oldTime=0.0;
unsigned long newTime;
int dt=2000;
bool testRange=true;
bool testRange2=true;

Encoder myEnc(2,3);
LiquidCrystal_I2C lcd1(0x27, 16, 2);


void setup() {
pinMode(led1,OUTPUT);
pinMode(led2,OUTPUT);
lcd1.init();
lcd1.backlight();
}

void loop() {
  newTime=millis();
  lcd1.setCursor(0,0);
  encoder=myEnc.read()*446/400;
  if(encoder!=prev_value){
    lcd1.clear();
    delay(10);
    prev_value=encoder;
  }
  lcd1.print(encoder);
  digitalWrite(led1,LOW);
  digitalWrite(led2,LOW);

  k=brV+brM;

  for(l=0;l<k;l++){
     for(i=0;i<brV;i++){
        if(encoder>=array1[i] && encoder<=(array1[i]+tolerance) && testRange){
           oldTime=newTime;
           digitalWrite(led1,HIGH);
           testRange=false;
         }
         else if(oldTime-newTime >= dt){
          oldTime=newTime;
          digitalWrite(led1,LOW);
         }
         if(encoder>(array1[i]+tolerance){
          testRange=true;
         }
     }
      for(j=0;j<brM;j++){
         if(encoder>=array2[j] && encoder<=(array2[j]+tolerance) && testRange2){
           oldTime=newTime;
           digitalWrite(led2,HIGH);
           testRange2=false;
         }
         else if(newTime-oldTime >= dt){
          oldTime=newTime;
          digitalWrite(led2,LOW);
         }
         if(encoder>array2[j]+tolerance){
          testRange2=true;
         }
      }
  }


  }

, 👍0

Обсуждение

как вы думаете, сколько времени потребуется для выполнения циклов for, пока светодиод не выключится в цикле ()?, @Juraj

Я предполагаю, что выполнение цикла for занимает пару миллисекунд., @Andrija Erovic

Я думаю, что это меньше миллисекунды, и именно столько времени горит светодиод. плюс ЖК-код, @Juraj

Может ли проблема быть решена, если я использую прерывания по таймеру?, @Andrija Erovic

что еще может произойти за 2 секунды, пока горит светодиод?, @Juraj

Эта программа предназначена только для тестирования. В основной программе будет еще один светодиод, который будет гореть все время, но выключится на эти 2 секунды, и снова включится, когда пройдет 2 секунды, @Andrija Erovic

переместите обработку тайм-аута светодиода из циклов for прямо в loop(), @Juraj

Но светодиод должен загораться только тогда, когда значение энкодера больше, чем array[i] . Будет ли программа знать, когда включить светодиод?, @Andrija Erovic


2 ответа


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

0

в цикле() заменить

digitalWrite(led1,LOW);

с

if (newTime - oldTime >= dt){
   digitalWrite(led1,LOW);
}

и вы можете удалить

else if(oldTime-newTime >= dt){
   oldTime=newTime;
   digitalWrite(led1,LOW);
}

из цикла for

,

Теперь работает, светодиод включается на 2 секунды, а потом гаснет. Но только для первой итерации он работает для первого значения из массива, при сравнении с другими значениями он ведет себя так же, как и раньше., @Andrija Erovic

вы хотите зажечь светодиод на 2 секунды столько раз, сколько значений совпадают? затем сначала посчитайте спички, а затем выполните моргание, @Juraj

Я пробовал это. Я добавил счетчик, который подсчитывает, сколько раз совпадают эти два значения. А затем в своем IF я добавил, что всякий раз, когда счетчик newTime-oldTime >= dt && i<counter должен выключать светодиод и увеличивать i на 1 (i++) , но он по-прежнему ведет себя так же. По какой-то причине похоже, что он распознает только первую итерацию цикла for, @Andrija Erovic


1

Старое и новое время не совпадают в той части, где светодиоды выключены

else if(oldTime-newTime >= dt){
          oldTime=newTime;
          digitalWrite(led1,LOW);
         }


Когда простые процессоры достигают максимального или минимального значения и продолжают считать, они переполняются и начинают считать с дальнего конца: Итак, 5-8=maxint(наибольшее число)-3 Результатом является то, что разница представляет собой огромное число, превышающее 2000, за исключением того, что каждые несколько недель, когда millis() переполняется и становится больше, чем может хранить Unsigned big int, и начинает отсчет с нуля. (многие коды не работают в этом случае, ваш сработает только тогда ;-)
Правильная версия:

else if(newTime-oldTime >= dt){
          oldTime=newTime;
          digitalWrite(led1,LOW);
         }

Хотя я заметил, что testrange (оба) возвращает свое значение в true только в ограниченных обстоятельствах, если ввод от кодировщика значительно увеличился очень быстро, чтобы догнать растущие вводы, поэтому следующие значения никогда не будут проходить условие для их включения

if(encoder>=array1[i] && encoder<=(array1[i]+tolerance) && testRange)

никогда не вернет значение true, поскольку testRange остается ложным. Добавить

testRange=истина; testRange2=истина;

в конце цикла, иначе он вернется в значение true для следующей итерации цикла(). Я думаю, вопрос в том, хотите ли вы, чтобы другие функции работали, когда светодиоды включены или нет.

Плохая привычка делать ненужные переменные, такие как i,j,k,l, глобальными, так как они тратят память, даже если они не нужны, вы можете определить их внутри самой структуры, например: for(int i=1;... таким образом как только цикл for, while и т. д. (скобки закрываются) завершается, вы возвращаете свою память и можете снова использовать переменную

,

Вы правы, глупая ошибка. Я изменил его сейчас, но он все еще не работает, @Andrija Erovic