Счет времени с использованием миллисекунд

Я пытаюсь написать код, в котором фоторезисторы (a или b) воспринимают мигание света, а светодиоды (k и d) — одновременно с этим миганием. И я хочу, чтобы когда оба фоторезистора почувствуют темноту более 3 секунд, светодиоды загорятся и останутся, пока один из них снова не загорится. Но я не могу понять, в какой части я должен поставить счетчик времени в миллисекундах?

int k = 2;
int d = 3;
int fk = A0;
int fd = A1;
int a = 0;
int b = 0;

void setup() {
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  a = analogRead (fk);
  b = analogRead (fd);
  while (a < 1000 && b < 1000)
  {
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    a = analogRead (fk);
    b = analogRead (fd);
  }
  if (a > 1000)
    digitalWrite(2, HIGH);
  else
    digitalWrite(2, LOW);
  if (b > 1000)
    digitalWrite(3, HIGH);
  else
    digitalWrite(3, LOW);
}

, 👍1

Обсуждение

Вы сказали фоторезисторы и мигающие огни?? Имейте в виду, что фоторезисторы имеют нечетную валентную зону. В частности, фоторезисторы будут проводить ток при включении света и будут продолжать проводить ток после того, как свет погаснет, возможно, на секунду или более. Поэтому, если ваши огни мигают достаточно быстро, вы никогда не обнаружите, что огни гаснут с помощью фоторезисторов., @st2000

Блинки идут с интервалом в 1 секунду, я уже проверял, все работает, я просто застрял с этим таймингом., @Ieva Kriščiūnaitė

Какой тип света вы мигаете, чтобы активировать фоторезисторы?, @VE7JRO


3 ответа


2

Миллис измеряет время. Вы можете сохранить эту меру и сравнить ее позже. Я не знаю, что в вашем коде представляет собой ощущение темноты/света в вашем коде (резисторы могут использоваться для повышения или понижения измеренного входа в зависимости от вашей схемы), поэтому вам придется работать следующим образом, заменяя вещи в < ;>

unsigned long lastlight;
void loop()
{
    if (<isLitSensorA>) lastlight = millis();
    if (<isLitSensorB>) lastlight = millis();
    if(millis() - lastlight > 3000){ //3 секунды с момента lastlight
        <LightsAlwaysOn>
    }
    else{
        <BlinkWithLights>
    }
}
,

3

Это один из тех случаев, когда решение состоит в том, чтобы просто реализовать конечный автомат. Рассмотрим конечный автомат с этими тремя состояния:

  • СВЕТ: свет был обнаружен хотя бы одним из датчиков, Светодиоды следуют за датчиками света.
  • SHORT_DARK: ни один датчик не видит свет, оба светодиода не горят
  • LONG_DARK: прошло не менее трех секунд с тех пор, как ни один датчик увидел свет, оба светодиода горят.

Переходы между этими состояниями можно изобразить следующим образом. диаграмма состояний:

переходы состояний

где «обнаружена темнота» означает, что ни один датчик не видит свет, а «свет обнаружен» означает, что по крайней мере один датчик видит свет.

Как правило, рекомендуется всегда рисовать диаграмму состояний прежде чем вы начнете писать код. Как только вы убедитесь, что ваша диаграмма описывает желаемое поведение, почти тривиально перевести его в код. Вот как я бы это закодировал:

void loop()
{
    bool light_k = analogRead(IN_K) >= 1000;
    bool light_d = analogRead(IN_D) >= 1000;

    static enum { LIGHT, SHORT_DARK, LONG_DARK } state;
    static uint32_t darkness_start;
    switch (state) {
    case LIGHT:
        digitalWrite(OUT_K, light_k ? HIGH : LOW);
        digitalWrite(OUT_D, light_d ? HIGH : LOW);
        if (!light_k && !light_d) {
            darkness_start = millis();
            state = SHORT_DARK;
        }
        break;
    case SHORT_DARK:
        if (light_k || light_d) {
            state = LIGHT;
        } else if (millis() - darkness_start >= 3000) {
            digitalWrite(OUT_K, HIGH);
            digitalWrite(OUT_D, HIGH);
            state = LONG_DARK;
        }
        break;
    case LONG_DARK:
        if (light_k || light_d) {
            state = LIGHT;
        }
        break;
    }
}
,

0

Вот более элегантный способ сделать это. Эта программа не требует, чтобы вы действительно считали, когда было темно, вместо этого она просто запоминает время, когда в последний раз видела свет (как поэтично ;). Я также добавил некоторые комментарии к коду.

// Все переменные
int k = 2;        // светодиод 1
int d = 3;        // светодиод 2
int fk = A0;      // фоторезистор 1
int fd = A1;      // фоторезистор 2
int lastLight = 0;

// Настраиваем светодиоды
void setup() {
  pinMode(k, OUTPUT);
  pinMode(d, OUTPUT);
}

void loop()
{
  // Проверяем фоторезисторы
  int a = analogRead (fk);
  int b = analogRead (fd);
  if (a > 1000 || b > 1000)
  {
    // Включаем светодиоды, если один фоторезистор чувствует свет
    digitalWrite(k, HIGH);
    digitalWrite(d, HIGH);
    // Также установить время, когда в последний раз было светло, на текущее время
    lastLight = millis();
  }
  else if (abs(millis() - lastLight) > 3000)
  {
    // Включаем светодиоды, если темно более 3 секунд (то есть 3000 миллисекунд)
    digitalWrite(k, HIGH);
    digitalWrite(d, HIGH);
  }
  else
  {
    // Выключаем светодиоды
    digitalWrite(k, LOW);
    digitalWrite(d, LOW);
  }
}
,

По поводу «if (lastLight < millis() - 3000)»: здесь у вас есть ошибка с пролонгацией миллисекунд. Его можно каким-то образом смягчить с помощью if (millis() - lastLight > 3000), но он все равно потерпит неудачу, если он останется темным дольше, чем период ролловера. Добавление lastLight = millis() - 9000 в if или какую-либо переменную состояния может это исправить., @Edgar Bonet

Хороший вопрос, я обновил ответ, чтобы он соответствовал этому. Однако использование if (millis() - lastLight > 3000) этого не изменит. Вы можете обойти эту проблему, используя абсолютное значение разницы (таким образом светодиоды остаются темными, даже если происходит переключение). Я не понимаю вашего предложения на тот случай, если темнота остается дольше 49,5 дней., @LukasFun

abs() не поможет, но вы должны сделать lastLight unsigned long. См. [Переполнение millis()... это плохо?](https://www.gammon.com.au/millis) и [Как я могу справиться с переполнением millis()?](https://arduino.stackexchange .com/q/12587). Если темнота остается дольше 49,7 дней, millis() будет очень близка к lastLight, и этот код выключит светодиоды. Этого не произойдет, если вы неоднократно меняете lastLight, чтобы оставаться на несколько секунд позади millis()., @Edgar Bonet