добровольно перезапустить счетчик прошедших миллисекунд с чтением
Когда я активирую высокий уровень, он будет считаться до тех пор, пока я задам его, пока я нахожусь под высоким уровнем, а затем отключится. Я могу снова начать считать, когда захочу, запуская низкий уровень и возвращаясь к высокому, и он начинается с самого начала, пока время на низком уровне не находится в пределах времени, которое я попросил, чтобы оно было высоким. Проблема в том, что я иду к низкому среднему счету, а затем быстро возвращаюсь к высокому, счет начинается с того места, где миллис остановился, не начиная с самого начала. Есть ли способ сделать это лучше.
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);
}
@northershoveler, 👍0
3 ответа
Во-первых, сделайте безопасным перенос кода, а во-вторых, добавьте еще одно условие:
Итак, как я понял, изменения 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);
}
// Если вы переходите на НИЗКИЙ уровень по истечении времени, он ничего не делает, ожидая следующего ВЫСОКОГО
}
Во-первых, милли должны использоваться относительно, чтобы избежать переноса. Простое исправление состоит в том, чтобы вычесть 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);
}
Спасибо за помощь, этот код ближе к тому, что я искал. Это для насоса уровня воды, когда триггер высокий, он включается, когда вода поднимается, триггер опускается и остается включенным в течение таймера в качестве отказоустойчивого, а затем выключается, когда истекшее время превышает установленное время и тоже не в моем коде отключается дополнительным триггером. Вот мой рабочий код.
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); //чтобы я мог видеть серийный монитор }
- Как справиться с rollover millis()?
- Использование millis() и micros() внутри процедуры прерывания
- ардуино - миллисекунды ()
- Кнопка с таймером переключения и функцией сброса времени + светодиод обратной связи
- Использовать timer0, не влияя на millis() и micros().
- Торговый автомат Arduino для мониторинга ввода монет в слот во время ожидания ввода пользователя
- Влияет ли `millis()` на длинные ISR?
- nodeMCU — Millis() — Простой счетчик — Как долго горит светодиод?
Можно принять свой собственный ответ как решение проблемы., @VE7JRO