1

私は長い間プログラミングをしていないので、ArduinoUNOボードを使って電子工学から拡張したいと思っています。

GrathioのSteveHoeferによるSecretKnockDetecting Door Lockに基づいた新しいプロジェクトを開始しました。次のことを実装したいと思います:

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

実装

グローバル値が0に等しく、有効なノックパターンがtrueの場合、遅延ではなくミリ秒を使用して黄色のLEDを4回点滅させ、「リッスン」できるようにします。

別の有効なノックパターンが6秒以内に聞こえない場合、タイムアウトしてグローバルを0にリセットし、最初の真のパターンを確認して黄色のLEDを点滅させることができます。

6秒以内に別の有効なノックパターンが聞こえた場合は、カウンターをインクリメントします。

カウンターが1に等しい場合は、別の有効なノックパターンを待ち、6秒以内に真の場合は、カウンターを再度インクリメントし、黄色のLEDを点滅させないでください。

それ以外の場合は、タイムアウトしてすべての値をリセットします。

カウンターが4以上になるまで、マスターLEDアレイをトリガーします。

ノックが4回成功したら、作成したマスターLEDアレイをトリガーします。

問題

このプロジェクトは、旅客機で使用されているテストパネルに触発されました。私はそれらをたくさん見て、タイミングについて学び始めるのに良い場所だと思いました。

毎回millis()をリセットしたくないので、いくつかの問題があります。ノック検出スクリプト内でブール値ではなくボタンを使用しているため、コードに迷うことはありません。

これは50秒後に応答しないことを理解しています。これは初心者の間違いですが、ボタンを押したままにすると、私が得たものを証明します。以下のコードも、最初のdigitalRead HIGHまたは真のブール値の後にタイムアウトがありません(私はこれに苦労しています)。

Arduinoスケッチ

  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  

これが現在のスケッチです。私が使用したカウンターはほとんど無意味であると理解しています。

どんな助けでも大歓迎です!

4

3 に答える 3

1

それはたくさんのことなので、あなたの質問を理解できないかもしれませんが、以下のコードのビットが問題として際立っています:

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

      .....
      }

可能な「リセット」millis()はなく、それは単にプログラムが起動してからのミリ秒数を返す関数であることを理解していますか? プログラムが実行されている限り(ロールオーバーするまでは増加しますが、それは別の問題です)、増加し続けます。したがって、上記のコードでは、'currentTime' は非常に短い間 (6 秒) だけ < 6000 になり、その後は (ミリ秒がリセットされるロールオーバー条件を除いて) 二度と戻りません。

したがって、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()使用には注意してください。フロー制御には簡単に使用できますが、複数の処理が行われるプログラムでは、混乱を招き、問題の解決が困難になる可能性があります。

ああ、チップ上の組み込みタイマーを使用して割り込みをトリガーするより洗練されたタイミングを行う方法がありますが、最初にコツをつかむことをお勧めします。

于 2013-02-28T17:40:33.053 に答える
0

上記のコードは実際には間違っています。millis() はしばらくするとロールオーバーするので注意してください。ロングタイプのみです。したがって、ミリ秒 + タイムアウトが max(long) に近く、ミリス() がロールオーバーしてゼロからカウントを開始する場合、ミリス()>=nextupdate は、タイムアウトが実際に発生した場合でも false になります。

これを行う正しい方法は次のとおりです。

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
于 2016-11-21T12:14:22.070 に答える
0

あなたの助けを借りて遊んだ後、次のスケッチを思いつきました。

スケッチは私が望んでいたほとんどすべてを行います...

1 回目、2 回目 (inCount = 1)、3 回目 (inCount = 2) のボタンを押した後にタイムアウト (T/O) になった場合は、もう一度押して、triggerFlash を 2 回ループせずに最初に戻りたいと思います。 .

それか、タイムアウト内に別の「待機とリッスン」を実装して2番目(inCount = 1)に移動するなどですが、問題が発生する可能性があると思います。

フラッシュ内で使用される遅延があることは知っていますが、それは millis() に変更されます。基本的な機能と理解を得ようとしているだけです。
const 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);
  } 
}

どんなアイデアでも大歓迎です!(カウントを改善して編集)

于 2013-03-01T18:08:36.317 に答える