2012-11-27 85 views
0

從我讀到的,我的問題的解決方案是使用中斷,但如果我正確地理解它們,我不能在由中斷調用的例程中使用延遲。我有一個大按鈕LED開關。我希望它在閒置時有一個心跳,但一旦它被推動,保持綠色並執行代碼。Arduino中斷替代

如果我按下足夠多的按鈕次數(我假設在完成heartbeat的一個循環時在恰當的時間獲得狀態改變),但我堅持如何使它工作第一次點擊。有沒有其他方法可以做我正在嘗試的?

void loop(){ 

heartbeat();         //Make LED beat. 
buttonVal = digitalRead(buttonPin);    //Check the button. 
    if (buttonVal != buttonState) {    //If the button state changed. 
     if (buttonVal == HIGH){     //Check if the button is pressed. 
      analogWrite(greenPin, 255);   //Button stays green once pushed. 
      functionA       //Has some delays in it. 
      functionB       //Has some other delays. 
     } 
    } 
} 

void heartbeat(){ 
    for(i = 0; i < pmw; i++) { 
     analogWrite(greenPin,i); 
     delay(((60000/rate)*.1)/pmw); 
    } 

    for (i = pmw; i > 0; i--){ 
     analogWrite(greenPin,i); 
     delay(((60000/rate)*.2)/pmw); 
    } 

    for(i = 0; i < pmw; i++) { 
     analogWrite(greenPin,i); 
     delay(((60000/rate)*.1)/pmw); 
    } 

    for (i = pmw; i > 0; i--){ 
     analogWrite(greenPin,i); 
     delay(((60000/rate)*.6)/pmw); 
    } 
} 

回答

5

你在大部分假設中都是正確的。處理這種情況的正確方法是使用中斷,並且延遲中斷服務例程(ISR)並不是一個好主意。所以你想要做的是在你的ISR中設置一個標誌並在主循環中檢查該標誌。

// Flag needs to be volatile if used in an ISR 
volatile int buttonFlag = 0; 

void loop() 
{ 
    if (buttonFlag == 0) 
    { 
     heartbeat();      //make led beat 
    } 
    else 
    { 
     analogWrite(greenPin, 255);   //button stays green once pushed 
     functionA       //has some delays in it 
     functionB       //has some other delays 
     buttonFlag = 0;      //clear flag after executing code 
    } 

} 

// Interrupt Service Routine attached to INT0 vector 
ISR(EXT_INT0_vect) 
{ 
    buttonFlag = digitalRead(buttonPin); //set flag to value of button 
} 

由於中斷只會觸發按鈕狀態的變化,所以您不需要檢查該狀態。

確保您的標記變量是全局標記,並且在ISR中聲明volatile。並確保您正在使用正確的中斷向量與您正在使用的引腳一起使用。

這是關於Arduino中斷的good tutorial。這是你正在嘗試做的另一個good example

您可能還想查看debouncing your switch,這取決於您使用的交換機類型。如果不是錯過了第一次印刷,就會得到太多的印刷機,您需要實施某種類型的去摺疊。

+0

你先生是英雄和學者!這是我需要的指導。我設法用arduino attachInterrupt(與原始的avr-libc)做到這一點,但那就是我希望它做的一切!走這條路,我不需要改變任何有關其他功能延遲的事情,實際的ISR也沒有任何延誤。我沒有注意到開關有任何反彈,但我沒有得到儘可能實施的東西,這可能是一個很好的措施。或者,也許我會用硬件解決方案來獲得它。 (RC /反轉schmidtt觸發器)主要感謝embedded.kyle –

+0

@JoshWisotzkey非常歡迎。請記住,你的芯片和你一樣喜歡被打斷。所以請保持短暫的中斷! –

2

我是一名專業程序員,但我是Arduino世界的新手。我注意到許多Arduino所有者不知道編程的基本原理,並且無法在使用這個驚人的技術方面取得好的結果。

