簡體   English   中英

使用毫秒計時器的Arduino“超時”功能

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

我編程的時間不長,我只想使用 Arduino UNO 板擴展電子工程。

我已經開始了一個基於 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 )

執行

如果全局值等於 0 並且有效的敲擊模式為真,則使用毫秒而不是延遲使黃色 LED 閃爍 4 次,以便它仍然可以“收聽”。

如果在 6 秒內未聽到另一個有效的爆震模式,它將超時並將全局重置為 0,以便它可以確認初始真實模式並閃爍黃色 LED。

如果在 6 秒內聽到另一個有效的敲擊模式,則增加一個計數器。

如果計數器等於 1,則等待另一個有效的敲擊模式,如果在 6 秒內為真,則再次增加計數器並且不閃爍黃色 LED。

否則,超時並重置所有值。

依此類推,直到計數器大於或等於 4 時觸發主 LED 陣列。

一旦成功敲擊 4 次,我希望它觸發我構建的主 LED 陣列。

問題

該項目的靈感來自客機上使用的測試面板。 我見過他們很多,並認為這將是一個開始和了解時間的好地方。

有一些問題,因為我不希望每次都重置 millis() 並且我使用的是按鈕而不是爆震檢測腳本中的布爾值,所以我不會迷失在代碼中。

我知道這不會在 50 秒后響應,這是一個初學者的錯誤,但如果我按住按鈕證明了我所擁有的。 下面的代碼在第一次 digitalRead HIGH 或 true boolean 之后也沒有超時(我正在為此苦苦掙扎)。

阿杜諾素描

  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  

這是當前的草圖,我知道我使用的計數器幾乎毫無意義。

任何幫助將不勝感激!

這是一個很大的問題,所以我可能不明白你的問題,但下面的代碼是一個問題:

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

      .....
      }

您是否了解millis()不可能“重置”,而這僅僅是一個返回程序啟動以來毫秒數的函數? 只要程序正在運行,它就會繼續增加(直到它翻轉,但這是一個單獨的問題)。 所以在上面的代碼中,'currentTime' 只會非常非常短暫地小於 6000(6 秒),然后再也不會(除了毫秒重置的翻轉條件)。

因此,使用millis()跟蹤時間的典型方式是,在setup中,將其當前值存儲到變量中並將超時時間值添加到其中:

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

然后在loop中您可以進行檢查:

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

 // do whatever you want to do

}

使用delay()時也要小心——它很容易用於流量控制,但對於任何有不止一件事的程序來說,它可能會導致混亂和難以解決問題。

哦 - 使用芯片上的內置計時器觸發中斷有更復雜的計時方法,但最好先掌握事情的竅門。

在你的幫助下,我想出了下面的草圖。

草圖幾乎可以完成我想要的一切......

當它在第 1 次、第 2 次(inCount = 1)或第 3 次(inCount = 2)按鈕按下后超時(T/O)時,我希望它恢復到開始,而不必再次按下它並循環 triggerFlash 兩次.

要么在超時內實施另一個“等待和傾聽”,以​​將其移動到第二個(inCount = 1)等,但我認為這可能會導致問題。

我知道閃光燈中使用了延遲,但將更改為millis(),我只是想獲得基本功能和理解。
常量 int switchPin = 2; // 輸入引腳的編號 const int BswitchPin = 4; // 輸入引腳的編號 const int outPin = 3; 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);
  } 
}

任何想法都非常感謝! (用改進的計數進行了編輯)

上面的代碼實際上是錯誤的。 請小心millis(),因為它們會在一段時間后翻轉。 它只是長型。 因此,如果 millis+timeout 接近 max(long) 並且 millis() 將翻轉並從零開始計數,即使實際發生超時,millis()>=nextupdate 也會為假。

正確的方法是:

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

我只是實現了 Arduino 庫。 希望對您的問題有所幫助。 我讓它像 javascript 中的 setTimeout 和 setInterval 一樣工作。 你可以在這里下載, Github

這是我的代碼示例您可以在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