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

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

unsigned long induceTime = 0;
unsigned long elapseTime;
long setTime = 10000;
int openClose;
int openClosePin = 2;
int writeToPin = 3;
void setup() {
Serial.begin(9600);
}

void loop() {
  int openClose = digitalRead(openClosePin);
  elapseTime = millis(); 
  if (openClose == HIGH && elapseTime < induceTime + setTime){ 
    digitalWrite(writeToPin, HIGH); 
    Serial.println(' ');
    Serial.println(elapseTime);
    Serial.println(' ');
    Serial.println(induceTime);
    Serial.println(' ');   
}
  if (openClose == LOW && elapseTime > induceTime + setTime){
    induceTime = elapseTime;
    Serial.println(elapseTime);
    Serial.println(induceTime);
}

delay(500);
}

, 👍0


3 ответа


0

Во-первых, сделайте безопасным перенос кода, а во-вторых, добавьте еще одно условие:
Итак, как я понял, изменения LOW/HIGH должны запускать таймер с нуля, независимо от того, закончился ли работающий таймер или нет, поэтому таймер все еще работает HIGH/LOW -> и LOW/HIGH должен перезапуститься

// заменить/вставить перед установкой
unsigned long startTime = 0;
bool timerIsOn = false;
//беззнаковое долгое время elapseTime;


 // замените ваш цикл этим
void loop() {
  int openClose = digitalRead(openClosePin);
// истечение времени = millis();
  if (openClose == HIGH && timerIsOn = false){
       timerIsOn = true;
       startTime = millis();
       digitalWrite(writeToPin, HIGH); 
       Serial.print(' ');
       Serial.print(millis());
       Serial.print(' ');
       Serial.print(startTime);
        Serial.println(' ');
   }
   // Это условие для того, чтобы время вышло
  if (timerIsOn = true && millis() - startTime > setTime){ 
     digitalWrite(writeToPin, LOW);
     timerIsOn = false;
     Serial.print(setTime);
     Serial.print(' ');
     Serial.println(millis()-startTime);
  }
   // Это условие для снижения до истечения времени
  if (openClose == LOW && timerIsOn = true){
    digitalWrite(writeToPin, LOW);
    timerIsOn = false;
    Serial.print('timerIsOn = ');
    Serial.println(timerIsOn);
    Serial.print(' ');
    Serial.println(millis()-startTime);
  }
 // Если вы переходите на НИЗКИЙ уровень по истечении времени, он ничего не делает, ожидая следующего ВЫСОКОГО
}
,

0

Во-первых, милли должны использоваться относительно, чтобы избежать переноса. Простое исправление состоит в том, чтобы вычесть induceTime с той же стороны сравнения. Пример: elapseTime - induceTime > setTime

Это также поднимает вопрос о том, что ваш "счетчик" всегда равен elapseTime, он же миллис, а не (elapseTime - induceTime), поэтому он никогда не перестает считать.

Вы также никогда не звоните digitalWrite(writeToPin, LOW); Таким образом, он идет высоко и остается высоким. Я подозреваю, что вы хотели установить его на низкое значение где-то в операторе else.

Теперь о проблеме с быстро меняющимися сигналами:

Кроме того, вы можете использовать прерывание и таймер, чтобы ваша частота дискретизации (определяемая задержкой (500)) не вступала в игру. Это даст наилучшее время за счет ограничения того, какие контакты вы можете использовать для openClosePin, и вы также должны убедиться, что вы достаточно устраняете дребезг сигнала (аппаратно).

В качестве альтернативы вы можете уменьшить 500 до приемлемого #. Но тогда вы захотите иметь еще один счетчик, чтобы предотвратить спам вашего последовательного вывода.

В приведенном ниже примере реализованы только ISR и сокращение до 500. Не реализован таймер (который потребуется для точного использования setTime для отключения writeToPin до LOW).

volatile unsigned long induceTime = 0;
volatile unsigned long elapsedTime;
unsigned long setTime = 10000;
//изменчивый int openClose; //может захотеть переключить это в isr...
int openClosePin = 2;
int writeToPin = 3;

void pinChangedISR(){
  if(digitalRead(openClosePin)){ // рост
    digitalWrite(writeToPin, HIGH);
    induceTime = millis();
  }
  else{//падает
    digitalWrite(writeToPin, LOW);
    elapsedTime = millis() - induceTime;
  }
}

void setup() {
  pinMode(writeToPin, OUTPUT);
  pinMode(openClosePin, INPUT); //может потребоваться INPUT_PULLUP в зависимости от аппаратного обеспечения
  attachInterrupt(digitalPinToInterrupt(openClosePin), pinChangedISR, CHANGE);
  Serial.begin(9600);
}

void loop() {
  static int frameCount = 0;
  unsigned long delayTime = 100;
  openClose = digitalRead(openClosePin);
  if (openClose == HIGH){ 
    elapsedTime = millis() - induceTime;
    if(elapsedTime >= setTime) digitalWrite(writeToPin, LOW);
    else if(setTime - elapsedTime < 100) delayTime = setTime - elapsedTime;
  }
  if(framecount >= 5){ //время печати...
    framecount = 0;
    if(digitalRead(writeToPin) == HIGH){
      Serial.println(' ');
      Serial.println(elapsedTime);
      Serial.println(' ');
      Serial.println(induceTime);
      Serial.println(' ');
    }
    else{ //эта часть немного отличается
      Serial.println(elapsedTime); //отчет о длительности последнего импульса, когда импульс неактивен
      Serial.println(millis()); // отчет о текущем времени для сравнения inducetime
    }
  } else ++framecount;
  delay(delayTime);
}
,

1

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

unsigned long induceTime = 0;
беззнаковое долгое время ожидания;
длинный setTime = 10000;
инт открытьЗакрыть;
интервал openClosePin = 2;
интервал writeToPin = 3;
недействительная установка () {
Серийный.начать(9600);
}

недействительный цикл () {
int openClose = цифровое чтение (openClosePin);
elapseTime = миллисекунды();
if (openClose == HIGH){ //сбросить счетчик
induceTime = миллисекунды();
digitalWrite (writeToPin, ВЫСОКИЙ);
Serial.println(induceTime);
}
если (openClose == НИЗКИЙ) {
elapseTime = миллис () - induceTime; //induceTime устанавливается, когда оставляем высокий уровень
если (elapseTime < setTime){
digitalWrite (writeToPin, ВЫСОКИЙ);
Serial.println (время истечения);
Serial.println("в пределах setTime high");
}
если (elapseTime > setTime){
digitalWrite(writeToPin, LOW);
Serial.println (время истечения);
Serial.println("в течение setTime для низкого уровня");
}
Серийный.println(' ');
Serial.println (время истечения);
Серийный.println(' ');
Serial.println(induceTime);
Серийный.println(' ');
}
delay(1000); //чтобы я мог видеть серийный монитор
}
,

Можно принять свой собственный ответ как решение проблемы., @VE7JRO