简体   繁体   English

使用毫秒计时器的Arduino“超时”功能

[英]Arduino 'time out' function using a millis timer

I've not been programming for long and I just want to expand from electronic engineering with an Arduino UNO board.我编程的时间不长,我只想使用 Arduino UNO 板扩展电子工程。

I've started a new project based on the Secret Knock Detecting Door Lock by Steve Hoefer on Grathio and I'd like to implement the following:我已经开始了一个基于 Steve Hoefer 在 Grathio 上的 Secret Knock Detecting Door Lock 的新项目,我想实现以下内容:

( http://grathio.com/2009/11/secret_knock_detecting_door_lock/ ) ( http://grathio.com/assets/secret_knock_detector.pde ) ( http://grathio.com/2009/11/secret_knock_detecting_door_lock/ ) ( http://grathio.com/assets/secret_knock_detector.pde )

Implementation执行

If the global value equals 0 and the valid knock patter is true then flash a yellow LED 4 times using millis rather than delay so that it can still 'listen'.如果全局值等于 0 并且有效的敲击模式为真,则使用毫秒而不是延迟使黄色 LED 闪烁 4 次,以便它仍然可以“收听”。

If another valid knock pattern is not heard within 6 seconds it will time out and reset global to 0 so that it can acknowledge the initial true pattern and flash the yellow LED.如果在 6 秒内未听到另一个有效的爆震模式,它将超时并将全局重置为 0,以便它可以确认初始真实模式并闪烁黄色 LED。

If another valid knock pattern is heard withing 6 seconds, increment a counter.如果在 6 秒内听到另一个有效的敲击模式,则增加一个计数器。

If the counter equals 1, wait for another valid knock pattern and if true within 6 seconds, increment the counter again and don't flash the yellow LED.如果计数器等于 1,则等待另一个有效的敲击模式,如果在 6 秒内为真,则再次增加计数器并且不闪烁黄色 LED。

Otherwise, time out and reset all values.否则,超时并重置所有值。

And so on until if the counter is greater than or equal to 4 trigger the master LED array.依此类推,直到计数器大于或等于 4 时触发主 LED 阵列。

Once is gets to 4 successful knocks, I'd like it to trigger the master LED array I've built.一旦成功敲击 4 次,我希望它触发我构建的主 LED 阵列。

Problems问题

This project was inspired by the test panels used on passenger airplanes.该项目的灵感来自客机上使用的测试面板。 I've seen them a lot and thought it would be a good place to start and learn about timing.我见过他们很多,并认为这将是一个开始和了解时间的好地方。

There are a few problems as I don't wish to reset millis() every time and I'm using a button rather than the boolean within the knock detection script so I don't get lost in the code.有一些问题,因为我不希望每次都重置 millis() 并且我使用的是按钮而不是爆震检测脚本中的布尔值,所以我不会迷失在代码中。

I understand this won't respond 50 seconds later and it's a beginners mistake but proves what I've got if I hold down the button.我知道这不会在 50 秒后响应,这是一个初学者的错误,但如果我按住按钮证明了我所拥有的。 The code below also doesn't have a time out after the 1st digitalRead HIGH or true boolean (I am struggling with this).下面的代码在第一次 digitalRead HIGH 或 true boolean 之后也没有超时(我正在为此苦苦挣扎)。

Arduino sketch阿杜诺素描

  int inPin = 2;         // input pin switch
    int outPin = 3;       // output pin LED
    
    long currentTime = 0; // counter
    long nextTime = 0; // counter
    long lastTime = 0; // counter
    
    int patternCounter = 0; // build up 
    int globalValue = 0; // lock out
    int breakIn = 0; // waste of time?
    
    void setup()
    {
      pinMode(inPin, INPUT);
      pinMode(outPin, OUTPUT);
      Serial.begin(9600);
      Serial.println("GO");
    }
    
    void loop(){
    
      // boolean true, switch just for testing
      if (digitalRead(inPin)==HIGH&&globalValue==0&&breakIn==0) { 
        Serial.println("CLEARED 1st");
        delay (500); // flood protection
        globalValue++;
        breakIn++;
        if (globalValue>0&&breakIn>0){ 
          currentTime = millis(); // start a 'new' counter and 'listen'
          if (currentTime<6000) { // less than
            if (digitalRead(inPin)==HIGH) { // and true
              Serial.println("CLEARED 2nd"); // cleared the stage
              delay (500); // flood protection 
              patternCounter++;
            } // if counter less
          } // if true or high
          if (currentTime>6000) {
            Serial.println("TIMEOUT waiting 2nd"); // timed out
            globalValue = 0;
            patternCounter = 0;
            breakIn = 0;
          } // if more than
        } // global master
      }
    
      // 3rd attempt
      if (globalValue==1&&patternCounter==1){ // third round
        nextTime = millis(); // start a 'new' counter and 'listen'
        if (nextTime<6000) { // less than
          if (digitalRead(inPin)==HIGH) { // and true
            Serial.println("CLEARED 3rd");
            delay (500); // flood protection
            patternCounter++;
          } // if counter less
        } // if true or high
        if (nextTime>6000) {
          Serial.println("TIMEOUT waiting 3rd"); // timed out
          globalValue = 0;
          patternCounter = 0;
        } // if more than
       } // global master
    
      // 4th attempt and latch
      if (globalValue==1&&patternCounter==2){ // last round 
        lastTime = millis(); // start a 'new' counter and 'listen'
        if (lastTime<6000) { // less than
          if (digitalRead(inPin)==HIGH) { // and true
            digitalWrite(outPin, HIGH); // LED on
            Serial.println("CLEARED 4th ARRAY"); // cleared the stage
            delay(500); // flood protection
          } // true or high
        } // counter
        if (lastTime>6000) {
          Serial.println("TIMEOUT waiting 4th"); // timed out
          globalValue = 0;
          patternCounter = 0;
        } // if more than
       } // global and alarm
    
    
       } // loop end  

That's the current sketch, I understand the counters I've used are near pointless.这是当前的草图,我知道我使用的计数器几乎毫无意义。

Any help would be greatly appreciated!任何帮助将不胜感激!

That is a lot to wade through so I may not understand your question but the bit of code below stands out as a problem:这是一个很大的问题,所以我可能不明白你的问题,但下面的代码是一个问题:

   currentTime = millis(); // start a 'new' counter and 'listen'
      if (currentTime<6000) { // less than

      .....
      }

Do you understand that there is no "resetting" of millis() possible and that is merely a function that returns the number of milliseconds since the program launched?您是否了解millis()不可能“重置”,而这仅仅是一个返回程序启动以来毫秒数的函数? It will continue to increase as long as the program is running (until it rolls over but that is a separate problem).只要程序正在运行,它就会继续增加(直到它翻转,但这是一个单独的问题)。 So in the above code 'currentTime' is only going to be < 6000 very, very briefly (6 seconds) and then never again (except for the rollover condition where millis resets).所以在上面的代码中,'currentTime' 只会非常非常短暂地小于 6000(6 秒),然后再也不会(除了毫秒重置的翻转条件)。

So a typical way millis() is used to track time is, in setup , to store it's current value into a variable and add your timeout period value to it:因此,使用millis()跟踪时间的典型方式是,在setup中,将其当前值存储到变量中并将超时时间值添加到其中:

// timeoutAmount is defined at head of program. Let's say it is 6000 (6 seconds)
nextUpdate = millis() + timeoutAmount; 

Then in loop you can do the check:然后在loop中您可以进行检查:

if (millis() >= nextUpdate){
  nextUpdate = millis() + timeoutAmount; // set up the next timeout period

 // do whatever you want to do

}

Also be careful using delay() - it is easy to use for flow control but for any program with more than one thing going on it can lead to confusing and hard to solve problems.使用delay()时也要小心——它很容易用于流量控制,但对于任何有不止一件事的程序来说,它可能会导致混乱和难以解决问题。

Oh - there are more sophisticated ways of doing timing using the built-in timers on the chip to trigger interrupts but better to get the hang of things first.哦 - 使用芯片上的内置计时器触发中断有更复杂的计时方法,但最好先掌握事情的窍门。

I've come up with the following sketch after playing around with your help.在你的帮助下,我想出了下面的草图。

The sketch will almost do everything I wanted...草图几乎可以完成我想要的一切......

When it times out (T/O) after the 1st, 2nd (inCount = 1) or 3rd (inCount = 2) button press, I'd like it to revert back to the start without having to press it again and loop triggerFlash twice.当它在第 1 次、第 2 次(inCount = 1)或第 3 次(inCount = 2)按钮按下后超时(T/O)时,我希望它恢复到开始,而不必再次按下它并循环 triggerFlash 两次.

Either that or implementing another 'wait and listen' within the time out to move it to the 2nd (inCount = 1) etc but I think that may cause problems.要么在超时内实施另一个“等待和倾听”,以​​将其移动到第二个(inCount = 1)等,但我认为这可能会导致问题。

I know there's delay used within the flashes but that will be changed to millis(), I'm just trying to get the basic function and understanding.我知道闪光灯中使用了延迟,但将更改为millis(),我只是想获得基本功能和理解。
const int switchPin = 2;常量 int switchPin = 2; // the number of the input pin const int BswitchPin = 4; // 输入引脚的编号 const int BswitchPin = 4; // the number of the input pin const int outPin = 3; // 输入引脚的编号 const int outPin = 3; const int thePin = 5; const int thePin = 5;

long startTime; // the value returned from millis when the switch is pressed
long escapeTime; // the value returned from millis when in time out
long duration;  // variable to store the duration

int inCount = 0;
int dupe = 0;

void setup()
{
  pinMode(switchPin, INPUT);
  pinMode(outPin, OUTPUT);
  pinMode(thePin, OUTPUT);
  digitalWrite(switchPin, HIGH); // turn on pull-up resistor
  Serial.begin(9600);
  Serial.println("Go");
  digitalWrite(outPin, HIGH);
}

void loop()
{
  if(inCount==0&&digitalRead(switchPin) == LOW)
  {
    // here if the switch is pressed
    startTime = millis();
    while(inCount==0&&digitalRead(switchPin) == LOW)
      ; // wait while the switch is still pressed
    long duration = millis() - startTime;
    if (duration<4000) {
      Serial.println("1");
      triggerFlash();
      inCount++;
    }
  } // master 1

  if (inCount>0&&inCount<4&&digitalRead(switchPin) == LOW) 
  {
    // here if the switch is pressed
    startTime = millis();
    while(inCount>0&&inCount<4&&digitalRead(switchPin) == LOW)
      ; // wait while the switch is still pressed
    long duration = millis() - startTime;
    delay(500); // flood protection
    if (duration>4000) { // script an escape here - formerly if (while will loop the condition)

      Serial.println("T/O");
      triggerFlash();
      inCount = 0;      
    }

    if (duration<4000) {
      dupe = inCount + 1;
      Serial.println(dupe);
      inCount++;
    }
  }
  if (inCount>=4) {
    digitalWrite(thePin, HIGH);
  }
} // loop

void triggerFlash() {
  int i = 0;
  for (i=0; i < 8; i++){   
    digitalWrite(outPin, LOW);
    delay(100);
    digitalWrite(outPin, HIGH);
    delay(100);
  } 
}

Any ideas are very appreciated!任何想法都非常感谢! (edited with improved counting) (用改进的计数进行了编辑)

The above code is actually WRONG.上面的代码实际上是错误的。 Please be carefull with millis() as they rollover after some time.请小心millis(),因为它们会在一段时间后翻转。 it is only long type.它只是长型。 So if the millis+timeout is near max(long) and millis() will rollover and start counting from zero, the millis()>=nextupdate will be false even if the timeout actually occurs.因此,如果 millis+timeout 接近 max(long) 并且 millis() 将翻转并从零开始计数,即使实际发生超时,millis()>=nextupdate 也会为假。

The correct way to do this is:正确的方法是:

unsigned long start = millis();
unsigned long timeout = MY_TIMEOUT_HERE; 
...
//check if timeout occured
unisgned long now = millis();
unsigned long elapsed = now - start;
if(elapsed > timeout)
   //do whatever you need to do when timeout occurs

I just implement Arduino library.我只是实现了 Arduino 库。 hope it help your problem.希望对您的问题有所帮助。 I made it to work like setTimeout and setInterval in javascript.我让它像 javascript 中的 setTimeout 和 setInterval 一样工作。 You can download it here, Github你可以在这里下载, Github

This is example of my code You can see it in action in Tinkercad这是我的代码示例您可以在Tinkercad中看到它的实际效果

/*
  Author : Meng Inventor
  Contact : https://www.facebook.com/MLabpage
  15 July 2022
*/

#include "simple_scheduler.h"
#define LED1_PIN 7
#define LED2_PIN 6
#define LED3_PIN 5
#define GREEN_LED_PIN 4
Task_list job_queue;


void setup()
{

  Serial.begin(115200);

  pinMode(LED1_PIN, OUTPUT);
  pinMode(LED2_PIN, OUTPUT);
  pinMode(LED3_PIN, OUTPUT);
  pinMode(GREEN_LED_PIN, OUTPUT);

  // setInterval will run repeatly for every given time period (ms)
  job_queue.setInterval(blink_green, 1000);
  job_queue.setInterval(led1_on, 2000);
}

unsigned long timer = millis();
void loop()
{
  job_queue.update();
 
}
void led1_on(){
  digitalWrite(LED1_PIN, HIGH);
  job_queue.setTimeout(led1_off, 250); //setTimeout will run once after given time period (ms)
}
void led1_off(){
  digitalWrite(LED1_PIN, LOW);
  job_queue.setTimeout(led2_on, 250);//setTimeout will run once after given time period (ms)
}
void led2_on(){
  digitalWrite(LED2_PIN, HIGH);
  job_queue.setTimeout(led2_off, 250);//setTimeout will run once after given time period (ms)
}
void led2_off(){
  digitalWrite(LED2_PIN, LOW);
  job_queue.setTimeout(led3_on, 250);//setTimeout will run once after given time period (ms)
}

void led3_on(){
  digitalWrite(LED3_PIN, HIGH);
  job_queue.setTimeout(led3_off, 250);//setTimeout will run once after given time period (ms)
}
void led3_off(){
  digitalWrite(LED3_PIN, LOW);
}



void blink_green() {
  digitalWrite(GREEN_LED_PIN,HIGH);
  job_queue.setTimeout(blink_green_off, 500);
}

void blink_green_off() {
  digitalWrite(GREEN_LED_PIN,LOW);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM