簡體   English   中英

AVR C延時按下按鈕可對兩個功能進行編程

[英]AVR C Programming two functions on button press with delay

我真的是AVR編程新手。 我有一個ATMEGA8,想做這樣的事情:

如果按一下按鈕,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功能結束。

對不起,英語能力很差。 希望您了解我的問題,也許您可​​以幫助我。

實現目標的最簡單方法可能是輪詢LED回路中的按鈕,就像您已經在按鈕回路中一樣。 但是,作為一般解決方案,它的內聚性很差,無法擴展到更復雜的應用程序。

在不求助於中斷或多任務調度程序的情況下,實現並發的通用方法是使用狀態機進行LED控制。

狀態機不是調用led()並要求它在返回之前完成整個閃存序列,而是簡單地確定是否按下了按鈕以及是否應該更改LED狀態然后立即返回。 它會跟蹤時間和狀態,但不會在一個呼叫中執行完整的LED序列。

狀態機

這是在下面實現的,但是請注意,時間安排很簡單,並且使用了您已經使用的延遲功能來實現-因為我無法告訴您還有哪些其他服務可用。 如果要花費大量時間進行處理,則可能會影響閃光時間。 它依賴於每10毫秒調用一次LED狀態機,並且僅對呼叫進行計數。 狀態機最好使用一個獨立的時鍾源(例如,標准庫clock()函數),那么它是否被非定期調用無關緊要-而不是計算調用次數,它會切換狀態在經過的實際時間上。

注意使用static變量來維護狀態。 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,即使釋放按鈕,十個周期也會完成。 如果你想閃爍停止按鈕被釋放時,則start_flashing必須在測試LED_FLASH_OFF和可能LED_FLASH_ON狀態,並導致早日回歸LED IDLE 例如:

狀態機2

該方法可以很容易地適用於在計時器中斷時運行LED狀態機。 代替ledUpdate()將按鈕狀態作為參數,它可以通過共享變量傳遞給中斷處理程序。 狀態機代碼的其余部分將保持不變。 然后,主循環將在按鈕按下時簡單地設置共享變量。

我個人提倡將壓電控件,按鈕輪詢和LED控件分開並封裝,以使主循環如下所示:

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

那將具有更嚴格的凝聚力和更寬松的耦合。 在軟件設計中有兩個有用的目標,可以實現代碼的可維護性和可重用性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM