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

Я пытаюсь сделать производственный счетчик для машины. Я хочу отобразить производственный отсчет последней минуты для каждой секунды. Таким образом, дисплей должен обновляться каждую секунду и отображать реальное значение последних 60 секунд. У меня есть система для обнаружения вывода продукта в реальном времени и передачи его на Arduino с помощью цифрового входного штифта.

Я написал ниже коды и для этого. то, что я сделал, - это подсчитал выход и получил выход в секунду. Затем сохраните его в массиве в виде разделенного значения для каждой секунды. Каждую секунду массив обновлялся и добавлял новое значение для текущей секунды. Наконец, добавьте все значение счета за последние 60 секунд и выведите его как производительность текущей минуты.

Мой вопрос заключается в том, есть ли какой-нибудь простой и эффективный способ сделать это без использования нескольких переменных ?

    #define countSensor 8  //вход счетного датчика
    
    uint8_t records[60];
    uint8_t countSensorState = 0;
    uint8_t totalCount = 0;
    uint8_t countOfLastSec = 0;
    uint8_t lastCount = 0;
    uint8_t lastMinCount;
    uint32_t preMills = 0;
    
    
    void setup() {
      Serial.begin(9600);
      //init sensor input pin
      pinMode(countSensor, INPUT_PULLUP); //изменение в зависимости от типа датчика
    
      //очистить случайное значение ячеек памяти
      for (int i = 0; i < 60; i++) {
        records[i] = 0;
      }
    
    }
    
    void loop() {
      //get count at falling edge
      if (digitalRead(countSensor)^ countSensorState) {
        if (!digitalRead(countSensor)) {
          totalCount++;
    
        }
        countSensorState = digitalRead(countSensor);
      }
      //получить отсчет последней секунды
      if (millis() - preMills > 1000) {
        preMills = millis();
        countOfLastSec = totalCount - lastCount;
        lastCount = totalCount;
        //запись последних 60-х отсчетов
        //--сдвиг назад на секунду в массиве
        for (int i = 0; i < 59; i++) {
          records[i] = records[i + 1];
        }
        //--запись текущей секунды в массиве по 59-му индексу
        records[59] = countOfLastSec;
        //get last 60s count
        for (int i = 0; i < 60; i++) {
          lastMinCount += records[i];
        }
        Serial.println(lastMinCount);
      }
    
    
    
    }

, 👍1

Обсуждение

Если вам действительно нужна общая сумма за последние 60 секунд, то да, вы должны сохранить этот массив. Если вы можете жить с чем-то вроде [экспоненциально взвешенной скользящей средней](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average), то необходимо сохранить только предыдущее значение среднего значения., @Edgar Bonet

вам не нужно сдвигать значения .... индексируйте массив по кругу, @jsotola

@jsotola, я не смог понять это правильно. Как я могу применить круговой массив к своему коду? Не могли бы вы дать мне измененный код..., @user_fs10

прямо сейчас вы используете цикл " для "для итерации массива с помощью указателя "i".... удалите инструкцию " для... используйте i++` каждую секунду вместо этого ... считайте 0 1 2.. 59 0 1 2 ...., @jsotola


1 ответ


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

1

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

  • Нет никакого смысла хранить totalCount. Вы не используете его по-настоящему, и он в конце концов переполнится.

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

  • Вы вызываете digitalRead(countSensor) три раза подряд. Логика подсчета ребер работает до тех пор, пока три вызова дают один и тот же результат, но это не гарантировано. Безопаснее считывать контакт только один раз за итерацию цикла.

  • Точно так же два вызова millis() могут дать разные результаты, и это сделает ваши тайминги немного выключенными.

  • Условие millis() - preMills > 1000> будет срабатывать только тогда, когда Прошло 1001 миллисекунда. Из-за того, как работает millis (), иногда вы пропустите 1001-ю миллисекунду и обработаете 1002-ю миллисекунду. Чтобы избежать накопления этих небольших временных ошибок, лучше всего обновлять премиллы, всегда добавляя ровно 1000.

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

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

Вот моя попытка применить все вышеперечисленные предложения. Предупреждение: он не был протестирован.

const uint8_t countSensor = 8;

uint8_t record[60];       // последние 60 секунд отсчетов
uint8_t currentIndex; // текущий индекс в записи[]
uint8_t oldSensorState; // предыдущее состояние countSensor input
uint32_t previousSecond; // последний раз мы печатали minuteCount
uint8_t thisSecondCount; // количество элементов в текущем втором
uint16_t minuteCount; // количество элементов в последнюю минуту

void setup() {
    Serial.begin(9600);
    pinMode(countSensor, INPUT_PULLUP);
}

void loop() {
    // Подсчет падающих краев.
    uint8_t sensorState = digitalRead(countSensor);
    if (oldSensorState == HIGH && sensorState == LOW) {
        thisSecondCount++;
    }
    oldSensorState = sensorState;

    // Обновляйте статистику каждую полную секунду.
    if (millis() - previousSecond >= 1000) {
        previousSecond += 1000;

        // Обновите minuteCount, удалив секунду, которая падает с
        // окна, и добавив ту, которая входит в окно.
        minuteCount += thisSecondCount - record[currentIndex];

        // Замените счетчик, который больше не нужен, на
        // текущий.
        record[currentIndex] = thisSecondCount;

        // Начинайте отсчет новой секунды.
        thisSecondCount = 0;

        // Обновить текущий индекс, обернув его на 60.
        if (++currentIndex >= 60) {
            currentIndex = 0;
        }

        Serial.println(minuteCount);
    }
}
,