2014-10-12 68 views
0

我真的很新AVR編程。 我有一個ATMEGA8,想要做這樣的事情:AVR C編程延時按鈕上的兩個功能

如果你按一個按鈕,一個LED應該打開和關閉10次。作品。 但是隻要按下按鈕,壓電就會發出聲音。 問題是我不能同時做這兩個功能。

閃爍LED功能

int i; 
void led(void) 
{ 
    for (i = 0; i < 10; i++) 
    { 
     PORTB |= (1 << PB0); //LED on 
     _delay_ms(250);  //wait 250ms 

     PORTB &= ~(1 << PB0); //LED off 
     _delay_ms(250);  //wait 250ms 
    } 
} 

主要代碼:

while (1) 
{ 
    if (!(PINB & (1<<PB7))) 
    { 
     PORTB |= (1 << PB1); // Piezo on 
     led(); 
    } 
    else 
    { 
     PORTB &= ~(1 << PB1); // Piezo off 
    } 
} 

壓電停留,直到閃爍LED功能是過,即使我只是按下按鈕的時間很短。

不好的英語技能。我希望你能理解我的問題,也許你能幫助我。

+0

簡單但破壞組織,您可以在led功能內添加按鈕狀態的檢查,並在那裏只用四分之一秒延遲關閉壓電,或者如果您將延遲分成較小的時間段並在兩者之間檢查,則更少。或者爲了更有組織的解決方案,使用有狀態事件驅動的設計並將領先的時間移至中斷。或者保持原樣並將壓電元件移動到引腳電平變化中斷。 – 2014-10-12 14:02:36

回答

3

實現您的目標最簡單的方法可能是輪詢LED環路中的按鈕,因爲您已經在按鈕循環中。然而,作爲一個通用的解決方案,它的內聚性差,不能擴展到更復雜的應用程序。

a 通用實現併發性的方法,不借助中斷或多任務調度程序就是使用狀態機進行LED控制。

與其調用led()並要求它在返回之前完成整個閃存序列,狀態機將簡單地確定按鈕是否被按下以及是否是時間更改LED狀態,然後立即返回。它會記錄時間和狀態,但不會在一次通話中執行完整的LED指示燈序列。

statemachine

這將在下面執行,但是請注意,時機是原油和使用你已經使用了延時功能實現的 - 因爲我不能告訴其他的服務提供給您。如果任何處理需要很長時間,這可能會影響閃光時間。它依靠每10ms調用一次LED狀態機,並且它只是對通話進行計數。如果狀態機使用獨立的時鐘源(例如標準函數庫clock())會更好,那麼它是否被稱爲非週期性並不重要 - 而不是計算調用次數,它會切換狀態實際時間已過。

注意使用static變量來維護狀態。 A static在調用該函數之間保持其值。

#define TICK 10   // milliseconds 
#define FLASH_ON_TICKS 25 // 250ms 
#define FLASH_OFF_TICKS 25 // 250ms 
#define FLASH_COUNT 10 

static void ledUpdate(int start_flashing) ; 

int main(void) 
{ 
    for(;;) 
    { 
    // Perform loop on each tick (10ms) 
    // Assumes loop processing time is not significant! 
    _delay_ms(TICK) ; 

    if (!(PINB & (1<<PB7))) 
    { 
     PORTB |= (1 << PB1); // Piezo on 
     ledUpdate(1) ; 
    } 
    else 
    { 
     PORTB &= ~(1 << PB1); // Piezo off 
     ledUpdate(0) ; 
    } 
    } 

    return 0 ; 
} 

void ledUpdate(int start_flashing) 
{ 
    static enum 
    { 
    LED_IDLE, 
    LED_FLASH_ON, 
    LED_FLASH_OFF 

    } led_state = LED_IDLE ; 

    static int led_tick = 0 ; 
    static int flash_count = 0 ; 

    switch(led_state) 
    { 
    case LED_IDLE : 
    { 
     if(start_flashing) 
     { 
     led_state = LED_FLASH_ON ; 
     PORTB |= (1 << PB0); //LED on 
     } 
    } 
    break ; 

    case LED_FLASH_ON : 
    { 
     led_tick++ ; 
     flash_count++ ; 
     if(led_tick >= FLASH_ON_TICKS) 
     { 
     led_state = LED_FLASH_OFF ; 
     led_tick = 0 ; 
     PORTB &= ~(1 << PB0); //LED off 
     } 
    } 
    break ; 

    case LED_FLASH_OFF : 
    { 
     if(flash_count >= FLASH_COUNT) 
     { 
     led_state = LED_IDLE ; 
     } 
     else 
     { 
     led_tick++ ; 
     if(led_tick >= FLASH_ON_TICKS) 
     { 
      led_state = LED_FLASH_ON ; 
      led_tick = 0 ; 
      PORTB |= (1 << PB0); //LED on 
     } 
    } 
    break ; 
    } 
} 

注意,按鈕的狀態隻影響LED如果尚未閃爍,完成十個週期,即使鬆開按鈕。如果您希望釋放按鈕時閃爍停止,則必須在LED_FLASH_OFF和可能的LED_FLASH_ON狀態中測試start_flashing,並且會導致提早返回到LED IDLE。例如:

statemachine2

的方法,可以很容易地適合於在一個定時器中斷運行LED狀態機。可以將按鈕狀態作爲參數而不是ledUpdate(),這可以通過共享變量傳遞給中斷處理程序。狀態機代碼的其餘部分將保持不變。然後主循環會在按鈕關閉時簡單地設置共享變量。

個人身份證主張分離和封裝所述壓電控制,按鈕輪詢和LED控制,使得主迴路看起來像:

int main() 
{ 
    for(;;) 
    { 
     int button_state = getButtonState() ; 
     upodatePiezo(button_state) ; 
     updateLed(button_state) ; 
    } 
} 

這將對桁條的凝聚力和更鬆散的耦合。軟件設計中兩個有用的目標是實現代碼的可維護性和可重用性。

+0

非常感謝。 – 2014-10-12 18:15:48