特別是,如果沒有必要,我想建議不要使用Arduino中斷,因爲只有兩個中斷,即使您可以爲單個傳感器或執行器寫一個「美麗」代碼必須實施一個更復雜的項目,你不能使用它們。當然你在使用中斷處理單個按鈕時是正確的,但是如果你有四個按鈕來管理呢?

因此,我使用「時間片」或「單步」技術重寫了「心跳」草圖。使用這種技術,每次執行循環功能時,您只需運行控制功能的「單步」,因此您可以根據需要插入儘可能多的數據,並且可以快速響應您使用的所有傳感器。 爲此,我爲每個必須實現的控制函數使用全局計數器,並且每次執行循環函數時,都執行每個函數的單個步驟。 這是新的草圖:

// Interrupt.ino - this sketch demonstrates how to implement a "virtual" interrupt using 
// the technique of "single step" to avoid heavy duty cycles within the loop function. 

int maxPwm = 128; // max pwm amount 
int myPwm = 0;  // current pwm value 
int phase = 1;  // current beat phase 
int greenPin = 11; // output led pin 
int buttonPin = 9; // input button pin 
int buttonFlag = 1; // button flag for debounce 

int myDir[] = {0,1,-1,1,-1}; // direction of heartbeat loop 
int myDelay[] = {0,500,1000,500,3000}; // delay in microseconds of a single step 

void setup() 
{ 
    pinMode(buttonPin, INPUT); // enable button pin for input 
    // it's not necessary to enable the analog output 
} 

void loop() 
{ 
    if(phase>0) heartbeat(); // if phase 1 to 4 beat, else steady 
    buttonRead(); // test if button has been pressed 
} 

// heartbeat function - each time is executed, it advances only one step 
// phase 1: the led is given more and more voltage till myPwm equals to maxPwm 
// phase 2: the led is given less and less voltage till myPwm equals to zero 
// phase 3: the led is given more and more voltage till myPwm equals to maxPwm 
// phase 4: the led is given less and less voltage till myPwm equals to zero 
void heartbeat() 
{ 
    myPwm += myDir[phase]; 
    analogWrite(greenPin, myPwm); 
    delayMicroseconds(myDelay[phase]); 
    if(myPwm==maxPwm||myPwm==0) phase = (phase%4)+1; 
} 

// buttonRead function - tests if the button is pressed; 
// if so, forces phase 0 (no beat) and enlightens the led to the maximum pwm 
// and remains in "inoperative" state till the button is released 
void buttonRead() 
{ 
    if(digitalRead(buttonPin)!=buttonFlag) // if button status changes (pressed os released) 
    { 
     buttonFlag = 1 - buttonFlag; // toggle button flag value 
     if(buttonFlag) // if pressed, toggle between "beat" status and "steady" status 
     { 
     if(phase) myPwm = maxPwm; else myPwm = 0; 
     phase = phase==0; 
     analogWrite(greenPin, myPwm); 
     } 
    } 
} 

正如你看到的,代碼是非常緊湊和快速的執行。我將心跳循環分爲四個「階段」,由myDelay陣列調節,其計數方向由myDir陣列調節。如果沒有任何反應,pwm引腳的電壓在每一步都會遞增,直到達到maxPwm值,然後環路進入階段2,電壓遞減到零,依此類推,實現原始心跳。

如果按下該按鈕,則迴路進入零相(無心跳),並且LED與maxPwm電壓一致。從現在開始,循環保持穩定的指示燈,直到釋放按鈕(這實現「去抖」算法)。如果再次按下該按鈕,buttonRead函數將重新啓動心跳功能,使其再次進入階段1,以便恢復心跳。

如果再次按下按鈕,則心跳停止,等等。所有都沒有任何exhitation或反彈。

+0

嗨,幾點注意:如果你想要你的答案添加段落,你必須按兩次Enter,而不是一次。此外,不要添加有關您的背景和「謝謝」等內容的東西 - Stack Overflow應該像維基百科,而不是論壇。只是回答這個問題。我已經從你的答案中編輯了那些東西。否則,這是一個很好的答案,我已經提出了這個答案。歡迎來到堆棧溢出! – durron597