Вопрос о библиотеке ElapsedMillis() и конечных автоматах

Я делаю своего рода конечный автомат с 3 состояниями, и на самом деле я делаю некоторые тесты, настраивая в начале моего кода state=3. Я подключил к каждому контакту 2 светодиода, в общей сложности 12 светодиодов. Я использую библиотеку elapsedMillis (https://github.com/pfeerick/elapsedMillis) чтобы сделать вещи немного проще, и я застрял в 3-м состоянии. В 3-м состоянии я хотел бы, чтобы каждая пара светодиодов оставалась включенной в течение 90 мс, чем в течение 1 мс. Библиотека elapsedMillis позволяет сделать что-то вроде этого:

elapsedMillis timeElapsed; //объявите глобальный, если вы не хотите, чтобы он сбрасывался при каждом запуске цикла

#include "elapsedMillis.h"

const int pin0 = 12;
const int pin1 = 11;
const int pin2 = 10;
const int pin3 = 9;
const int pin4 = 8;
const int pin5 = 7;

unsigned long t1 = 500;
unsigned long waiting = 1000;
unsigned long t2 = 100;
unsigned long t3 = 50;
unsigned long t4 = 1;
unsigned long t5 = 90;
unsigned long startTime = 0;

int ledArray[] = {pin0, pin1, pin2, pin3, pin4, pin5};
int j, k, a, c = 0;
int state = 3;

elapsedMillis elapsedTime;
elapsedMillis timer1;
elapsedMillis timer2;
elapsedMillis timer3;
elapsedMillis timer4;
elapsedMillis timer5;

void setup() {
  pinMode(pin0, OUTPUT);
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  pinMode(pin5, OUTPUT);
  Serial.begin(9600);

}

void loop() {

  switch (state) {

    case 0:
      // led accesi in modo scalare allo stato 0
      while (k <= 5)
      {

        if (timer1 >= t1)
        {
          if (j <= 5)
          {
            digitalWrite(ledArray[j], HIGH);
            j++;
            timer1 = 0;

          }
          k++;
          elapsedTime = 0;
        }

      }
      // attendo 1s poi vado allo stato 1

      if (elapsedTime >= waiting) {
        state = 1;
        elapsedTime = 0;
      }

      break;

    case 1:

      // led spenti rapidamente in modo scalare

      while (k >= 0) {
        if (timer2 >= t2)
        {
          if (j >= 0)
          {
            digitalWrite(ledArray[j], LOW);
            j--;
            timer2 = 0;
          }
          k--;
          elapsedTime = 0;
        }
      }
      // attendo 0.1s
      if (elapsedTime >= t2) {
        state = 2;

      }
      break;

    case 2:

      // светодиодное затухание на 3 вольта
      if (c <= 3)
      {
        while (a <= 255)
        {
          if (timer3 >= t3) {
            analogWrite(ledArray[3], a);
            timer3 = 0;
            a += 10;

          }

        }
        while (a >= 0)
        {
          if (timer3 >= t3) {
            analogWrite(ledArray[3], a);
            timer3 = 0;
            a -= 10;
          }
        }
        c++;
      }
      else {
        state = 3;
      }

      break;

    case 3:
      
      if (timer4 >= t5) {
        if (j <= 5) {
          digitalWrite(ledArray[j], HIGH);
          j++;
          timer4 = 0;
          if (timer5 >= t4) {
              digitalWrite(ledArray[j], LOW);
              timer5 = 0;
            }
          }
        }
      break;
  }
}

case 3:

  for (int ii = 0; ii <= 5; ii++) 
  {
    digitalWrite(ledArray[ii], ( (ii == j) && (timer4 < 90)));
  }
  
  if (timer4 > 91) {
    j += backwardScan ? -1 : 1 ;
    if (j > 5) {
      backwardScan = 1;
      j = 5;
    }
    if (j < 0) {
      backwardScan = 0;
      j = 0;
    }
    timer4 = 0;
  }
  break;

Для state3 я хотел бы получить эффект, подобный автомобилю Knight Rider "KITT" в телешоу 80-х. Каждая пара из 2 светодиодов должна двигаться вперед и назад... в ближайшее время: первые 2 светодиода остаются включенными на 90 мс и 1 мс выключенными, затем вторые 2 светодиода на 90 мс и 1 мс выключенными...и т. Д ...

Похоже, что светодиоды в массиве горят все вместе.

, 👍0

Обсуждение

И в чем же собственно заключается проблема? Пожалуйста, дайте подробное описание. Также: Как вы видите, работает ли это? 1 мс-это слишком короткая пауза, чтобы видеть человеческим глазом, @chrisl

Для state3 я хотел бы получить эффект, подобный автомобилю Knight Rider "KITT" в телешоу 80-х. Каждая пара из 2 светодиодов должна двигаться вперед и назад... в ближайшее время: первые 2 светодиода остаются включенными на 90 мс и 1 мс выключенными, затем вторые 2 светодиода на 90 мс и 1 мс выключенными ... и т. Д..., @tommy

А в чем проблема с вашим кодом? Что именно он делает не так, как ожидалось? Пожалуйста, не давайте нам гадать, @chrisl

похоже, что светодиоды в массиве горят все вместе, @tommy

Предположение о случае 3-переменная состояния " j " - это то, какая пара светодиодов должна гореть, и...Не уверен... Нет состояния для туда и обратно, состояние синхронизации-это разница между timer4 и timer5? Я бы предположил, что вам нужна другая переменная состояния, чтобы помнить, двигаетесь ли вы "назад" или "вперед". В общем случае с помощью логики конечных автоматов вы должны быть в состоянии точно определить, в каком состоянии вы находитесь, соответствующим образом установить выходы, а затем перейти или нет в следующее состояние. Например, ваш код должен быть в состоянии распознать, как установить светодиоды KITT в состояние "средняя пара, сканирование вперед-вперед, вкл., 33 мс для перехода"., @Dave X

Да, в состоянии 3 переменная j должна отслеживать, в какой паре светодиодов вы находитесь, но моя реальная проблема заключается в том, как включить светодиод на 90 мс и 1 мс, используя timer4 и timer5, если это необходимо. У меня есть t4, который является переменным для светодиода 90 мс, и t5, который выключен для светодиода 1 мс, @tommy

.. Вы можете обработать состояние on & Xms для перехода в состояние таймера с помощью for(int ii=0, ii<=5,ii++){digitalWrite(edArray[ii],( (ii==j) && (timer4 <90) }} and then whenever if(timer4>91), обновить backward, j и timer4` до соответствующего следующего состояния., @Dave X

м-м-м ... извини, я плохо читаю..., @tommy


1 ответ


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

2

Вам нужно сохранить больше информации о состоянии, чтобы "случай 3" работал как светодиодный сканер в стиле КИТТА. Я думаю, что вы можете сделать это с тремя переменными состояния: j для какой пары светодиодов активен, backwardsScan, чтобы сказать, в какую сторону идти, и timer4, чтобы вспомнить, где в цикле 91 мс мы находимся с активной парой светодиодов.

Попробуйте что-то вроде этого:

...
int backwardsScan = 0;
...

case 3: // КИТТ-подобное сканирование вперед и назад 90us/1us
  // j запоминает, какая пара светодиодов активна
  // backwardsScan запоминает, в каком направлении сканировать
  // timer4 обрабатывает цикл включения-выключения 90 мс/1 мс.
  // 
  // сбросить выходные светодиоды соответствующим образом для (j,timer4):
  for(int ii=0;ii<=5;ii++){
    digitalWrite(ledArray[ii],( (ii==j) && (timer4 <90))); 
  }
  // обновить состояние КИТТА на основе (j,backwardsScan,timer4)
  if(timer4 > 91){ 
     j += backwardsScan? -1 : 1 ;
     if (j > 5){
        backwardsScan = 1;
        j = 5;
        }
     if (j < 0) {
        backwardsScan = 0;
        j = 0;
        }
     timer4 = 0;
     }

  break;

Главный трюк с автоматами состояний заключается в том, чтобы полностью определить полное состояние из того, что вы отслеживаете-оно должно быть без памяти, поскольку переменные состояния полностью определяют состояние, и вам не нужно запоминать предыдущее состояние. Если вы обнаружите, что вам нужно знать больше одной вещи, вам может понадобиться вектор или набор переменных состояния. Можно было бы отобразить весь вектор состояния led-backwardsScan-timer4 в одну переменную состояния (например, timer4 по модулю 182 мс), но это было бы излишне сложно. Важно распознать все переменные, необходимые для полного определения состояния.

,

Я заметил, что вы пишете: "backwardsScan?", а цифровая запись мне непонятна..., @tommy

The ( Backwards)? -1 : 1) - тернарный оператор https://en.wikipedia.org/wiki/%3F: Если backwardsScan равен true, то он возвращает первое значение -1, а если false, то второе значение +1., @Dave X

Я должен был изменить это: for(int ii=0,ii<=5,ii++) с ";" не ,, @tommy

Логика в digitalWrite записывает только ВЫСОКИЙ уровень на активный светодиод во время sub 90ms timer4, а НИЗКИЙ-на все остальные светодиоды и на активный светодиод после 90ms., @Dave X

У меня много ошибок, я пытаюсь сейчас исправить код..., @tommy